How to Fix CORS Errors in REST API Development: Causes and Solutions

One of the most popular services we offer is ongoing website maintenance because most clients we work with become return clients.

How to Fix CORS Errors in REST API Development: Causes and Solutions

How to Fix CORS Errors in REST API Development

If you have ever built a frontend that calls a REST API, chances are you have seen this dreaded message in your 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.

It stops your application dead in its tracks. Nothing renders. Your API call fails silently or throws an ugly error. And the worst part? Your API works perfectly fine in Postman or cURL.

This guide will explain what CORS errors are, why they happen, and walk you through the most common fixes across Node.js (Express), Python (Flask), and browser-based requests. Whether you are building your first REST API or debugging a production issue, this post covers everything you need.

What Is CORS Exactly?

CORS stands for Cross-Origin Resource Sharing. It is a security mechanism built into web browsers that controls how web pages from one origin (domain, protocol, or port) can request resources from a different origin.

An “origin” is defined by three components:

  • Protocol (http vs https)
  • Domain (example.com vs api.example.com)
  • Port (3000 vs 8080)

If any of these differ between the page making the request and the server receiving it, the browser treats it as a cross-origin request and enforces CORS rules.

Why Does CORS Exist?

CORS exists to protect users. Without it, any malicious website could make requests to your bank’s API using your cookies and session data. The browser’s Same-Origin Policy blocks this by default. CORS is the mechanism that allows servers to selectively relax this restriction for trusted origins.

What Causes CORS Errors?

A CORS error occurs when the browser sends a cross-origin request and the server’s response does not include the proper CORS headers. Here are the most common causes:

Cause Description
Missing Access-Control-Allow-Origin header The server response does not include this header at all.
Origin mismatch The header exists but does not match the requesting origin (e.g., the server allows https://app.com but the request comes from http://localhost:3000).
Preflight request failure The browser sends an OPTIONS request first, and the server does not handle it correctly.
Disallowed HTTP method The server does not include the method (PUT, DELETE, PATCH) in Access-Control-Allow-Methods.
Disallowed custom headers The request includes headers (like Authorization) not listed in Access-Control-Allow-Headers.
Credentials not allowed The request sends cookies or auth tokens but the server does not set Access-Control-Allow-Credentials: true.
Wildcard with credentials The server responds with Access-Control-Allow-Origin: * while credentials are included, which browsers reject.

Understanding Preflight Requests

Before diving into fixes, it is important to understand preflight requests because they are responsible for a large percentage of CORS errors developers encounter.

When your browser determines a request is “not simple” (for example, it uses PUT, DELETE, or includes custom headers like Authorization), it first sends an OPTIONS request to the server. This is the preflight. The server must respond to this OPTIONS request with the appropriate CORS headers. Only then will the browser proceed with the actual request.

A request triggers a preflight if it meets any of these conditions:

  1. Uses a method other than GET, HEAD, or POST
  2. Includes headers beyond the basic set (Accept, Content-Type with limited values, etc.)
  3. Uses Content-Type with a value other than application/x-www-form-urlencoded, multipart/form-data, or text/plain

If your server does not respond to OPTIONS requests properly, the preflight fails and your actual request never gets sent.

How to Fix CORS Errors: Step-by-Step Solutions

Now let’s get into the practical fixes. We will cover server-side solutions (the correct approach), development workarounds, and framework-specific implementations.

Fix 1: Add CORS Headers on the Server (The Right Way)

The proper solution to a CORS error is always to configure the server to send the correct response headers. This tells the browser which origins, methods, and headers are allowed.

The key headers you need to set are:

  • Access-Control-Allow-Origin – Which origins can access the resource
  • Access-Control-Allow-Methods – Which HTTP methods are permitted
  • Access-Control-Allow-Headers – Which request headers are permitted
  • Access-Control-Allow-Credentials – Whether cookies/auth can be sent
  • Access-Control-Max-Age – How long the preflight result can be cached

Node.js / Express

The easiest approach in Express is to use the cors middleware package:

npm install cors

Basic usage (allows all origins):

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

app.use(cors());

app.get('/api/data', (req, res) => {
  res.json({ message: 'CORS is working!' });
});

app.listen(8080);

For production, you should restrict the allowed origins:

const corsOptions = {
  origin: ['https://yourfrontend.com', 'https://app.yourfrontend.com'],
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
  maxAge: 86400
};

app.use(cors(corsOptions));

Manual setup without the cors package:

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'https://yourfrontend.com');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.header('Access-Control-Allow-Credentials', 'true');

  // Handle preflight
  if (req.method === 'OPTIONS') {
    return res.sendStatus(204);
  }
  next();
});

