Mental model

Everything about CORS rests on one word: origin. An origin is exactly a scheme, a host, and a port together — https://www.example.com and http://www.example.com are different origins (different scheme); so are https://a.example.com and https://b.example.com (different host); and so are two services on different ports of the same host. The path, query string, and trailing slash are not part of the origin — they describe where in an origin a request goes, not whose it is.

The browser's default rule is the Same-Origin Policy: a page loaded from one origin may not read the response to a request it makes to a different origin. Cross-Origin Resource Sharing is the browser's mechanism for relaxing that policy — a controlled opt-out, granted by the server through response headers, that lets specific other origins read specific responses. CORS is not a security feature of the server; it is a gate the browser keeps between a page and the page's JavaScript, to protect its own user from pages that would otherwise read your bank or webmail in the background using your logged-in session.

That last point has a corollary worth fixing firmly: the server is never protected by CORS. Tools like curl, Postman, server-to-server calls, and native apps are not browsers — they do not enforce the Same-Origin Policy and they ignore CORS headers entirely. So curl can read a response your page cannot, and that is not a bug in either of them: CORS only ever constrains browsers, and only to protect the user sitting in front of that browser. The rules are defined by the WHATWG Fetch standard; the notion of an origin itself comes from RFC 6454. There is no separate "CORS RFC", despite what the search results suggest.

Compare two origins

Type any two URLs below (or pick a preset) and the comparator breaks each into its scheme, host, and port, then tells you two things that are easy to conflate: whether the pair is the same origin (what CORS checks) and whether it is the same site (what cookies and SameSite check). These are different questions with different answers for the same pair.

Preset URL pairs

Enter two valid http:// or https:// URLs above to compare them — or pick a preset.

Same-origin vs cross-origin, side by side

The button below fires the identical request at two paths to the same backend — one that lives on this page's own origin (so it is same-origin), and one on the API's separate origin (so it is cross-origin). Same scenario, same server, same response contract; the only difference is which path each request took.

Press the button to fire the identical POST at both paths at once — one same-origin, one cross-origin — and watch them come back differently.

Origin vs site: two different boundaries

CORS is origin-scoped; cookies are site-scoped — and "site" is a coarser boundary than "origin". Two URLs are the same site when their hosts share a registrable domain: the pair https://a.example.com and https://b.example.com are different origins (different host) but the same site (both under example.com). A cookie set for example.com is sent to both, which is why cross-site request forgery is a concern CORS alone does not solve; but the browser still gates the read of a cross-origin response with CORS even when the two are same-site. This is exactly the split-domain team's situation — your frontend and API on different subdomains are same-site, yet still cross-origin, so CORS applies.

Subdomains being cross-origin is the point most people trip on first. a.example.com and b.example.com feel like "the same site" because they are — but they are not the same origin, and CORS compares origins. That is why your www. frontend talking to an api. subdomain is a cross-origin request that needs CORS headers, even though both live under one domain.

One caveat worth naming: this project's local development setup reproduces the API and OTHER-API analogs as different loopback hosts (localhost and 127.0.0.1) rather than real subdomains — different hosts, so technically different sites too, more foreign than the all-same-site topology the deployed site actually uses. It doesn't change anything about origin-scoped CORS, but the distinction matters for cookie-scope demos on a later page.

Watching in your browser's developer tools? Open the Network tab when you press "Run both requests": you'll see two POST entries to the demo endpoint. The same-origin one completes with a readable 200; the cross-origin one also gets a 200 from the server (open its response and look) but the browser marks it blocked and hands your code nothing. That gap — a full response received, then withheld from JavaScript — is the entire premise of the rest of this course.