diagram.mmd — sequence
CORS Request Flow sequence diagram

Cross-Origin Resource Sharing (CORS) is a browser security mechanism that controls which cross-origin HTTP requests a web page is allowed to make. It enforces the same-origin policy by default and requires servers to explicitly opt in to cross-origin access via specific response headers.

The same-origin policy prevents a script on app.example.com from fetching data from api.other.com by default. CORS provides a controlled way for servers to relax this restriction. The mechanism exists entirely in the browser — the server still receives and processes the request, but the browser blocks JavaScript from reading the response unless the server sends the correct CORS headers.

For simple requests (GET or POST with certain content types), the browser sends the request directly and checks the Access-Control-Allow-Origin header in the response. If the response header allows the requesting origin, JavaScript can read the response. If not, the browser blocks access.

For non-simple (preflighted) requests — those using methods like PUT, DELETE, PATCH, or custom headers — the browser automatically sends an OPTIONS preflight request first. The preflight asks the server to confirm it accepts the actual method and headers from that origin. The server responds with Access-Control-Allow-Origin, Access-Control-Allow-Methods, and Access-Control-Allow-Headers. If approved, the browser sends the actual request.

CORS headers to configure correctly on your server: Access-Control-Allow-Origin (specific origin or * for public APIs), Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Allow-Credentials (must be true for cookie-based auth, and requires a specific origin, not *), and Access-Control-Max-Age (caches the preflight result to avoid repeated OPTIONS calls).

CORS is often confused with CSRF protection — see CSRF Protection Flow for how they differ and interact.

Free online editor
Edit this diagram in Graphlet
Fork, modify, and export to SVG or PNG. No sign-up required.
Open in Graphlet →

Frequently asked questions

CORS (Cross-Origin Resource Sharing) is a browser security mechanism that controls whether JavaScript on one origin can read responses from a different origin. Servers opt into cross-origin access by returning specific `Access-Control-*` response headers; without them, the browser silently blocks the response from JavaScript even if the server processed the request.
When a browser detects a non-simple cross-origin request (e.g., PUT, DELETE, or a request with custom headers), it first sends an `OPTIONS` preflight request to the server. The server responds with the allowed methods, headers, and origin. If approved, the browser proceeds with the actual request. The preflight result is cached for the duration set in `Access-Control-Max-Age`.
CORS is a browser enforcement mechanism that restricts which origins can read API responses — it does not prevent the server from receiving the request. CSRF protection prevents malicious cross-origin sites from submitting state-changing requests that the server would accept. CORS alone does not protect against CSRF for requests that do not require a preflight.
Reflecting the `Origin` header verbatim in `Access-Control-Allow-Origin` without validating against an allowlist grants any origin access. Setting `Access-Control-Allow-Origin: *` combined with `Access-Control-Allow-Credentials: true` is rejected by browsers but is a common misconfiguration attempt. Allowing broad wildcard methods or headers widens the attack surface unnecessarily.
mermaid
sequenceDiagram participant Browser participant Origin as Frontend Origin (app.example.com) participant API as API Server (api.other.com) note">Note over Browser: Preflight for non-simple request Browser->>API: OPTIONS /data HTTP/1.1\nOrigin: app.example.com\nAccess-Control-Request-Method: POST\nAccess-Control-Request-Headers: Content-Type, Authorization API-->>Browser: 200 OK\nAccess-Control-Allow-Origin: app.example.com\nAccess-Control-Allow-Methods: GET, POST, PUT\nAccess-Control-Allow-Headers: Content-Type, Authorization\nAccess-Control-Max-Age: 86400 note">Note over Browser: Preflight approved\nSend actual request Browser->>API: POST /data HTTP/1.1\nOrigin: app.example.com\nAuthorization: Bearer token\nContent-Type: application/json API-->>Browser: 200 OK\nAccess-Control-Allow-Origin: app.example.com\n{"result": "data"} note">Note over Browser: CORS check passed\nJavaScript can read response note">Note over Browser: Blocked cross-origin attempt Browser->>API: GET /private\nOrigin: attacker.com API-->>Browser: 200 OK\n(no CORS headers for attacker.com) note">Note over Browser: Browser blocks JS from\nreading response — CORS violation
Copied to clipboard