What Is a CORS Error, and How Do You Fix It?
A CORS error is one of the most common things a web developer runs into, and one of the most commonly misunderstood — it’s not a bug in your code, not a bug in the API, and not something you can fix by changing anything in your JavaScript. It’s the browser enforcing a rule that only the server on the other end can change.
This guide explains what’s actually happening, why it exists, and what your real options are depending on whether you control the API you’re calling.
What CORS actually is
CORS (Cross-Origin Resource Sharing) is a browser security rule: by default, JavaScript running on one origin (say, https://yourapp.com) can’t read the response from a request to a different origin (https://api.example.com), even though the request itself often goes out and the server responds normally. The browser gets the response and then throws it away before your code ever sees it, unless the server explicitly said it’s okay.
That "explicitly said it’s okay" is an Access-Control-Allow-Origin response header. If the API doesn’t send one that matches your origin, the browser blocks your JavaScript from reading the response — regardless of whether the request itself succeeded on the server.
Why it exists
Without this rule, any website you visit could silently make authenticated requests to other sites you’re logged into — your bank, your email — using cookies your browser sends automatically, and read the responses. CORS (alongside the older same-origin policy it extends) exists specifically to stop that.
It’s worth internalizing: CORS protects the person visiting the API-calling site, not the API itself. A server that skips CORS headers entirely isn’t "insecure" in the way an open database would be — it’s just not opted in to being called from arbitrary browser JavaScript, which is a deliberate default, not an oversight.
Why it works from Postman/curl but not the browser
CORS is enforced by browsers specifically, not by HTTP as a protocol. A command-line tool like curl, a desktop app like Postman, or a server calling another server all bypass it entirely — there’s no browser involved to enforce the rule. That’s the single most common reason "it works everywhere except my frontend" reports happen: everywhere else was never subject to the restriction in the first place.
If you control the API
This is the real fix: add CORS headers on the server. In most frameworks this is a one-line middleware — Express’s cors package, Django’s django-cors-headers, Spring’s @CrossOrigin, and equivalents in every major framework. Set the allowed origin to your actual frontend domain (or a specific allowlist) rather than a wildcard if the request also sends credentials like cookies — browsers reject the combination of Access-Control-Allow-Origin: * with credentialed requests specifically.
If you don’t control the API
If the API is a third party that hasn’t opted in to browser CORS for your origin, there’s no client-side trick that changes that — CORS isn’t a client capability gap, it’s enforced by the browser regardless of what JavaScript tries. The real options are: check if the provider has a CORS-enabled endpoint or offers one on request, route the call through your own backend so the browser is only ever talking to your own origin, or — for quick testing only — route through a CORS proxy that fetches the response server-side and adds the header for you.
A CORS proxy is a genuine convenience for testing, but it’s a real trade-off: the proxy operator sees everything in that request, including any auth headers or tokens. It’s fine for poking at a public API; it’s not something to route production traffic — or anything with real credentials — through by default.
Common CORS mistakes to check for
A handful of specific misconfigurations account for most "I added CORS headers and it still doesn’t work" reports.
- Access-Control-Allow-Origin: * combined with credentials (cookies, Authorization headers with credentials: "include") — browsers reject this combination outright.
- Headers added to the actual response but not to the OPTIONS preflight response — browsers check the preflight response’s headers before ever sending the real request for non-simple requests.
- A typo or trailing slash mismatch between the allowed origin and the actual origin — these are checked as exact strings, not patterns, unless the server explicitly handles wildcards.
- CORS headers added to the wrong layer — a CDN, load balancer, or reverse proxy in front of the API can strip or override headers the application itself sends.
FAQ
Is a CORS error a security vulnerability?
No — it’s the opposite. CORS blocking your request means the security feature is working as designed. A vulnerability would be an API that should restrict cross-origin access but doesn’t (or does so incorrectly, like allowing * with credentials); a CORS error itself is just the browser refusing to hand your JavaScript a response it wasn’t authorized to read.
Can I just disable CORS in my browser?
Browser flags and extensions that disable CORS exist, but they only affect your own browser during testing — they don’t change how the API behaves for anyone else, including your users in production. Relying on one is a sign the API itself still needs a real fix before anything depending on it can ship.
Does adding a CORS proxy "fix" CORS?
It works around it for testing, but it doesn’t fix the underlying cause — the API still isn’t opted in to browser access from your origin. A proxy fetches the response on a server (where CORS doesn’t apply) and re-serves it with the right header added. That’s fine for checking whether an endpoint works; it’s not a substitute for the API actually adding CORS support if you need this to work reliably in production.
Why does my request fail with no error details, just "CORS error"?
This is a deliberate browser limitation, not a missing detail — for security reasons, browsers don’t expose why a cross-origin response was blocked (which header was missing, what the actual response was) to your JavaScript. To see what actually happened, check the Network tab in your browser’s DevTools, which shows the real response and headers even though your code can’t access them.
See this handled for you, automatically.
Try the free API Request Builder