Add CORS Support to Your Express + TypeScript API

April 07, 2021
Written by
Mia Adjei
Twilion
Reviewed by

Imagine you've just built a great API using Node.js, Express, and TypeScript. You've also built a client-side web app and are ready to fire it up in your browser, get it talking to your server, and hopefully share it with the world.

You open up a browser window and navigate to where your app is running, then you pop open the console in your developer tools. Your app makes its first API call to your server...but then, instead of the data you're expecting to see populate your app, you see an error like the one below in your console:

Access to fetch at 'http://localhost:5000/rooms' from origin 'http://localhost:3000' 
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present 
on the requested resource. If an opaque response serves your needs, set the 
request's mode to 'no-cors' to fetch the resource with CORS disabled.

Yikes! This error is due to Cross-Origin Resource Sharing (CORS) restrictions. While this may be frustrating, it's a situation many a developer has found themselves in.

But what is CORS? And how can you resolve this error message and get the data from your server into your app? This tutorial will show you how to add CORS support to your Express + TypeScript API so you can keep moving forward with your exciting projects.

What is Cross-Origin Resource Sharing (CORS)?

Cross-Origin Resource Sharing (CORS) is a security protocol in modern browsers that allows or restricts resources from being shared between different origins, depending on which origin initiated the HTTP request.

An origin describes where a request is initiated. Origins have two required parts (scheme and hostname) and one optional part (port), as shown below:

https://www.twilio.com
  ^       ^
  |       |
scheme hostname


http://localhost:5000
  ^       ^       ^
  |       |       |
scheme hostname  port

The browser adds an Origin header to all of the requests it makes. When a request arrives at the server, if the origin in the request is included in the list of origins that are allowed to retrieve resources from that server, the server will add an Access-Control-Allow-Origin header to its response to let the browser know that the content is accessible to this specific origin.

For example, the following shows that all origins are allowed to request resources:

Access-Control-Allow-Origin : *

However, the header below tells the browser that only requests from https://www.twilio.com are allowed resources:

Access-Control-Allow-Origin : https://www.twilio.com

You are likely to be using different ports during your local development work. If you take a look at the example error message from the introduction of this post, you can see that in this example, the app is being served at localhost:3000 but is trying to fetch data from localhost:5000. Because the two ports are different, this means they are from different origins, so by default, the browser will deny this request:

Access to fetch at 'http://localhost:5000/rooms' from origin 'http://localhost:3000' 
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present 
on the requested resource. If an opaque response serves your needs, set the 
request's mode to 'no-cors' to fetch the resource with CORS disabled.

To fix this and to allow data to flow between your server and client, you can add CORS support to your server. For this tutorial, you'll use the cors npm package to add middleware that will set the Access-Control-Allow-Origin header and specify the domains that are allowed to access your server's resources.

If you want to read about what else CORS can be used for, check out the Mozilla documentation about this subject here.

Configure CORS in your Express server

To get started, you will need:

The CORS information in this tutorial can be used for any Express project. However, for the purposes of this example, you may want to follow along with the code in the Express project listed above. This video API is built with Express and TypeScript, so it makes for a great sample project to work with.

If you're following along with the example project, follow the instructions in the repository's README.md to get up and running.

Once you've run the command npm run start, you should see a log statement in your terminal that lets you know that your server is running on port 5000:

Express server listening on port 5000

If instead, you're using your own Express API, that's great too! Your cURL requests will likely be different, so substitute in the parameters that make sense for your project.

Run a simulation with a cURL command

If you're using the example code from the repository above, open a second terminal window and try running the following cURL command:

curl -H "Origin: http://localhost:3000" --head http://localhost:5000/rooms

With this cURL command, you are simulating how the browser issues a request. In this case, your server is running on http://localhost:5000 and your app is running on and making a request from the origin localhost:3000. In this example, your “app” is trying to request a list of video chat rooms.

The response that appears in your terminal window will be similar to the one below:

HTTP/1.1 200 OK
X-Powered-By: Express
Vary: Origin
Content-Type: application/json; charset=utf-8
Content-Length: 52
ETag: <ETag>
Date: Tue, 30 Mar 2021 16:45:54 GMT
Connection: keep-alive
Keep-Alive: timeout=5

If you examine this output, you'll notice that there is no Access-Control-Allow-Origin header in this response. If this were actually a response received by a browser, the browser would block the request.

It's time to update your server so that your server responds with the Access-Control-Allow-Origin header for specific cross-origin requests.

