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.
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_headerdirective sits inside the correctlocationblock. In Apache, confirmHeader setis 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/dataWildcard
*not working with credentialed requests. Browsers reject responses that pairAccess-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. AddVary: Originto the response so caches store separate copies per origin.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.
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. AddVary: Originon 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.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.
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
- Fetch Standard: HTTP Access-Control-Allow-Origin
- Origin
- Vary
- Access-Control-Allow-Credentials
- Access-Control-Allow-Methods
- CORS
- HTTP headers