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.

Three valid values, exactly one per response
# 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 null value grants access to documents with an opaque origin, such as pages on file: or data: 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.com does not match requests from https://www.example.com, http://example.com, or https://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 a TypeError and 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 Origin serializes to null.
  • Because any site can produce a null origin, 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 to null.

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.

Values that never match
# 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.

Allowlist and echo, in generic server logic
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 Origin against an allowlist, echo the match, and send Vary: Origin for 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.