StackHawk

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

StackHawk   |   Jul 15, 2025

LinkedIn
X (Twitter)
Facebook
Reddit
Subscribe To StackHawk Posts

If you’re a frontend or full-stack developer, you have probably struggled with CORS for longer than you should. This is because it’s a complex concept to grasp, especially for new developers building React apps on their local machines or those working with third-party APIs in their React applications.

If you’re dealing with a React application that’s encountering CORS errors when calling APIs, this guide will help you understand the issue and provide guidance on how to resolve it properly. Before we get into the exact fixes and workarounds, let’s first understand what CORS is and what causes CORS errors.

What Is CORS?

CORS stands for cross-origin resource sharing. It’s a protocol that defines rules for sharing resources from a different origin. For example, if you are developing an app locally and have your React app being served on localhost:8080 and your API on localhost:4000, these are two different origins, and CORS policies will apply.

As I just mentioned, modern web applications consist of two key components: a client, such as a React web app, and a server, like an API server. The client requests data from the server, and the server responds with the requested data. This architecture is popular because it enables your backend to be used across multiple clients, such as web apps, desktop applications, or native mobile apps.

The Same-Origin Policy

Since the client and server are separate applications, they’re usually hosted on different domains. When you request a resource from an application of a different origin, the web browser uses a same-origin policy (SOP) to block requests to that origin.

An origin consists of three parts:

  • Protocol (http/https)
  • Domain (localhost, example.com)
  • Port (3000, 8080, 80, 443)

If any of these differ between your React app and your API, you’re making a cross-origin request. However, not all cross-origin requests require CORS. Simple requests, such as GET, HEAD, or POST with standard headers and content types like application/x-www-form-urlencoded, multipart/form-data, or text/plain, can be sent directly to the server without any CORS policy blocking the request. Only requests with custom headers, non-standard HTTP methods (like PUT or DELETE), or content types other than these three will trigger a preflight OPTIONS request. For example, a POST request with the application/json content type will trigger a preflight.

How CORS Works

CORS enables your browser to access resources from a different origin by explicitly allowing them through server-sent headers. Normally, the browser blocks such cross-origin requests due to the same-origin policy.

For complex requests, the browser sends a preflight OPTIONS request to the server to check if the actual request is safe to send. The server responds with CORS headers that specify which origins are allowed, which methods are permitted, and which headers can be used.

If the server’s response passes the browser’s checks, the actual request is sent. Depending on how CORS is configured, the browser then allows or blocks the cross-origin response.

Understanding CORS Errors in React

If you’re reading this, you’ve likely encountered a CORS error in your existing React application. Especially when building a new app or integrating with third-party APIs for the first time, this error is very common. Let’s look at what this error looks like and understand what’s happening.

Common CORS Error Messages

When your React app tries to call an API on a different origin, you’ll see errors like these in the browser console:

Access to fetch at 'https://api.example.com/data' from origin 'http://localhost:3000' 
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is 
present on the requested resource.

Or

Access to XMLHttpRequest at 'http://localhost:8080/api' from origin 'http://localhost:3000' 
has been blocked by CORS policy: Request header field authorization is not allowed 
by Access-Control-Allow-Headers in preflight response.

Once you see these Access-Control-Allow errors pop up in your browser console, you can be almost certain that CORS issues are the root cause. Next, you need to determine where and how to fix them, which can be the tricky part.

Where CORS Errors Typically Occur

In your React app, you’re probably making API calls like this:

const fetchData = async () => {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  return data;
};

Or, maybe you’re doing something with a similar library like Axios:

import axios from 'axios';

const getData = async () => {
  const response = await axios.get('http://localhost:8080/api/users');
  return response.data;
};

Regardless of how you are doing it, CORS occurs because your application, which is running in the browser, is requesting a resource from an origin that differs from where the web app is running. This error can occur at several points in the development journey and under various scenarios.

Common Scenarios That Trigger CORS Errors

