This error means your browser sent a cross-origin request, the server's response did not include permission for your page's origin, and the browser refused to hand the response to your JavaScript. The request often did reach the server; the browser blocks only the reading of the result. CORS (Cross-Origin Resource Sharing) is enforced by browsers, which is why the same call works fine from curl or Postman.
You see it in the browser developer console when a page on one origin (scheme, host and port together) calls an API on another, for example https://app.example.com calling https://api.example.com, or http://localhost:3000 calling http://localhost:8000.
The fix always lives on the server that receives the request. Frontend code cannot grant itself permission.
Causes, most likely first
- The API does not send
Access-Control-Allow-Originat all. CORS was never configured. - The header is sent but with a different origin, a typo, wrong scheme (
httpversushttps), a missing port, orwwwversus non-www. - The preflight
OPTIONSrequest fails. For requests with custom headers, JSON content type or methods like PUT and DELETE, the browser first sendsOPTIONS; if that returns 404, 405, a redirect or no CORS headers, the real request is never made. - Error responses lack CORS headers. A 401, 404 or 500 returned by a proxy or an exception handler often skips the middleware that adds them, so you see a CORS error that hides the real status.
- Credentialed requests with a wildcard. With cookies or
credentials: 'include', the server must name the exact origin and sendAccess-Control-Allow-Credentials: true;*is rejected. - A redirect on the API call that drops the headers, or a CDN or proxy stripping them.
Step 1: look at the actual response
Reproduce the browser request with curl, adding the Origin header:
curl -i -H "Origin: https://app.example.com" https://api.example.com/data
Look for Access-Control-Allow-Origin in the response. Then simulate the preflight:
curl -i -X OPTIONS https://api.example.com/data \
-H "Origin: https://app.example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: content-type,authorization"
A correct preflight returns a 2xx status (commonly 204) with Access-Control-Allow-Origin, Access-Control-Allow-Methods and Access-Control-Allow-Headers. The CORS Checker performs these tests from outside, and the HTTP Header Checker shows raw headers. In the browser, open the Network tab, find the failing request and its OPTIONS sibling, and inspect status and headers.
Step 2: add the headers on the server
Allow only the origins you trust. Examples:
Express (Node):
const cors = require('cors');
app.use(cors({
origin: ['https://app.example.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
}));
Place it before your routes so it also covers errors and OPTIONS.
nginx:
location /api/ {
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin "https://app.example.com" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
add_header Access-Control-Max-Age 86400 always;
return 204;
}
add_header Access-Control-Allow-Origin "https://app.example.com" always;
add_header Vary Origin always;
proxy_pass http://backend;
}
Apache:
Header always set Access-Control-Allow-Origin "https://app.example.com"
Header always set Access-Control-Allow-Methods "GET, POST, OPTIONS"
Header always set Access-Control-Allow-Headers "Content-Type, Authorization"
Use the always keyword so headers are added to error responses too. If you allow several origins, check the request's Origin against an allowlist in code and echo back the matching one, sending Vary: Origin so caches do not serve one origin's answer to another.
Step 3: handle credentials correctly
If your frontend uses fetch(url, { credentials: 'include' }), the response must contain Access-Control-Allow-Credentials: true and an explicit Access-Control-Allow-Origin with the exact origin, not *. Cookies also need suitable SameSite and Secure attributes for cross-site use; see cookie flags.
Step 4: dodge common traps
- Redirects. Call the final URL; a
301fromhttptohttpsor from a missing trailing slash can break the preflight, which does not follow redirects. - Wrong URL gives 404 without headers, which appears as CORS. Check the status code with the HTTP स्टेटस चेकर.
- Duplicate headers. If both the app and the proxy add
Access-Control-Allow-Origin, the browser rejects the duplicate value. Add it in one place. mode: 'no-cors'does not fix anything: it gives you an opaque response you cannot read. Avoid it as a workaround.- Public CORS proxies expose your traffic and are not suitable for production.
- Same origin alternative. Serve the API under the same origin through a reverse proxy path such as
/api, and CORS no longer applies.
How to verify
Repeat the curl tests and confirm the headers appear on both the OPTIONS and the real request, including on error responses. Reload the page with the Network tab open, with cache disabled, and confirm no console error remains. Run the CORS Checker for an outside view. If the API now returns data, validate its body with the JSON वैलिडेटर.
अगले कदम
- Test your API with the CORS Checker.
- Inspect raw headers with the HTTP Header Checker.
- Read how to monitor API endpoints.
- Review the HTTP security headers guide.
सामान्य प्रश्न
Why does it work in Postman but not in the browser?
CORS is enforced by browsers only. Postman and curl do not apply the policy.
Can I fix CORS from the frontend?
No. The server must send the permission headers. Frontend options are to use a same-origin proxy or to change the API.
Is Access-Control-Allow-Origin: * safe?
For public, unauthenticated data it is fine. For anything using cookies or tokens, list specific origins instead, and never combine a wildcard with credentials.
Why do I see a CORS error when the real problem is a 500?
Error responses often lack CORS headers, so the browser reports a CORS failure and hides the status. Check the Network tab and the server log.
Get notified when this fix updates
Plus occasional practical tips on uptime and monitoring, nothing else. Unsubscribe anytime.
यह पेज सामान्य जानकारी है, जिसे हमारी संपादकीय टीम ने लिखा है और दस्तावेज़ीकरण बदलने पर अपडेट किया जाता है। सर्वर और प्रदाता अलग-अलग होते हैं, इसलिए बदलाव पहले सुरक्षित तरीके से जाँचें। देखें: संपादकीय नीति और अस्वीकरण.