What Is CORS and Why Is It Blocking My Request?
CORS is the browser refusing to let your JavaScript read a response from a different origin, because the server did not say it was allowed.
The two things people get wrong immediately:
Your server is not blocking you. The browser is. The request usually reaches the server and the server usually responds. The browser then refuses to hand that response to your code.
Only the browser enforces it. The same call from curl, Postman or your backend works fine. CORS is not a firewall. It is a rule browsers apply to protect users.
01Why It Exists
Without CORS, any website you visited could make authenticated requests to any other site using your cookies, and read the answers. Your bank, your email, your admin panel.
The same-origin policy blocks that by default. CORS is the mechanism a server uses to say "requests from this specific other origin are fine."
So CORS is not the restriction. The same-origin policy is the restriction. CORS is the way to relax it deliberately.
02What Counts as a Different Origin
An origin is scheme + host + port. All three must match, or it is cross-origin.
| From | To | Same origin? |
|---|---|---|
| https://app.example.com | https://app.example.com/api | Yes |
| https://app.example.com | http://app.example.com | No, scheme differs |
| https://app.example.com | https://api.example.com | No, host differs |
| https://app.example.com | https://app.example.com:8080 | No, port differs |
| http://localhost:3000 | http://localhost:8000 | No, port differs |
That last row is why nearly every developer meets CORS in their first week.
03The Preflight Request
The part that confuses people most is the request they never made.
For anything beyond a simple request, the browser first sends an OPTIONS request asking permission:
http
OPTIONS /api/users HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type, authorization
The server must answer with what it allows:
http
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: content-type, authorization
Access-Control-Max-Age: 86400
Only then does the browser send the real request.
A request avoids preflight only if it uses GET, HEAD or POST, sends no custom headers, and uses a Content-Type of text/plain, multipart/form-data or application/x-www-form-urlencoded.
Which means sending Content-Type: application/json triggers a preflight. Almost every modern API call does.
04The Five Causes of a CORS Error
- The server sends no
Access-Control-Allow-Originheader at all. The most common cause. Nothing is configured. - The header is present but does not match your origin. Including a trailing slash mismatch, or
httpwhere you senthttps. - The preflight is not handled. The server returns 404 or 405 to
OPTIONSbecause no route exists for it. Related: 405 Method Not Allowed. - A header is not on the allow list. You send
Authorizationand the server never declared it inAccess-Control-Allow-Headers. - Credentials plus a wildcard. If you send cookies with
credentials: 'include', the server cannot replyAccess-Control-Allow-Origin: *. It must name your exact origin, and also sendAccess-Control-Allow-Credentials: true.
That last one catches people who "fixed" CORS with a wildcard and then added authentication.
05How To Fix It Properly
Configure the server. This is the only real fix. Set Access-Control-Allow-Origin to the origins you actually want, plus the methods and headers you accept. Every framework has middleware for it.
Do not use * in production if the API is authenticated. A wildcard means any website can call your API from a user's browser. Name your origins.
Handle OPTIONS explicitly. If your router does not answer preflight requests, nothing else you configure matters.
Set Access-Control-Max-Age. It tells the browser to cache the preflight result, so you are not doubling every request.
Use a proxy in development. Most dev servers can proxy /api to your backend, making everything same-origin locally. This removes the problem rather than working around it.
Do not use a browser extension that disables CORS. It fixes your machine and nobody else's, and it hides the problem until production.
06FAQ
What does a CORS error actually mean?
The browser blocked your JavaScript from reading a response from a different origin because the server did not send headers permitting it. The request usually succeeded; you are just not allowed to see the result.
Why does my API work in Postman but not the browser?
Postman is not a browser and does not enforce the same-origin policy. CORS is a browser rule, so tools outside the browser are unaffected. This is normal and it means the server is fine.
What is a preflight request?
An automatic OPTIONS request the browser sends before the real one, asking the server which origins, methods and headers it permits. Any request with a custom header or Content-Type: application/json triggers one.
Can I fix CORS from the frontend?
No. The headers must come from the server. Anything that appears to fix it client-side is either a dev-server proxy, which is legitimate, or a browser extension, which is not a fix.
Is Access-Control-Allow-Origin: * safe?
For a public read-only API, generally yes. For an authenticated one, no. It also cannot be used at all with credentialed requests, where the server must name the exact origin.
Why does localhost:3000 get CORS errors calling localhost:8000?
Because an origin is scheme, host and port together. Different ports are different origins even on the same machine. Use a dev-server proxy or configure the backend to allow the frontend's origin.
Does CORS protect my API?
Not really. It protects your users' browsers from other websites making authenticated requests on their behalf. Anything not a browser ignores CORS entirely, so it is not access control. Use authentication for that.
07Related
- 405 Method Not Allowed - what happens when OPTIONS is not handled
- What Is a Bearer Token? - the header that most often triggers a preflight
- API Fundamentals - requests, headers and responses from scratch
Source: MDN: Cross-Origin Resource Sharing
08About ApyHub
ApyHub is a curated API catalog for developers, teams and AI agents: file conversion, data validation, OCR and extraction and more across 20 categories. One key covers all of it, every endpoint is MCP-ready so AI agents can discover and call them directly, and every service page has a playground for testing before you build.
EU-based and EU-hosted, which keeps data residency simple for teams with GDPR obligations.
Browse the catalog | Get a free API key - no credit card required.