Most often, a CORS issue is triggered by:

  1. Development setup: Your React app runs on http://localhost:3000 but calls an API on http://localhost:8080
  2. Third-party APIs: Calling external services that don’t allow your domain
  3. Production deployment: Frontend deployed to https://myapp.com, calling API at https://api.myapp.com
  4. Mixed protocols: HTTP frontend trying to call HTTPS API (or vice versa)

Some of these issues are easier to resolve than others, such as fixing CORS errors due to a development setup versus getting a third-party API configured correctly that you don’t own. In any case, you’ll want to do a quick diagnosis just to make sure that it is, in fact, a CORS issue before jumping into fix-mode.

Quick Diagnosis

Before fixing the issue, confirm it’s actually a CORS problem. You can do this by:

  1. Check the Network tab in browser dev tools – you’ll see the request but no response data.
  2. Look for preflight OPTIONS requests – Complex requests show an OPTIONS call before the actual request.
  3. Test the API directly – Try the same URL in a new browser tab, with curl, Postman, etc. If it works, it’s a CORS issue.

If the API responds normally with curl but fails in your React app, you have a CORS issue.

It’s also important to note that tools like curl and Postman don’t enforce CORS policies since they’re not browsers, so they can’t replicate CORS errors. The browser itself enforces the CORS policy, so always make sure to test in a real browser environment.

Fixing CORS Errors in React

Now that we’ve determined that there is a CORS issue, let’s fix it. When you’re developing a React app, there are a few client-side workarounds that work great for development. Unfortunately, they aren’t suitable for production, though, so we will cover the server-side fixes later. However, you can skip this section and proceed directly to the server-side fixes if you need to implement them in production.

Solution 1: React Proxy (Development Only)

The easiest way to handle CORS during development is to use React’s built-in proxy feature. You can add this to your application’s package.json in the proxy section, like this:

{
  "name": "my-react-app",
  "version": "0.1.0",
  "proxy": "http://localhost:8080",
  "dependencies": {
    // ...
  }
}

Now you can make requests to relative URLs in your React code:

const fetchData = async () => {
  const response = await fetch('/api/data'); // Proxied to localhost:8080
  const data = await response.json();
  return data;
};

This works because instead of using:

fetch('http://localhost:8080/api/data') 

You’ll instead use: 

fetch('/api/data')

Now, the React development server will proxy API requests to your backend server, avoiding CORS issues entirely.

Solution 2: Custom Proxy Configuration

For more complex setups, you can use a custom proxy configuration. To do this, create a setupProxy.js file in your src folder. In the new file, you can add a configuration similar to this:

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'http://localhost:8080',
      changeOrigin: true,
    })
  );
  
  app.use(
    '/auth',
    createProxyMiddleware({
      target: 'http://localhost:9000',
      changeOrigin: true,
    })
  );
};

This setup enables you to proxy different API paths to distinct backend servers, such as one for your application-level services and another for your authentication server.

Limitations of Client-Side Solutions

Now, it’s important to remember that React proxy solutions only work during development. They won’t work in production because they rely on the React development server. For production, you need server-side CORS configuration.

The True Fix: Server-Side CORS Configuration

Although the browser enforces CORS, the server-side configuration is where the true fix needs to be implemented, especially in production. This is because the proper way to handle CORS is on the server side, not through client-side workarounds. The server must send the correct headers to inform browsers that cross-origin requests are permitted and from which domains. Let’s take a look at how this can be done across a few different server-side implementations.

Express.js Server Configuration

If you control the backend API, here’s how you can enable CORS in a Node.js/Express application:

Basic CORS Setup

const express = require('express');
const app = express();

// Basic CORS middleware
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  
  // Handle preflight OPTIONS requests
  if (req.method === 'OPTIONS') {
    return res.status(200).end();
  }
  next();
});

app.get('/api/data', (req, res) => {
  res.json({ message: 'Hello from API!' });
});

