CORS (Cross-Origin Resource Sharing)
CORS controls whether browser JavaScript is permitted to read resources served by a different origin. It is enforced by browsers through HTTP response headers and is not a general server-to-server access-control mechanism.
An origin is the combination of scheme, host, and port. For example, `https://app.example.com` and `https://api.example.com` are different origins because their hosts differ, even though they share a parent domain. A browser applies the same-origin policy to restrict scripts from freely reading cross-origin responses.
CORS lets a server explicitly grant a browser permission to expose a cross-origin response to JavaScript. The server does this primarily with `Access-Control-Allow-Origin`, optionally together with headers controlling methods, request headers, credentials, and exposed response headers. The browser evaluates these headers; JavaScript does not directly disable or override the policy.
A simple cross-origin request may be sent without a preflight, but the browser still checks the response before exposing it to the requesting script. For requests that are not considered CORS-safelisted, the browser first sends an `OPTIONS` preflight describing the intended method and headers. The server must respond with appropriate CORS permissions before the browser proceeds with the actual request.
Credentials such as cookies change the rules. A credentialed CORS response cannot use `Access-Control-Allow-Origin: *`; the server must identify an allowed origin and also explicitly permit credentials with `Access-Control-Allow-Credentials: true`. Servers should validate allowed origins carefully rather than reflecting arbitrary `Origin` values.
CORS is primarily a browser security mechanism. A command-line client, backend service, or other non-browser HTTP client can generally send the same HTTP request without being stopped by CORS, although authentication and application-level authorization can still reject it.
Key points
- CORS governs browser access to cross-origin responses, not whether an HTTP request can exist.
- The browser compares origins using scheme, host, and port.
- Simple requests can be sent directly; some cross-origin requests require an `OPTIONS` preflight.
- `Access-Control-Allow-Origin` determines which origin may read the response.
- Credentialed CORS requires explicit credential permission and cannot use `*` for the allowed origin.
Interview questions
What is CORS, and why do browsers enforce it?
CORS stands for Cross-Origin Resource Sharing and governs whether browser JavaScript can read a response from another origin. Browsers enforce it as part of the web's same-origin security model. A server can grant cross-origin access by returning appropriate CORS headers. The browser interprets those headers and determines whether the response is exposed to the script.
What is a CORS preflight request?
A preflight is an `OPTIONS` request the browser sends before certain cross-origin requests. It asks the server whether the intended method and request headers are permitted. The server responds with CORS headers such as `Access-Control-Allow-Methods` and `Access-Control-Allow-Headers`. If the response does not authorize the request, the browser does not expose the subsequent response to the calling JavaScript.
Why can't `Access-Control-Allow-Origin: *` be used with credentials?
Credentialed CORS requests expose ambient credentials such as cookies to the cross-origin request. The server therefore has to explicitly identify the permitted origin rather than granting access to every origin. For credentialed CORS, the response uses a specific `Access-Control-Allow-Origin` value and `Access-Control-Allow-Credentials: true`. This prevents wildcard origin access from being combined with credentialed cross-origin reads.
A frontend gets a CORS error even though the API returns HTTP 200. What could be happening?
The HTTP request can reach the server and still fail the browser's CORS check. The response may be missing `Access-Control-Allow-Origin`, may specify the wrong origin, or may omit another required CORS permission. If the request was preflighted, the `OPTIONS` response could also be incorrect even when the eventual endpoint returns 200. I would inspect the browser network panel and compare both the request's `Origin` and the relevant response headers.
How would you design CORS for an API serving multiple frontend origins?
I would maintain an explicit allowlist of trusted origins and compare the incoming `Origin` against that list. For an allowed origin, the server can return that exact origin in `Access-Control-Allow-Origin`, rather than reflecting arbitrary input. If credentials are required, I would also return `Access-Control-Allow-Credentials: true` and avoid wildcard origins. I would ensure preflight handling permits only the necessary methods and headers and consider `Vary: Origin` when responses differ by origin.