Cross-Origin Resource Sharing (CORS)

Cross-Origin Resource Sharing (CORS) is the server-controlled protocol that allows a browser to relax the Same-Origin Policy (SOP) when the response explicitly whitelists the calling origin. It can feel like a productivity killer during development, but CORS is simply the browser confirming that a remote API actually trusts your front-end before handing you sensitive data.


Mechanism: Simple vs. Preflight Requests

Browsers categorize cross-origin requests into two types so they can decide how much validation is required.

1. Simple Requests

A request qualifies as “simple” if it meets the W3C criteria: it uses GET, HEAD, or POST and only includes standard headers (Accept, Accept-Language, Content-Type with text/plain, multipart/form-data, or application/x-www-form-urlencoded). The browser sends these requests directly and then inspects the response headers to see if the origin was allowed.

2. Preflight Requests

If the request involves potentially sensitive operations—PUT, DELETE, custom headers, JSON bodies—the browser performs a preflight check. It sends an automatic OPTIONS request asking the server for permission before the actual call:

OPTIONS /api/resource
Origin: https://app.example.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: Authorization, X-Trace-Id
  • The Check: the browser asks, “May I send this method/headers from this origin?”
  • The Response: the server must reply with explicit Access-Control-Allow-* headers. If the origin or method isn’t whitelisted, the browser blocks the real request.

Essential HTTP Response Headers

A correct CORS implementation relies on specific headers in the server’s response:

  • Access-Control-Allow-Origin — Lists the origin(s) permitted to read the response.
  • Access-Control-Allow-Methods — Enumerates the HTTP methods allowed for that origin.
  • Access-Control-Allow-Headers — Indicates which custom headers the client may send.
  • Access-Control-Allow-Credentials — Boolean flag telling the browser whether cookies/Authorization headers may accompany the request.
  • Access-Control-Max-Age — Duration (in seconds) that the browser may cache the preflight approval, reducing round-trips.

Security Implications and Best Practices

Misconfigured CORS can open serious holes. Treat the headers as part of your security architecture:

  1. Avoid wildcard origins in production. Access-Control-Allow-Origin: * is fine for anonymous, public APIs. Authenticated or internal endpoints must list the exact origin they trust.
  2. Handle credentials carefully. When Access-Control-Allow-Credentials: true is present, the Allow-Origin header cannot be a wildcard; it must explicitly echo the calling origin.
  3. Minimize preflight latency. Use Access-Control-Max-Age so the browser can cache the preflight response and avoid extra OPTIONS requests.

Note

CORS is browser-side only. curl, Postman, Node servers, Lambda functions—all bypass SOP/CORS entirely. Protect sensitive APIs with real authentication and authorization (OAuth2, JWTs, mTLS, VPNs, IP allowlists).