GuidesHEADERS
The complete list of CORS headers
CORS runs on a fixed set of HTTP headers: the browser sets a few request headers, and the server answers with response headers that grant or withhold access. This list of CORS headers covers both sides, the fetch metadata headers that ride along, and which header resolves which console error.
Request headers the browser sets
The browser generates these headers automatically when a page issues a cross-origin fetch or XMLHttpRequest. Servers read them to decide whether to permit the request.
| Header | Sent on | Purpose |
|---|---|---|
| Origin | CORS requests and preflights | The requesting origin: scheme, host, and port, or null |
| Access-Control-Request-Method | Preflight requests | The HTTP method the actual request will use |
| Access-Control-Request-Headers | Preflight requests | Sorted, lowercase list of the non-safelisted headers the actual request will send |
| Sec-Fetch-Mode | Most requests | The request mode: cors, no-cors, navigate, same-origin, or websocket |
| Sec-Fetch-Site | Most requests | How initiator and target relate: cross-site, same-site, same-origin, or none |
| Sec-Fetch-Dest | Most requests | Where the response will be used; fetch and XHR send the empty value |
| Sec-Fetch-User | User-initiated navigations | Always ?1; omitted when there was no user activation |
Origin, Access-Control-Request-Method, Access-Control-Request-Headers, and the Sec-Fetch-* headers are forbidden request headers: the browser sets them and JavaScript cannot override them.
Response headers the server answers with
The server communicates permission by adding these headers to its responses. They decide whether the browser exposes the response body, and whether an actual request may follow a preflight.
| Header | Appears on | Purpose |
|---|---|---|
| Access-Control-Allow-Origin | Preflight and actual responses | The one origin allowed to read the response, or * without credentials |
| Access-Control-Allow-Credentials | Preflight and actual responses | Only valid value is true; permits credentialed requests when the client opts in |
| Access-Control-Allow-Methods | Preflight responses | Methods allowed for the actual request; GET, HEAD, POST always allowed |
| Access-Control-Allow-Headers | Preflight responses | Request headers allowed in the actual request; matching is case-insensitive |
| Access-Control-Max-Age | Preflight responses | Seconds the browser may cache the preflight; default 5, capped at 7200 in Chromium and 86400 in Firefox |
| Access-Control-Expose-Headers | Actual responses | Extra response headers scripts may read beyond the safelisted set |
| Timing-Allow-Origin | Actual responses (adjacent standard) | Origins allowed to see detailed Resource Timing data; takes a list or * |
- Read the Access-Control-Allow-Origin guide for exact-match rules, wildcards, and the null origin.
- Read the Access-Control-Allow-Credentials guide for cookies, client opt-in flags, and wildcard incompatibilities.
- Read the Access-Control-Allow-Headers guide for custom headers, safelists, and the Authorization wildcard trap.
- Read the Access-Control-Allow-Methods guide for preflighted verbs like PUT, PATCH, and DELETE.
The full exchange in one view
A cross-origin request with non-safelisted methods or headers runs in two phases: an OPTIONS preflight, then the actual request. Each header above appears at a fixed position in that exchange.
> OPTIONS /reports HTTP/2
> origin: https://app.example.com
> access-control-request-method: PUT
> access-control-request-headers: content-type, x-api-key
> sec-fetch-mode: cors
> sec-fetch-site: cross-site
< HTTP/2 204
< access-control-allow-origin: https://app.example.com
< access-control-allow-methods: PUT
< access-control-allow-headers: Content-Type, X-Api-Key
< access-control-max-age: 7200
< vary: Origin
> PUT /reports HTTP/2
> origin: https://app.example.com
> content-type: application/json
> x-api-key: demo-key
< HTTP/2 200
< access-control-allow-origin: https://app.example.com
< access-control-expose-headers: X-Request-Id
< vary: OriginWhich header fixes which error
Browser consoles name the failing header directly. Match the error to the header, then check the response it belongs on.
| Console error | Header to fix |
|---|---|
| No 'Access-Control-Allow-Origin' header is present on the requested resource | Access-Control-Allow-Origin on the actual response |
| Response to preflight request doesn't pass access control check | Allow-Origin, Allow-Methods, or Allow-Headers on the preflight response |
| Method PUT is not allowed by Access-Control-Allow-Methods in preflight response | Access-Control-Allow-Methods |
| Request header field X-Api-Key is not allowed by Access-Control-Allow-Headers | Access-Control-Allow-Headers |
| The value of the 'Access-Control-Allow-Origin' header must not be the wildcard '*' | Echo the explicit origin and add Access-Control-Allow-Credentials: true |
- Follow the diagnosis guide to work from symptom to server fix.
- Follow the preflight guide when the failing request is the OPTIONS itself.
Defaults and safelists worth memorizing
The browser defaults explain why some requests skip the preflight entirely and why some responses are readable without any extra headers.
- CORS-safelisted methods are
GET,HEAD, andPOST, always allowed without preflight negotiation. - CORS-safelisted request headers are
Accept,Accept-Language,Content-Language,Content-Typelimited toapplication/x-www-form-urlencoded,multipart/form-data, andtext/plain, andRangewith a single range value. - CORS-safelisted response headers exposed to scripts by default are
Cache-Control,Content-Language,Content-Length,Content-Type,Expires,Last-Modified, andPragma. - The default preflight cache is 5 seconds; browsers cap
Access-Control-Max-Ageat 7200 seconds in Chromium and 86400 seconds in Firefox.
Good questions.
Can JavaScript set or change the Origin header?
No. Origin is a forbidden request header controlled by the browser; fetch and XMLHttpRequest cannot set or override it.
Which CORS headers come from the browser and which from the server?
The browser sets Origin, Access-Control-Request-Method, Access-Control-Request-Headers, and the Sec-Fetch-* headers on requests. The server returns the Access-Control-Allow-* family, Access-Control-Max-Age, and Access-Control-Expose-Headers on responses.
What are the limits on preflight caching?
The default is 5 seconds when Access-Control-Max-Age is omitted. Chromium caps the value at 7200 seconds (2 hours) and Firefox at 86400 seconds (24 hours).
How do I check which headers an endpoint returns?
Run the URL through the CORS header checker and inspect the preflight and actual response headers directly.