StackHawk
Hamburger Icon

React CORS Guide:
What It Is and
How to Enable It

stackhawk

StackHawk|July 12, 2021

This is a brief guide on what CORS is and how it works. See it in action and learn how to enable CORS in a React application.

Developers have struggled with CORS for longer than they should. This is because it's a tricky concept to grasp, especially for new developers who are working with third-party APIs from their single-page applications on React, Angular, Vue, etc.

In this post, I'll help you understand CORS from the ground up. I'll set up a sample React app and an Express server to demonstrate how and why CORS errors occur. I'll also show you how you can deal with it in general and in a React application.

CORS Explained

CORS stands for cross-origin resource sharing. Just like HTTPS, it's a protocol that defines some rules for sharing resources from a different origin. We know that modern web apps consist of two key components: a client and a server. The client requests some data from the server, and the server sends back data as a response.

React CORS Guide: What It Is and How to Enable It image

Client-server request response.

This architecture is popular these days because it allows your back end to be used independently across multiple clients like a web app, a desktop GUI, or a native application.

Watch a demo to see StackHawk in flight

The Same-Origin Policy

Since the client and server are separate applications, they're usually hosted on different domains. Therefore, your own client that's requesting data from your own server might have different origins. In another scenario, you might use some third-party services for authentication, analytics, etc. The bottom line is that at some point you are going to interact with an application with a different origin than yours. This means you're going to request resources from the application by making an HTTP request.

React CORS Guide: What It Is and How to Enable It image

Browser's same-origin policy.

When you request a resource from an application of a different origin, the web browser uses an SOP (same-origin policy) protocol to block all your requests to that origin. Back in the day, this is what made the Internet secure! For instance, a malicious cracker or hacker from xyz.com wouldn't be able to access your information on abcbank.com. However, this underlying security rule governing browsers does not allow you to request a resource from a different origin. That's a common use case widely used across web apps today. So what's the solution?

Enter CORS

CORS enables you to access a resource from a different origin. It is used to override your browser's default behavior due to SOP. So now when your client requests a resource, the response will additionally contain a stamp that tells your browser to allow resource sharing across different origins.

React CORS Guide: What It Is and How to Enable It image

Client-server request response with CORS enabled.

Once your browser identifies this stamp, responses for requests from different origins are allowed to pass through. That's precisely what CORS is, and I hope you understand enough to see it in action. If you wish to learn more about it, here's a detailed guide that may help you out. 

Create Express Server With API Endpoints

In order to enable CORS, you need to create 

  • A client that can request resources from a server

  • A server with some endpoints that can send a response back to the client

Needless to say, both client and server should be running on different domains or have different origins. We can use React to create a simple client that requests resources from a server. However, we first need a server that can serve as an endpoint the client can request a resource from. 

Let's create a simple server using Express with some API endpoints. Inside the directory of your choice, run the following command:

mkdir cors-server && cd cors-server 

You should now have an empty folder named cors-server. Let's initialize a new npm project inside it by running 

npm init -y 

You should now have a package.json file inside the project. Great! Let's install Express, a lightweight NodeJS framework for creating web applications. 

npm i express 

Next, create an app.js file inside the root directory and add the following code to it:

const express = require('express');
const app = express();
app.get('/', (req, res) => {
    res.send('Welcome to CORS server 😁')
})
app.get('/cors', (req, res) => {
    res.send('This has CORS enabled 🎈')
})
app.listen(8080, () => {
    console.log('listening on port 8080')
})

In the above code, I have created a minimal server using Express that listens on port 8080. I have two routes, the / and /cors that sends a response.

Let's run our server using the following command:

node app

If you point your browser to http://localhost:8080/, you should see something like this:

React CORS Guide: What It Is and How to Enable It image

Express Server Endpoint.

And if you visit http://localhost:8080/cors, you should see something like this:

React CORS Guide: What It Is and How to Enable It image

Express Server Endpoint /cors.

Set Up React App

Now that we have a server up and running, let's set up a simple React app where we can make requests to our server. Create an empty React App by running 

npx create-react-app react-cors-guide 

Head over to your App.js and replace it with the following:

import { useEffect, useState } from 'react';
import './App.css';
function App() {
  const makeAPICall = async () => {
    try {
      const response = await fetch('http://localhost:8080/', {mode:'cors'});
      const data = await response.json();
      console.log({ data })
    }
    catch (e) {
      console.log(e)
    }
  }
  useEffect(() => {
    makeAPICall();
  }, [])
  return (
    <div className="App">
      <h1>React Cors Guide</h1>
    </div>
  );
}
export default App;

In the above code, I have a function makeAPICall that is invoked when our <App> component mounts on the DOM. Inside the makeAPCall function, I make a GET request to the endpoint http://localhost:8080/ using the Fetch API. 

If you open the browser and check your console, instead of the response from the endpoint you'll see an error that looks like this:

React CORS Guide: What It Is and How to Enable It image

CORS error.

