Cybersecurity / Networking

How to Resolve "CORS Header 'Access-Control-Allow-Origin' Missing" Error

4 min read by DebuggedIt

Quick answer

When developing modern web applications with frontend frameworks like React, Vue, or Angular communicating with an isolated API backend, browsers enforce the...

When developing modern web applications with frontend frameworks like React, Vue, or Angular communicating with an isolated API backend, browsers enforce the Same-Origin Policy (SOP). If the API server does not explicitly include the Access-Control-Allow-Origin HTTP response header during cross-origin requests, the browser blocks the response from being read by client-side JavaScript. Resolving this issue requires properly configuring CORS middleware on your backend server or reverse proxy to return valid headers for cross-site requests.

The Problem

When sending requests or configuring components in your development environment, the application or HTTP client fails with the following exact error trace:

# Example 1: Chrome Developer Console Error
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.

# Example 2: Firefox Web Console Error
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://api.example.com/data. 
(Reason: CORS header 'Access-Control-Allow-Origin' missing). Status code: 200.

# Example 3: Safari Network Error
Fetch API cannot load https://api.example.com/data. Response to preflight request doesn't pass access control check: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

This error halts script execution, prevents API communication, or results in immediate client-side connection drops.

Browser (Client) Origin: localhost:3000 1. OPTIONS Preflight / GET Request 2. Response WITHOUT Access-Control-Allow-Origin API Server api.example.com Browser Security Engine: Blocks Response Data from Web Application

Why It Happens

This failure occurs due to misconfigurations at the networking, cryptographic, or application protocol layer. The primary causes include:

  • Missing Backend CORS Middleware: The application server (Express, FastAPI, Django, Spring Boot) lacks CORS middleware configuration, leaving HTTP responses without cross-origin headers.
  • Unmapped Preflight OPTIONS Requests: Non-simple HTTP requests (containing custom headers like Authorization or JSON content types) trigger a preflight OPTIONS request that returns 404 Not Found or 405 Method Not Allowed instead of 200 OK with CORS headers.
  • Reverse Proxy Stripping Headers: Nginx, Apache, or AWS CloudFront is configured to handle SSL/caching but drops custom backend headers or fails to reflect the Origin header dynamically.
  • Unmatched Allowed Origins list: The server hardcodes specific origins (e.g., https://production.com) and rejects requests originating from development or staging URLs like http://localhost:3000.

The Fix

Follow these step-by-step solutions to resolve the error in your environment.

Solution 1: Configure CORS Middleware in Backend Frameworks

Enable and configure explicit CORS handling directly within your API framework.

For Node.js / Express:

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

const allowedOrigins = ['http://localhost:3000', 'https://yourdomain.com'];

app.use(cors({
  origin: function (origin, callback) {
    if (!origin || allowedOrigins.indexOf(origin) !== -1) {
      callback(null, true);
    } else {
      callback(new Error('CORS header Access-Control-Allow-Origin missing or restricted'));
    }
  },
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));

For Python / FastAPI:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000", "https://yourdomain.com"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Solution 2: Configure CORS at the Reverse Proxy (Nginx)

If your API runs behind Nginx, handle preflight OPTIONS requests directly at the proxy level to ensure headers are injected even if the backend application errors out:

server {
    listen 443 ssl;
    server_name api.example.com;

    location / {
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' '$http_origin' always;
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
            add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Accept' always;
            add_header 'Access-Control-Allow-Credentials' 'true' always;
            add_header 'Content-Length' 0;
            add_header 'Content-Type' 'text/plain charset=UTF-8';
            return 204;
        }

        add_header 'Access-Control-Allow-Origin' '$http_origin' always;
        add_header 'Access-Control-Allow-Credentials' 'true' always;

        proxy_pass http://localhost:8080;
    }
}

Solution 3: Verify Preflight Responses via cURL

Simulate a browser CORS preflight request using cURL to verify that Access-Control-Allow-Origin is present in response headers:

curl -i -X OPTIONS https://api.example.com/data   -H "Origin: http://localhost:3000"   -H "Access-Control-Request-Method: POST"   -H "Access-Control-Request-Headers: Authorization, Content-Type"

Confirm the response includes Access-Control-Allow-Origin: http://localhost:3000 and HTTP/1.1 200 OK or 204 No Content.

Still Not Working?

Credentials and Wildcard Origin Conflict

If your request sends cookies or uses Authorization headers with credentials: 'include' in fetch or Axios, setting Access-Control-Allow-Origin: * will result in a CORS violation. Browsers strictly disallow wildcard origins when credentials are enabled. Replace * with dynamic origin reflection or explicit domain lists on your server response, and ensure Access-Control-Allow-Credentials: true is explicitly returned.