Servers must handle preflight OPTIONS requests explicitly. When browsers make complex requests, they first send an OPTIONS request to check permissions. Your server needs to respond appropriately to these preflight requests.

Production-Ready CORS Configuration

In production environments, you’ll likely want to be a bit more explicit about which origins can access your APIs. Here is a more production-ready implementation that specifies environment-specific origins that can access the server. It also provides additional logic for handling mobile requests, allowed methods, and other aspects.

const express = require('express');
const cors = require('cors');
const app = express();

// Environment-specific origins
const allowedOrigins = [
  'http://localhost:3000',  // Development
  'https://myapp.com',      // Production
  'https://www.myapp.com'   // Production with www
];

const corsOptions = {
  origin: function (origin, callback) {
    // Allow requests with no origin (mobile apps, etc.)
    if (!origin) return callback(null, true);
    
    if (allowedOrigins.indexOf(origin) !== -1) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization']
};

app.use(cors(corsOptions));

app.get('/api/data', (req, res) => {
  res.json({ message: 'Hello from API!' });
});

Other Backend Technologies

If you’re not using Express, you’ll still need to create a CORS configuration on your server. Here is how to do so with two other popular frameworks among React developers: Fastify and Flask.

Node.js with Fastify

const fastify = require('fastify')({ logger: true });

fastify.register(require('@fastify/cors'), {
  origin: ['http://localhost:3000', 'https://myapp.com'],
  credentials: true
});

fastify.get('/api/data', async (request, reply) => {
  return { message: 'Hello from Fastify!' };
});

Python with Flask

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app, origins=['http://localhost:3000', 'https://myapp.com'])

@app.route('/api/data')
def get_data():
    return {'message': 'Hello from Flask!'}

Third-Party APIs

Unfortunately, if you’re calling third-party APIs that don’t support CORS, you have limited options. It’s still manageable, but it is not as elegant as the fixes above. In the case where you’re having third-party CORS issues, you can:

  1. Use your backend as a proxy – Make the API call from your server instead of the browser
  2. Contact the API provider – Request CORS support for your domain
  3. Use JSONP (if the API supports it, though this is legacy)

Common CORS Issues and Solutions

While fixing CORS is generally straightforward, it doesn’t mean that further issues don’t appear. Let’s take a look at the three most common problems and their solutions.

Issue 1: Wildcard with Credentials

When your React app sends cookies or authorization headers, browsers enforce strict security rules. Using a wildcard (*) with credentials would allow any website to make authenticated requests using a visitor’s existing login session, which is a serious security vulnerability.

Error: The value of the 'Access-Control-Allow-Origin' header must not be the wildcard '*' when the request's credentials mode is 'include

Solution: Use specific origins when sending credentials:

// React code with credentials
fetch('/api/data', {
  credentials: 'include', // Sends cookies
  headers: {
    'Authorization': 'Bearer token'
  }
});

// Server configuration
res.header('Access-Control-Allow-Origin', 'http://localhost:3000'); // Not '*'
res.header('Access-Control-Allow-Credentials', 'true');

Issue 2: Missing Authorization Header

Browsers only allow certain “simple” headers by default. Custom headers, such as Authorization, must be explicitly permitted by the server. If your React app sends an Authorization header but the server doesn’t include it in the allowed headers list, browsers will block the request.

Error: Request header field authorization is not allowed by Access-Control-Allow-Headers

Solution: Add the Authorization header to the allowed headers:

res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');

Issue 3: Preflight Cache Issues

Browsers cache preflight OPTIONS responses to improve performance. When you change your server’s CORS configuration, browsers may still use the cached preflight response, making it appear as though your changes aren’t working.

Problem: Changes to the CORS config aren’t reflected immediately.

Solution: Clear browser cache or set appropriate cache headers:

res.header('Access-Control-Max-Age', '0'); // Disable preflight caching during development

Best Practices for React CORS

As you move forward with resolving CORS issues and implementing a configuration across your development and production environments, there are a few key best practices to keep in mind. Specific best practices for development generally aren’t a good fit for production environments, which is why I’ve split them out below.