The above is the typical CORS error that occurs because your browser is blocking requests to your server. Even though both your client and the server are running from localhost, your server is hosted on the port 8080 and your React client on port 3000. Therefore, both have a different origin, and the browser's SOP policy comes into play. Let's dive deeper into this CORS error and see a server-side solution to fix this problem.

CORS Should Always Be Handled From Server Side!

Let's have a closer look at the above CORS error.

Access to fetch at 'http://localhost:8080/' 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.

It states that there's a missing Access-Control-Allow-Origin header on the resource you requested. If you think about it, your client doesn't have anything to do with CORS. It's only something that your browser imposes, and it suggests that your requested resource should be configured differently. 

Therefore, it makes sense to configure the response from the server in such a way that the browser identifies this as a CORS request. Hence, logically, CORS should always be handled from the server side. Later we'll explore a way to work around this on the client side, but the most reliable solution is to always make the response from the server CORS-friendly.

Enable CORS on Server Side

Let's head back to our server's app.js file. 

app.get('/cors', (req, res) => {
res.set('Access-Control-Allow-Origin', '*');
res.send({ "msg": "This has CORS enabled 🎈" })
})

Inside the request middleware callback, I first set the Access-Control-Allow-Origin header to an asterisk. The asterisk indicates that this resource can be requested by any client. Let's also change the endpoint in our React app. 

const response = await fetch('http://localhost:8080/cors', { mode: 'cors' });

Now inspect the console.

React CORS Guide: What It Is and How to Enable It image

CORS enabled.

Notice that the CORS error goes away and that you get back the response along with some JSON data. Everything works as intended. Great! All you needed to do was to attach that CORS stamp on your response. Note that you may need to restart your back-end server to see the above changes in action. 

You can also set the Access-Control-Allow-Origin to specific domains instead of the asterisk. For instance, setting it to http://localhost:3000 will only enable CORS for clients that are running on the specified URL, localhost:3000.

app.get('/cors', (req, res) => {
res.set('Access-Control-Allow-Origin', 'http://localhost:3000');
res.send({ "msg": "This has CORS enabled 🎈" })
})

While the server-side fix to CORS is the most technically coherent solution to this problem, there's a small catch. It requires you to make modifications on the server side. In some cases, you might not have access to server-side code.

For example, if you're using a third-party service for authentication, notification, sending emails, etc., you might run into this problem. In such cases, there isn't much you can do but shoot an email to the developers asking them to enable CORS for your app. There's a neat trick specific to React apps that you can use to work around this problem. Let's see how it works.

Proxy Requests in a React App

Have you ever tried to proxy your classmate during a lecture by shouting out to their roll call? That's how proxying works in API requests as well! You can tell your React app to proxy your requests to a server using the proxy property inside the package.json file. 

This is a simple one-step process. Go inside your app's package.json file and add the following property:

{
...
"proxy":"http://localhost:8080"
...
}

Now if you restart your React development server, you'll notice that all requests are being served to http://localhost:8080 instead of http://localhost:3000. You've proxied your React development server to your back-end server. The above works exactly the same way for third-party services as well. 

Under the hood, when your React app requests resources from http://localhost:8080, it pretends to be requesting this resource from the origin http://localhost:8080 instead of http://localhost:3000. This seems in line with browser's SOP, and you no longer get the CORS error.
Let's say you're using a service on https://randomservice.com and you come across the CORS error. You can add the URL inside the proxy property in your package.json file.

{
...
"proxy":"https://randomservice.com"
...
}

The development server will only attempt to send requests without text/html in its Accept header to the proxy.

Thus for the above method to work, you need to ensure that the server doesn't have text/html in its Accept header. In rare cases, you might need to specify more than one proxy URL. You can set up a proxy manually using a package http-proxy-middleware by following the steps given here.

StackHawk Can Test for this and many other API and Application Security Issues

Wrap-Up for CORS in a React App

Next time you run into the CORS error, remember to handle it first on the server side. If you're running out of time, you can set up a proxy for your React app for development. You can even create your own proxy server and serve requests through it. This may require some extra effort at first, but it definitely can be worth the investment. Here's a useful guide that can help you out in that context. 

You can even use chrome plugins like CORS Unblock to achieve this. Always remember to give a mode property with the value cors inside your fetch requests. Lastly, be aware that most of the tricks and hacks on the client side will not work in production. Make sure you have a foolproof server side fix to the problem before you deploy your application. 

This post was written by Siddhant Varma. Siddhant is a full stack JavaScript developer with expertise in frontend engineering. He’s worked with scaling multiple startups in India and has experience building products in the Ed-Tech and healthcare industries. Siddhant has a passion for teaching and a knack for writing. He's also taught programming to many graduates, helping them become better future developers.


StackHawk  |  July 12, 2021

Read More

Add AppSec to Your CircleCI Pipeline With the StackHawk Orb

Add AppSec to Your CircleCI Pipeline With the StackHawk Orb

Application Security is Broken. Here is How We Intend to Fix It.

Application Security is Broken. Here is How We Intend to Fix It.

Using StackHawk in GitLab Know Before You Go (Live)

Using StackHawk in GitLab Know Before You Go (Live)