What Is CORS? β Definition and How It Works
Learn what CORS is, why the same-origin policy exists, how preflight requests work, and why CORS errors are a browser rule rather than a server failure.
Cross-Origin Resource Sharing is the mechanism by which a server tells a browser that a page from another origin is allowed to read its responses. It relaxes a browser restriction; it is not a server-side security control.
1. Why the Restriction Exists
Browsers enforce the same-origin policy: a page may send requests to other origins, but by default it cannot read the responses. Origin means scheme, host, and port together.
Without it, any page you visited could read your logged-in email, banking, or intranet responses using your cookies. The policy is what keeps one site's credentials from being usable by another site's JavaScript.
2. What CORS Adds
CORS lets a server opt in to sharing. The browser sends an Origin header; the server answers with headers stating what is permitted.
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true
If the response lacks the matching permission, the browser blocks the page's access to it β the request may still have reached the server and had its effect.
3. Simple Versus Preflighted
| Request | Treatment |
|---|---|
| GET or POST with simple headers and a basic content type | Sent directly; response checked for permission |
Anything with a custom header, Authorization, JSON content type, or another method |
Preflighted first |
A preflight is an automatic OPTIONS request asking whether the real request is allowed. The server must answer it with the permitted methods and headers, and may set Access-Control-Max-Age so the browser caches the answer.
4. Credentials Change the Rules
To send cookies or authorisation headers cross-origin, the request must opt in and the server must return Access-Control-Allow-Credentials: true. In that mode the wildcard origin is forbidden β the server must name the exact origin.
This pairing is the source of a large share of CORS confusion: a configuration that works without credentials stops working the moment cookies are included.
5. Why the Error Is Confusing
A CORS failure appears in the browser console as a network-ish error, but the network request often succeeded. The browser simply refuses to hand the response to the page.
Consequences worth internalising:
- The server did the work and may have changed state. CORS does not prevent the request, only the reading of the reply.
- The same call from a server, a terminal, or a mobile app is unaffected, because the restriction is a browser policy.
- Fixing it means changing server response headers, not client code.
6. Common Misconceptions
- "CORS protects the API." It protects users of other websites. Authentication and authorisation protect the API.
- "A proxy fixes CORS." It bypasses it, because the browser is no longer talking cross-origin. That is a workaround, and it moves the trust question to the proxy.
- "
Allow-Origin: *is convenient and harmless." For public, unauthenticated data it is fine; combined with credentials it is forbidden precisely because it would be dangerous. - "It is a server error." It is a browser decision about a server response.
7. Real-World Examples
- A single-page app on one domain calling an API on another, which requires explicit allow headers.
- A local development front end on
localhost:3000calling a staging API, needing that origin allowed. - A public data API allowing all origins because nothing is credential-gated.
- A fetch from page JavaScript to a third-party site failing, while the identical request from a script on your own machine succeeds.
8. Summary
CORS is how a server grants browsers permission to expose its responses to pages from other origins, layered on top of the same-origin policy that otherwise forbids it.
The mental model that resolves most confusion: the request usually happens, the reading is what gets blocked, and the fix lives in the server's response headers.