How to Resolve "CORS Header 'Access-Control-Allow-Origin' Missing" Error
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.
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
Authorizationor JSON content types) trigger a preflightOPTIONSrequest that returns404 Not Foundor405 Method Not Allowedinstead of200 OKwith 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
Originheader dynamically. - Unmatched Allowed Origins list: The server hardcodes specific origins (e.g.,
https://production.com) and rejects requests originating from development or staging URLs likehttp://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.