Development Best Practices

In development environments, generally on a local development machine, you’ll want to do the following:

  1. Use React’s proxy feature for local development instead of disabling browser security.
  2. Test with different request types, including both simple and complex requests.
  3. Use environment-specific configurations for different API endpoints.
  4. Handle errors gracefully in your React components.

Production Best Practices

For production (and development, if you prefer), you should keep the following best practices in mind:

  1. Configure server-side CORS instead of relying on client-side workarounds
  2. Use specific origins instead of wildcards in production
  3. Test the CORS configuration before deploying to production
  4. Regularly audit CORS policies for security vulnerabilities

Why Automated CORS Testing Matters

CORS misconfigurations are among the most common security issues in modern web applications. Manual testing often misses edge cases, and it’s easy to create security gaps while attempting to resolve functionality issues inadvertently.

A common mistake when fixing CORS errors is implementing overly permissive configurations that work but create security vulnerabilities. For example, setting Access-Control-Allow-Origin: * with Access-Control-Allow-Credentials: true or using overly broad origin patterns.

One of the most trusted security platforms for this type of testing is StackHawk. By using StackHawk to test for vulnerabilities in your React applications and APIs, you get:

  • Early detection of CORS issues during development
  • Automated testing of complex CORS scenarios you might not think to test manually
  • Clear remediation guidance with specific examples of vulnerable requests
  • Verification that fixes don’t introduce new security issues

By integrating CORS security testing into your development workflow, you can ensure that your cross-origin requests work reliably while maintaining your application’s security.

Validating Your CORS Configuration with StackHawk

Once you’ve implemented CORS headers, it’s crucial to ensure your configuration is both functional and secure. A common mistake is fixing the immediate CORS error but inadvertently creating security vulnerabilities, such as allowing credentials from any origin or being overly permissive with allowed domains.

This is where automated security testing becomes invaluable. Instead of manually testing every possible CORS scenario and hoping you haven’t introduced security gaps, you can use StackHawk to automatically validate that your CORS implementation works correctly without creating new attack vectors.

StackHawk will test your CORS implementation for common security issues, including:

  • Wildcard origin acceptance with credentials: Testing if your API dangerously accepts * as an origin while allowing credentials
  • Origin reflection vulnerabilities: Checking if your API blindly reflects the Origin header without proper validation
  • Missing security headers: Identifying CORS setups that lack proper CSRF protection
  • Overly permissive configurations: Finding CORS policies that are broader than necessary

Instead of waiting for our AppSec team to notify us of an issue later in development, let’s use StackHawk to automatically identify this vulnerability for us. To do this, you’ll need to ensure you have a StackHawk account. If you need one, you can sign up for a trial account or log into an existing account.

If you’re logging into an existing StackHawk account, from the Applications screen, you’ll click Add Application.

Applications 52 findings dashboard

If you’re new to StackHawk, you’ll be automatically brought into the Add an App flow. On the Scanner screen, you’ll see the instructions for installing the StackHawk CLI. Since we will be running our testing locally, we will use this option. Once the hawk init command is executed successfully, click the Next button.

On the next screen, you will fill out an Application Name , Environment , and URL. Once filled out, click Next.

Since we will be testing a RESTful API, on the next page, we will choose our Application Type as “Dynamic Web Application/Single Page Application”.

Application Type details page

Depending on what you have set up as a backend API, you’ll also plug these details in. For example, if you have a REST API running, you would set the API Type to “REST / OpenAPI” and point to our OpenAPI Specification file by selecting the URL Path and adding the path to where your OpenAPI spec is located in the text box. Alternatively, as I’ve done here, we can also click “Skip for now” if you’re unsure. Once complete, click Next.

Lastly, we will need to add a stackhawk.yml file to the root of our project. Once the file is added, copy the screen’s contents, paste them into the file, and save it. Lastly, we can click the Finish button.