Add the cors npm package to your Express project

In your terminal window, navigate to the root of your project. If you're following along with the sample code, the root of the project is the express-video-api directory.

Install the cors package and its TypeScript types by running the following commands:

npm install cors
npm install --save-dev @types/cors

If you take a look at the package.json file, you will find that cors was added as a dependency and @types/cors was added to devDependencies.

Import and configure CORS options in JavaScript

Next, open the file that is the entry point to your app. If you're following with the sample code, this file is src/index.ts.

In your code editor, and below the line where you've imported express, import cors as well:

import cors from 'cors';

Add the following line above app.use(express.json()); to allow your Express server to use the cors middleware:

app.use(cors); /* NEW */

app.use(express.json());

Then add a list of the origins you want to allow to access resources on your server, and pass this list into your Express CORS options. For this tutorial, you'll add localhost:3000 as the origin you want to allow:

// Add a list of allowed origins.
// If you have more origins you would like to add, you can add them to the array below.
const allowedOrigins = ['http://localhost:3000'];

const options: cors.CorsOptions = {
  origin: allowedOrigins
};

Next, pass these options in as an argument for your cors middleware:

app.use(cors(options));

Your Express server will notice the changes and update.

At this point, if you are following along with the example project, your code should look like the code below:

import express from 'express';
import cors from 'cors';
import config from './config';
import roomsRouter from './routes/room';
import { Twilio } from 'twilio';

// Initialize Twilio client
const getTwilioClient = () => {
  if (!config.TWILIO_ACCOUNT_SID || !config.TWILIO_API_KEY || !config.TWILIO_API_SECRET) {
    throw new Error(`Unable to initialize Twilio client`);
  }
  return new Twilio(config.TWILIO_API_KEY, config.TWILIO_API_SECRET, { accountSid: config.TWILIO_ACCOUNT_SID })
}

export const twilioClient = getTwilioClient();

const app = express();

// Add a list of allowed origins.
// If you have more origins you would like to add, you can add them to the array below.
const allowedOrigins = ['http://localhost:3000'];

const options: cors.CorsOptions = {
  origin: allowedOrigins
};

// Then pass these options to cors:
app.use(cors(options));

app.use(express.json());

// Forward requests for the /rooms URI to our rooms router
app.use('/rooms', roomsRouter);

app.listen(5000, () => {
  console.log('Express server listening on port 5000');
});

Test that CORS is working

Now that you have configured CORS options on your server, try running the following cURL command simulation in your terminal again:

curl -H "Origin: http://localhost:3000" --head http://localhost:5000/rooms

If you check the response, you'll notice that there is now an Access-Control-Allow-Origin header with the origin http:://localhost:3000! This means that when you run your client-side app on localhost:3000, the app will be able to retrieve resources from your server.

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: http://localhost:3000
Vary: Origin
Content-Type: application/json; charset=utf-8
Content-Length: 52
ETag: <ETag>
Date: Tue, 30 Mar 2021 16:46:39 GMT
Connection: keep-alive
Keep-Alive: timeout=5

As another test, try running the following cURL command as well:

curl -H "Origin: http://localhost:4000" --head http://localhost:5000/rooms

Notice that in this command, you've changed the origin in your request to http://localhost:4000, which was not in your list of allowed origins. The response that comes back does not have the Access-Control-Allow-Origin header:

HTTP/1.1 200 OK
X-Powered-By: Express
Vary: Origin
Content-Type: application/json; charset=utf-8
Content-Length: 52
ETag: <ETag>
Date: Tue, 30 Mar 2021 16:40:47 GMT
Connection: keep-alive
Keep-Alive: timeout=5

This means that if someone tries to access your server from an app running on localhost:4000, they will not be able to access resources. Instead, a similar CORS error as before will appear in their console.

What's next for your Express API project?

If you want to take a look at the updated sample code from this tutorial in its entirety, you can find that code on the added-cors branch of this repository on GitHub. Or, if you just want a cheat sheet of how to implement CORS in your own app, check out the gist here.

You can also explore more through Twilio with these other CORS post(s):

Now that you know how to add CORS support to your Express + TypeScript server, you're all set to connect your server to a client-side application. What kind of app do you have in mind? I can't wait to see what you build.

Mia Adjei is a Software Developer on the Developer Voices team. They love to help developers build out new project ideas and discover aha moments. Mia can be reached at madjei [at] twilio.com.