GuidesHEADERS
Access-Control-Allow-Origin
The Access-Control-Allow-Origin response header tells the browser which requesting origin may read the response body. Browsers enforce it so scripts on one origin cannot read data from another without permission. When the header is missing or does not match, client-side code cannot inspect the response at all.
What the header does
Access-Control-Allow-Origin is an HTTP response header that indicates whether a response can be shared with requesting code from a given origin. When a browser runs a cross-origin fetch, it attaches an Origin request header carrying the scheme, host, and port of the calling page.
After the server responds, the browser inspects the Access-Control-Allow-Origin value before exposing anything to JavaScript. If the value authorizes the calling origin, the browser releases the response body. If the header is missing or does not match the page origin, the browser withholds the response and the fetch rejects.
Syntax
The header carries exactly one value: a single origin, the wildcard character, or the literal string null.
# Any origin may read the response (requests without credentials only)
Access-Control-Allow-Origin: *
# Exactly one origin: scheme, host, optional port. No path, no trailing slash
Access-Control-Allow-Origin: https://app.example.com
# The opaque origin of file: and data: pages and sandboxed iframes. Avoid it
Access-Control-Allow-Origin: null- The wildcard
*permits requesting code from any origin to read the response, but only on requests without credentials such as cookies or HTTP authentication. - A single origin value names one exact scheme, host, and optional port, such as
https://app.example.com. - The
nullvalue grants access to documents with an opaque origin, such as pages onfile:ordata:URLs and sandboxed iframes.
How the browser evaluates it
On every cross-origin request, the browser compares the Access-Control-Allow-Origin response value against the Origin header it sent. The rules are strict.
- The comparison is an exact match on scheme, host, and port.
- A response declaring
https://example.comdoes not match requests fromhttps://www.example.com,http://example.com, orhttps://example.com:8443. - Paths, trailing slashes, and wildcards inside the origin value are invalid and always fail the comparison.
- If the header is missing entirely, the browser withholds the response body from the script.
- When the check fails,
fetch()rejects with aTypeErrorand the console logs a CORS error, even when the server returned a 200 status.
Wildcard versus explicit origin
The choice between an asterisk wildcard and an explicit origin comes down to one question: does the request carry credentials?
- The wildcard
*lets any client origin read the data, which suits unauthenticated public APIs and static assets. - On a credentialed request the browser rejects a wildcard response outright, no matter what else the headers say.
- Credentialed requests need the explicit origin echoed back, plus Access-Control-Allow-Credentials set to
true. - Public content that tracks no user state can use the wildcard safely and skip origin bookkeeping entirely.
The null origin
Browsers assign the opaque origin null to requests from file: URLs, data: URLs, and iframes sandboxed without allow-same-origin. Such a page sends Origin: null on its requests.
Responding with Access-Control-Allow-Origin: null grants those documents access, and doing so is unsafe on a public API.
- Any hostile page can build a sandboxed iframe whose
Originserializes tonull. - Because any site can produce a
nullorigin, granting it exposes the resource to arbitrary pages across the internet. - For local development against
file:pages, run a local server instead of opening the API tonull.
Why multiple origins in one header fail
The specification does not allow comma-separated origins in Access-Control-Allow-Origin. The browser reads the whole value as one origin string, and no real request origin ever equals it.
# Invalid: read as one origin string, so no request origin ever equals it
Access-Control-Allow-Origin: https://app.example.com, https://admin.example.com
# Invalid: wildcard subdomains are not header syntax
Access-Control-Allow-Origin: https://*.example.com
# Invalid: an origin has no path and no trailing slash
Access-Control-Allow-Origin: https://app.example.com/To serve more than one origin, the server reads the incoming Origin header, checks it against an allowlist, and echoes that single origin back.
const allowedOrigins = new Set([
'https://app.example.com',
'https://admin.example.com',
]);
function corsHeaders(requestOrigin: string | undefined) {
if (requestOrigin && allowedOrigins.has(requestOrigin)) {
return {
'Access-Control-Allow-Origin': requestOrigin,
Vary: 'Origin',
};
}
return {}; // no grant for origins outside the allowlist
}Whenever the echoed value changes per request, the response must also carry Vary: Origin, or shared caches can serve one origin's grant to a different origin's client. The full pattern is covered in the guide on allowing multiple origins.
Common server patterns
Most implementations settle on one of three approaches.
- Return a static
Access-Control-Allow-Origin: *for public, unauthenticated APIs and media assets. - Return one hardcoded origin, such as
https://app.example.com, when the API serves a single known client. - Validate the incoming
Originagainst an allowlist, echo the match, and sendVary: Originfor multi-app or multi-environment deployments.
Errors this header resolves
A missing or mismatched Access-Control-Allow-Origin value is behind the most common CORS console errors.
- Resolves Chrome's "No 'Access-Control-Allow-Origin' header is present on the requested resource" error.
- Resolves Firefox's CORS Missing Allow Origin error when the endpoint declares no origin permission at all.
- On preflighted requests, the same check runs on the preflight response, so a missing header there also trips the errors in the preflight guide.
- For the full diagnosis flow from symptom to fix, see the guide to fixing CORS errors.
Good questions.
Can I send a comma-separated list of allowed origins?
No. The header accepts a single origin, the wildcard *, or null. A comma-separated value is parsed as one malformed origin string and fails every comparison.
Does the header support wildcard subdomains like https://*.example.com?
No. Wildcard subdomains are not valid header syntax. The server must match the incoming Origin against an allowlist and echo the exact origin that matched.
Why does a trailing slash break the origin?
An origin is exactly scheme, host, and optional port. A trailing slash adds a path component, the value stops being a serialized origin, and the exact match against the request Origin fails.
Is Access-Control-Allow-Origin: null secure?
No. Any malicious site can produce a null origin through a sandboxed iframe, so granting null opens the resource to arbitrary hostile pages.