CORS Error: No 'Access-Control-Allow-Origin' header is present
The browser blocked a cross-origin request because the server’s response didn’t include the CORS headers allowing your site’s origin.
Meaning
CORS is enforced by the browser, not the server. Your request often reaches the server and even succeeds — but the browser hides the response from your JavaScript because the server didn’t explicitly allow your origin.
That’s why the same request works in curl or Postman but fails in the browser. The fix is almost always on the server: return the right Access-Control-Allow-* headers, including for the OPTIONS preflight request.
Common causes
- Server doesn’t send
Access-Control-Allow-Originfor your origin - Preflight
OPTIONSrequest not handled (returns 404/405/401) - Using
Access-Control-Allow-Origin: *together with credentials (cookies) — not allowed - Custom headers (Authorization, X-Requested-With) not listed in
Access-Control-Allow-Headers - Error responses (4xx/5xx) skip the CORS middleware, so the real error is hidden
- Origin mismatch: http vs https, www vs non-www, different port
⚡ Quick fix
- Add the CORS headers on the server for your exact origin
- Respond to
OPTIONSwith 204 and the allow headers - If sending cookies, set a specific origin (not
*) andAccess-Control-Allow-Credentials: true - In development, use your dev server’s proxy instead of calling the API cross-origin
- Check the Network tab: if the preflight failed, fix that first
Detailed fix by platform
Node.js
- Express with the cors package:javascript
import cors from 'cors'; app.use(cors({ origin: ['https://app.example.com', 'http://localhost:5173'], credentials: true, allowedHeaders: ['Content-Type', 'Authorization'], }));
PHP
- Plain PHP (before any output):php
$allowed = ['https://app.example.com']; $origin = $_SERVER['HTTP_ORIGIN'] ?? ''; if (in_array($origin, $allowed, true)) { header("Access-Control-Allow-Origin: $origin"); header('Access-Control-Allow-Credentials: true'); header('Access-Control-Allow-Headers: Content-Type, Authorization'); header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS'); header('Vary: Origin'); } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; }
Nginx
- Add headers with
alwaysso they’re also sent on errors:nginxadd_header Access-Control-Allow-Origin "https://app.example.com" always; add_header Access-Control-Allow-Headers "Content-Type, Authorization" always; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always; if ($request_method = OPTIONS) { return 204; }
React
- In development, proxy API calls through the dev server (Vite
server.proxy, CRA"proxy"in package.json) so the browser sees a same-origin request.
AWS
- S3: add a CORS configuration on the bucket. API Gateway: enable CORS on the resource and redeploy the stage; Lambda proxy integrations must return the headers themselves.
Code examples
Test the preflight from the command line
curl -i -X OPTIONS https://api.example.com/users \
-H "Origin: https://app.example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: content-type, authorization"The response must include matching Access-Control-Allow-* headers and a 2xx status.
How to diagnose
- Network tab — Is the failing request the OPTIONS preflight or the actual request?
- Origin — What exact Origin does the browser send?
- Response headers — Does the response include Access-Control-Allow-Origin for that origin?
- Credentials — Are cookies involved? Then no wildcard origin.
- Errors — Is the server actually returning 4xx/5xx without CORS headers?
🧠 Still stuck? Analyze your error
Paste the full message, response headers or stack trace — we'll detect the platform and point to the most likely cause.
Report a correction or suggest an improvement
Last updated 2 Oct 2026