The course
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.
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.