Updated April 2026

CORS

CORS is a browser security mechanism that controls which cross-origin requests are allowed. Browsers block requests to different domains by default. CORS lets servers explicitly permit them by returning Access-Control-Allow-Origin and related headers.

What CORS is and why it exists

By default, browsers enforce the Same-Origin Policy — scripts on app.example.com cannot fetch data from api.other.com. This prevents malicious scripts from silently accessing APIs on your behalf.

CORS is the controlled exception. A server can declare which origins it trusts by returning the right headers. The browser checks those headers before allowing the response to reach your JavaScript.

The headers that make CORS work

HeaderDirectionWhat it does
Access-Control-Allow-OriginResponseWhich origin is allowed. Must match the request Origin exactly, or *
Access-Control-Allow-MethodsResponse (preflight)Which HTTP methods are allowed
Access-Control-Allow-HeadersResponse (preflight)Which request headers are allowed (Content-Type, Authorization, etc.)
Access-Control-Allow-CredentialsResponseWhether cookies and auth headers can be included
Access-Control-Max-AgeResponse (preflight)How long to cache preflight results (seconds)

Simple vs preflighted requests

Simple requests (GET, POST with text/plain or form data) go directly. The browser checks the response headers after.

Preflighted requests (POST with JSON, PUT, DELETE, custom headers) first send an OPTIONS request. The browser only sends the actual request if the preflight response has matching CORS headers.

Minimal working CORS — Nginx

# Handle preflight
if ($request_method = OPTIONS) { add_header Access-Control-Allow-Origin "https://app.example.com"; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; add_header Access-Control-Allow-Headers "Content-Type, Authorization"; add_header Access-Control-Max-Age 86400; return 204;
}
add_header Access-Control-Allow-Origin "https://app.example.com" always;

The wildcard trap

Using Access-Control-Allow-Origin: * is fine for public APIs with no authentication. Never combine it with Access-Control-Allow-Credentials: true — browsers reject this combination because it would let any origin access authenticated responses.

Test your live CORS config — CORSFixer →