In our root directory, we should see the stackhawk.yml file we’ve added:

Lastly, depending on our scan policy, CORS misconfiguration detection may not be enabled. To ensure this, go back to StackHawk, navigate to the Applications page, and select your app. Once on the config page, click on the Settings tab, then the Active Scan Plugins tab, located just below it. Then, locate the CORS Header plugin in the list and select it. You can find it easily by typing “cors” into the plugin search bar.

Lastly, click Save, located just above the Plugins list, to save the new configuration.

Run HawkScan

Next, we can go ahead with testing our application. In a terminal pointing to the root of our project, we will run HawkScan using the following command:

hawk scan

After running the command, the tests should execute in the terminal.

Note that if you get an error similar to:

HawkScan Target Not Found Error: Unable to access https://localhost:4000. Check if the web server is listening on the specified port.

This means that your API is not running in HTTPS, and that is how HawkScan is trying to call the API. To fix this, either add HTTPS capabilities to your API or, more simply, change the host entry in your stackhawk.yml to use only “http”.

This will run tests against our React application and the corresponding backend. Once the tests have run, we can begin to explore any findings that were discovered.

Explore The Initial Findings

Once the tests are complete, the terminal will contain some information about any vulnerabilities found. Below, we can see that StackHawk has found a few CORS vulnerabilities within my code that are present on multiple paths.

To explore this further, we will click on the test link at the bottom of the output. This will take us into the StackHawk platform to explore further.

After clicking on the link, we can now view the test results in a nicely formatted display. Next, we will click on the CORS Misconfiguration entry.

Within this entry, we can see an Overview and Resources that can help us with fixing this vulnerability, as well as the Request and Response that the API returned on the right side of the screen. Above this, you will also see a Validate button, which will display a cURL command with the exact HTTP request used to expose the vulnerability.

Understanding and Fixing CORS Security Issues

When StackHawk identifies CORS vulnerabilities, you’ll see detailed findings that indicate which paths are affected and provide potential remediation techniques (as shown in the image above). Using the techniques in this guide or the remediation advice provided by StackHawk for the vulnerability, you can then make the necessary adjustments to your code and configuration. Once fixed, ensure that you stop your web servers and redeploy the latest code. Next, we can ensure that the fix implemented actually resolves our CORS misconfiguration issues.

Confirm the fix!

With the latest code deployed, let’s confirm the fix in StackHawk. To do this, we will click the “Rescan Findings” button in StackHawk.

Then, we will see a modal containing the “hawk rescan” command that includes the correct Scan ID. You’ll run this command in the same terminal where you ran the initial set of tests.

Rescan findings window

In the output, you will again see any vulnerabilities that were found during the scan. In this case, you’ll see that the CORS misconfiguration vulnerabilities are no longer showing. Clicking on the link at the bottom of the terminal output, you can confirm that the CORS misconfiguration vulnerabilities have now been added to the Fixed Findings from Previous Scan, confirming that the vulnerability has been successfully fixed and has passed any vulnerability tests.

With that, we’ve successfully remedied and retested our application to ensure its safety from potential CORS misconfiguration attacks.

Secure Your React CORS Configuration with StackHawk

CORS errors are common when building React applications that communicate with APIs. While there are client-side workarounds for development (like React’s proxy feature), the proper solution is always to configure CORS on the server side.

Remember that fixing CORS errors correctly means ensuring your API works for legitimate requests while blocking potential security threats. Tools like StackHawk help automate this security validation, giving you confidence that your React CORS implementation is both functional and secure.

Want to ensure your React CORS configuration is secure? Sign up for StackHawk today for a free 14-day trial to automatically test your CORS configuration and detect potential vulnerabilities.

FEATURED POSTS

Security Testing for the Modern Dev Team

See how StackHawk makes web application and API security part of software delivery.

Watch a Demo

Subscribe to Our Newsletter

Keep up with all of the hottest news from the Hawk’s nest.

"*" indicates required fields

More Hawksome Posts