/errors/cors/no-access-control-allow-origin
blocked by CORS policy: No 'Access-Control-Allow-Origin' header
The commands on this page have not been executed by our verification runner yet.updated 2026-10-20
- tool
- CORS
- versions
- all modern browsers
- os
- any
Chrome reports Access to fetch at '…' from origin '…' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. when a page reads a response from another origin and the response does not allow it. The request did reach the server; the browser hides the response from your script. The fix is on the server.
What the browser checks
- Your page's origin, for example
http://localhost:5173, differs from the API originhttps://api.example.com. - For "non-simple" requests (JSON body, custom headers, PUT/DELETE) the browser first sends an
OPTIONSpreflight. - The response (and the preflight response) must contain
Access-Control-Allow-Originmatching your origin, or*for requests without credentials.
Fix on the server
A minimal Express example:
app.use((req, res, next) => {
res.set('Access-Control-Allow-Origin', 'https://app.example.com');
res.set('Vary', 'Origin');
if (req.method === 'OPTIONS') {
res.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
return res.sendStatus(204);
}
next();
});nginx equivalent:
add_header Access-Control-Allow-Origin "https://app.example.com" always;
add_header Vary Origin always;Cookies and credentials
With fetch(url, { credentials: 'include' }) the server must reply with the exact origin (never *) and Access-Control-Allow-Credentials: true.
Check the headers without a browser
curl -si -X OPTIONS https://api.example.com/items \
-H 'Origin: https://app.example.com' \
-H 'Access-Control-Request-Method: POST' | grep -i '^access-control'Sources
Related pages
config · httpStrict-Transport-Security (HSTS): max-age, includeSubDomains, preloadStrict-Transport-Security makes browsers use only HTTPS for max-age seconds. includeSubDomains covers subdomains; preload is a commitment that is hard to undo.flags · httpSet-Cookie attributes: SameSite, Secure, HttpOnly, Max-AgeSet-Cookie attributes decide when browsers send a cookie: SameSite controls cross-site requests, None needs Secure, HttpOnly hides it from JavaScript.errors · jsonSyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSONJSON.parse fails with Unexpected token '<' when the response is an HTML page, usually an error or login page, not JSON. Check the status and content type first.