Python Flask

Install the Flask-CORS extension:

pip install flask-cors

Basic usage:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route('/api/data')
def get_data():
    return {'message': 'CORS is working!'}

Restricted configuration for production:

CORS(app, resources={
    r"/api/*": {
        "origins": ["https://yourfrontend.com"],
        "methods": ["GET", "POST", "PUT", "DELETE"],
        "allow_headers": ["Content-Type", "Authorization"],
        "supports_credentials": True
    }
})

Django (Django REST Framework)

Install django-cors-headers:

pip install django-cors-headers

Add to your settings.py:

INSTALLED_APPS = [
    ...
    'corsheaders',
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    ...
]

CORS_ALLOWED_ORIGINS = [
    'https://yourfrontend.com',
]

CORS_ALLOW_CREDENTIALS = True

Fix 2: Handle Preflight (OPTIONS) Requests Properly

If you are setting headers manually and still getting CORS errors on PUT, DELETE, or requests with custom headers, the issue is almost certainly the preflight OPTIONS request.

Make sure your server:

  1. Responds to OPTIONS requests on the same endpoint
  2. Returns a 200 or 204 status code (not 404 or 500)
  3. Includes all CORS headers in the OPTIONS response

If you use a framework middleware like cors for Express or flask-cors, this is handled automatically. If you configure things manually, you must explicitly handle OPTIONS.

Fix 3: Use a Proxy During Development

During local development, your frontend often runs on localhost:3000 while your API runs on localhost:8080. Instead of configuring CORS just for development, you can use a development proxy so the browser thinks everything comes from the same origin.

React (Create React App / Vite)

In vite.config.js:

export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
      }
    }
  }
});

Now your frontend can call /api/data instead of http://localhost:8080/api/data, and the dev server proxies the request. No CORS issue at all.

Angular

Create a proxy.conf.json:

{
  "/api": {
    "target": "http://localhost:8080",
    "secure": false,
    "changeOrigin": true
  }
}

Then run: ng serve --proxy-config proxy.conf.json

Fix 4: Use a Serverless Function or Backend Proxy

If you are consuming a third-party API that you do not control and it does not send CORS headers, you cannot fix this on the client side. The solution is to route the request through your own backend or a serverless function.

The flow looks like this:

  1. Your frontend calls your own server: GET /api/proxy/weather
  2. Your server calls the third-party API (server-to-server, no CORS applies)
  3. Your server returns the data to the frontend with proper CORS headers

This works because CORS is a browser-only restriction. Server-to-server HTTP requests are not subject to CORS rules.

Example with a serverless function (e.g., Vercel, AWS Lambda, Cloudflare Workers):

// Vercel serverless function: /api/proxy.js
export default async function handler(req, res) {
  const response = await fetch('https://thirdparty-api.com/data', {
    headers: { 'Authorization': 'Bearer YOUR_KEY' }
  });
  const data = await response.json();

  res.setHeader('Access-Control-Allow-Origin', '*');
  res.status(200).json(data);
}

Fix 5: Quick Development Workarounds (Not for Production)

These are temporary workarounds for local development only. Never rely on these in production.

Workaround How Risk
Browser extension Install a CORS-unblock extension in Chrome or Firefox Disables security for all sites while active
Disable browser security Launch Chrome with --disable-web-security flag Completely disables Same-Origin Policy
Public CORS proxy Route requests through a service like cors-anywhere Third party sees all your traffic, rate limits apply

Warning: Using --disable-web-security or CORS extensions leaves your browser vulnerable. Use a separate browser profile for development if you go this route, and never browse the web with security disabled.

Common CORS Error Messages and What They Mean

Here is a quick reference table to help you diagnose specific error messages:

Error Message What It Means Fix
No ‘Access-Control-Allow-Origin’ header is present Server is not sending CORS headers at all Add CORS middleware or headers on the server
The value of the ‘Access-Control-Allow-Origin’ header must not be the wildcard ‘*’ You are sending credentials but using a wildcard origin Replace * with the specific origin
Method PUT is not allowed by Access-Control-Allow-Methods The server does not list PUT in allowed methods Add PUT to Access-Control-Allow-Methods
Request header field authorization is not allowed The Authorization header is not in allowed headers Add Authorization to Access-Control-Allow-Headers
Response to preflight request doesn’t pass access control check The OPTIONS request failed or returned wrong status Ensure OPTIONS returns 200/204 with correct headers

CORS Debugging Checklist

