Access-Control-Allow-Origin

Cross-origin requests fail by default in browsers. The Access-Control-Allow-Origin response header tells browsers which origins are permitted to read a response, serving as the cornerstone of the CORS protocol.

Usage

Note

CORS (Cross-Origin Resource Sharing) is a browser mechanism that blocks web pages from reading responses served by a different origin unless the server explicitly permits access. Browsers set the Origin header automatically on cross-origin requests. JavaScript cannot modify the Origin header.

Every CORS response includes Access-Control-Allow-Origin to tell the browser whether front-end code from a specific origin is allowed to read the response. Without a matching value, the browser blocks the response from reaching JavaScript.

Servers choosing to allow access have three options: a wildcard, an explicit origin, or null. Most production APIs dynamically select the origin by comparing the incoming Origin request header against an allowlist. When the origin matches, the server echoes the value back. Because the response changes depending on the request, a Vary: Origin header is required so caches store separate copies for each origin.

What triggers CORS

Any fetch() or XMLHttpRequest to a different origin triggers CORS enforcement. Font loading through @font-face, WebGL textures, and canvas.drawImage() from cross-origin images also trigger CORS checks. Requests carrying custom headers, non-simple methods like PUT, DELETE, or PATCH, or an application/json Content-Type trigger a preflight OPTIONS request before the actual request is sent. Standard navigation such as clicking links or loading pages in the browser does not trigger CORS.

Values

* (wildcard)

Permits any origin to read the response. The wildcard is only valid for requests without credentials.

Access-Control-Allow-Origin: *

Note

The wildcard is incompatible with credentialed requests. When Access-Control-Allow-Credentials is true, the server must return an explicit origin.

Explicit origin

A single origin value consisting of a scheme, hostname, and optional port. This is the standard approach for APIs restricted to known callers.

Access-Control-Allow-Origin: https://app.example.re

Only one origin is allowed per response. Servers supporting multiple origins inspect the Origin request header and reply with the matched value, adding Vary: Origin to the response.

null

Represents an opaque or privacy-sensitive origin. Some sandboxed documents and local file URLs send null as their origin.

Access-Control-Allow-Origin: null

Note

Responding with null is discouraged. Malicious documents from sandboxed iframes also carry a null origin, making this value easy to forge.

Example

A server dynamically mirrors the requesting origin and includes a Vary header for correct cache behavior.

Access-Control-Allow-Origin: https://app.example.re
Vary: Origin

A public CDN serving static assets to any caller uses the wildcard.

Access-Control-Allow-Origin: *

A credentialed cross-origin response pairs the explicit origin with the credentials header.

Access-Control-Allow-Origin: https://dashboard.example.re
Access-Control-Allow-Credentials: true
Vary: Origin

Troubleshooting

Cross-origin requests fail when the browser cannot match the response origin to the requesting page.

  1. Console shows "No 'Access-Control-Allow-Origin' header is present on the requested resource." The server did not include the header at all. Verify the server-side CORS configuration applies to the specific route and HTTP method. In nginx, confirm the add_header directive sits inside the correct location block. In Apache, confirm Header set is inside the matching <Directory> or <Location>. Test with curl to isolate the issue from browser behavior: curl -v -H "Origin: https://app.example.re" https://api.example.re/data

  2. Wildcard * not working with credentialed requests. Browsers reject responses that pair Access-Control-Allow-Origin: * with Access-Control-Allow-Credentials: true. The fix is to read the incoming Origin header, validate the value against an allowlist, and echo the matched origin back. Add Vary: Origin to the response so caches store separate copies per origin.

  3. Origin reflection without validation. Echoing the Origin request header verbatim without checking an allowlist opens the API to any domain. Attackers exploit this to steal data through a page they control. Always compare the incoming origin against a list of trusted values before reflecting.

  4. CDN caching a response with the wrong origin. When the server returns a dynamic origin value but omits Vary: Origin, a CDN stores the first origin value and serves the same cached response to every subsequent origin. Add Vary: Origin on every response that reflects a dynamic origin. In Cloudflare, this is handled automatically when using the CORS managed transform. In other CDNs, confirm the origin is part of the cache key.

  5. Preflight succeeds but the actual request fails. The OPTIONS response includes the CORS headers, but the follow-up GET, POST, or PUT response does not. Many server frameworks handle OPTIONS separately from other methods. Ensure the CORS headers are added to all response types, not only to preflight responses. In Express, place the CORS middleware before route handlers so every response passes through the middleware.

  6. Debugging with curl shows correct headers but the browser still blocks. Open DevTools, go to the Network tab, and inspect the actual response headers the browser received. Proxies, load balancers, or CDN edge rules sometimes strip or overwrite CORS headers between the origin server and the browser. Compare the curl output against the DevTools output to find the layer removing the header.

See also

Last updated: April 4, 2026