Skip to content

CORS

If your API is called from browser JavaScript on a different origin, you will meet CORS. It is one of the most misunderstood parts of web APIs, so let’s be precise about what it is and is not.

The browser’s same-origin policy blocks a page on https://app.example.com from reading a response from https://api.example.com unless the API explicitly opts in with Cross-Origin Resource Sharing headers. CORS is enforced by the browser, on behalf of the user — it is not a server-side access control.

For “non-simple” requests (most JSON POST/PUT/DELETE, custom headers), the browser first sends a preflight OPTIONS request asking permission:

sequenceDiagram
  participant B as Browser
  participant S as API
  B->>S: OPTIONS /articles (preflight)
  S-->>B: 204 + Access-Control-Allow-Origin/Methods/Headers
  B->>S: POST /articles (actual request)
  S-->>B: 201 Created + Access-Control-Allow-Origin
The browser checks permission with OPTIONS before the real request

The key response headers: Access-Control-Allow-Origin (which origins may read responses), -Allow-Methods, -Allow-Headers, and -Allow-Credentials (whether cookies/credentials are allowed).

JavaScript

Avoid the classic mistake of reflecting any origin (Access-Control-Allow-Origin: *) together with Allow-Credentials: true — the combination is forbidden and, more importantly, would expose authenticated responses to any site.

Who enforces CORS?
What is the preflight request?
Why is `Allow-Origin: *` with `Allow-Credentials: true` a problem?