When you hit a CORS error, run through this checklist before searching for more complex solutions:

  1. Open the browser DevTools Network tab and look at the actual request and response headers
  2. Check if there is an OPTIONS preflight request and whether it succeeded (status 200 or 204)
  3. Verify the response includes Access-Control-Allow-Origin with the correct origin value
  4. If using credentials (cookies, Authorization header), confirm the server sets Access-Control-Allow-Credentials: true and does NOT use wildcard * for the origin
  5. Check the request method and headers against what the server allows
  6. Test the API directly with cURL or Postman to confirm the API itself works (these tools do not enforce CORS)
  7. Check middleware order in your server framework. CORS middleware must run before your route handlers.
  8. Look for typos in origins such as a trailing slash (https://example.com/ vs https://example.com)

Best Practices for CORS in Production

Once you have fixed your CORS error, make sure your configuration is secure and maintainable:

  • Never use Access-Control-Allow-Origin: * in production if your API handles authentication or sensitive data. Always whitelist specific origins.
  • Keep your allowed origins list in environment variables so you can manage different values for development, staging, and production.
  • Set Access-Control-Max-Age to cache preflight responses and reduce the number of OPTIONS requests. A value of 86400 (24 hours) is common.
  • Only allow the HTTP methods and headers your API actually needs. Do not open everything just to make errors go away.
  • If you use a CDN or reverse proxy (Nginx, Cloudflare, AWS ALB), check that it is not stripping or overwriting your CORS headers.
  • Log preflight failures on your server so you can identify misconfiguration early.

CORS Errors with Specific Frontend Frameworks

React (fetch / axios)

CORS errors in React projects are almost always a server issue. React itself does not control CORS. However, a common mistake is setting headers on the client request thinking it will fix CORS:

// This does NOT fix CORS!
fetch('https://api.example.com/data', {
  headers: {
    'Access-Control-Allow-Origin': '*'  // Wrong! This is a response header.
  }
});

Access-Control-Allow-Origin is a response header that must be set by the server. Setting it on the client request does nothing.

If you are working locally, use the Vite proxy or CRA proxy configuration shown above.

Angular (HttpClient)

Same principle applies. Use the Angular dev proxy for local development, and ensure your backend sets the proper CORS headers for production.

JavaScript Fetch API

When using the Fetch API with credentials:

fetch('https://api.example.com/data', {
  method: 'GET',
  credentials: 'include'  // Sends cookies
});

The server must respond with:

Access-Control-Allow-Origin: https://yourfrontend.com  (NOT *)
Access-Control-Allow-Credentials: true

Frequently Asked Questions

What causes CORS errors?

CORS errors are caused by the browser blocking a cross-origin HTTP request because the server’s response does not include the required CORS headers. This happens when your frontend and backend are on different origins (different domain, protocol, or port).

How do I resolve a CORS error?

The correct fix is to configure your server to return the appropriate CORS headers, specifically Access-Control-Allow-Origin. Use a CORS middleware for your framework (such as the cors npm package for Express or flask-cors for Flask). For third-party APIs you do not control, use a backend proxy or serverless function.

How to get rid of CORS errors in Chrome?

For development, you can use Chrome with the --disable-web-security flag or install a CORS extension. However, these are temporary workarounds. The real fix is always on the server side. For production, you must configure proper CORS headers on your API server.

How to bypass CORS errors locally?

The best approach for local development is to use a dev server proxy (available in Vite, Webpack Dev Server, and Angular CLI). This routes your API requests through the same origin as your frontend, eliminating CORS entirely during development without any security compromise.

Why does my API work in Postman but not in the browser?

Postman and cURL are not browsers, so they do not enforce the Same-Origin Policy or CORS. They send the request directly without any preflight check. Browsers enforce CORS to protect end users, which is why the same request fails in a browser but works in Postman.

Can I fix CORS errors from the frontend?

No. CORS is enforced by the browser based on the server’s response headers. You cannot fix it by adding headers to your frontend request. The fix must come from the server or by using a proxy that you control.

Wrapping Up

CORS errors are one of the most common and frustrating issues in REST API development, but they follow predictable patterns. In almost every case, the solution is to configure your server correctly. Use framework-specific CORS middleware, handle preflight OPTIONS requests, and avoid wildcard origins when credentials are involved.

For local development, proxy configurations are your best friend. For third-party APIs, route requests through your own backend. And whatever you do, avoid disabling browser security in production.

At Pixelseed, we build REST APIs and web applications with security and developer experience in mind. If you are struggling with CORS or any other API integration challenge, feel free to reach out.

Subscription Form

Contact Details

Quick Links

Copyright © 2022 Pixel Seed. All Rights Reserved.