Learn CORSErrorsTesterFrameworksQuizSearch

CORS Headers: Request Permission and Response Exposure

By Ankit Jain · Updated

Know which CORS headers belong on OPTIONS, the actual response, or the browser’s request, with concrete examples.

CORS has two different header conversations: the browser describes the request it wants to send, and the server returns permission. Adding Access-Control-Allow-Origin to fetch’s request headers does not grant response access.

Header reference

HeaderSent byPurpose
OriginBrowserIdentifies the requesting origin
Access-Control-Request-MethodBrowser on preflightNames the intended actual method
Access-Control-Request-HeadersBrowser on preflightNames non-safelisted request headers
Access-Control-Allow-OriginServerGrants response access to one origin or an appropriate wildcard
Access-Control-Allow-CredentialsServerGrants include-mode response access when exactly true
Access-Control-Allow-MethodsServer on preflightPermits actual methods
Access-Control-Allow-HeadersServer on preflightPermits request header names
Access-Control-Expose-HeadersServer on actual responseMakes additional response headers readable
Access-Control-Max-AgeServer on preflightAllows preflight permission caching
Vary: OriginServerTells HTTP caches that the response varies by Origin

Allow-Headers and Expose-Headers differ

Suppose the frontend sends Authorization and needs to read X-Request-ID. The preflight response permits the request header:

Access-Control-Allow-Headers: Authorization

The actual response exposes the response header:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Expose-Headers: X-Request-ID
X-Request-ID: example-123

JavaScript can then read response.headers.get(‘X-Request-ID’). Ordinary safelisted response headers, such as Content-Type, are already readable when CORS permission succeeds. Set-Cookie remains unavailable to JavaScript.

A consistent policy matters

Return exactly one valid Allow-Origin value. For approved dynamic origins, use an allowlist and Vary: Origin; never return a list of origins. With credentials: include, use an exact origin, Allow-Credentials: true, and explicit method/header permissions where needed. Authorization always needs an explicit header name.

Put CORS headers on error responses that JavaScript needs to read as well as successes. Check duplicate headers and CDN caching when the application appears right but the browser sees something else.

References