The most misunderstood ten lines of the web platform. You've seen the red console error. You've pasted the Stack Overflow fix. This page makes you actually understand it — by letting you poke a simulated browser and server until it clicks.
§ 01 — First principles
An origin is the triple scheme + host + port. Nothing more, nothing less. The path doesn't matter. The query string doesn't matter. But a different subdomain, a different port, or http vs https — each one makes a completely different origin in the browser's eyes.
Type two URLs below (or hit a preset) and see how the browser compares them:
https://cors.in and https://cors.in:443 are the same origin — 443 is the default port for https, so browsers normalize it away. But https://cors.in:8443 is a stranger.
§ 02 — The rule CORS relaxes
Since the 1990s, browsers have enforced one big rule: JavaScript on one origin may not read responses from another origin. Why? Because your browser carries your cookies everywhere. Without this rule, any page you visit could quietly fetch() your webmail, your bank dashboard, your company intranet — with your session cookies attached — and read the results.
Here's the reframe that fixes most confusion: CORS is not a wall. CORS is a door in a wall that already existed. It's the mechanism a server uses to say "actually, browser, it's fine — let that other origin read my responses." Every CORS header you add makes the web less locked-down, not more.
<img src="other.site/pic.png"><script src>, <link><form action="other.site"><iframe> (it renders; you can't reach in)fetch() / XMLHttpRequest — reading the responsePOST /transfer-money — a CORS error in the console does not mean the transfer didn't happen.
§ 03 — The playground
You're JavaScript running on https://app.example.com. Configure the request on the left and the server on the right, then run it and watch what actually crosses the wire — including the invisible preflight OPTIONS request browsers send before "non-simple" requests.
This server answers preflights withAllow-Methods: GET, POST, PUT, DELETEAllow-Headers: Content-Type, X-API-Key
§ 04 — Case study
In 2019, Zoom's Mac client ran a hidden web server on http://localhost:19421 so that zoom.us could launch meetings without a click. To talk to it from the browser, Zoom needed CORS headers on that local server.
CORS felt like it was "in the way" — so instead of sending the headers, they bypassed it entirely: the page loaded images from the localhost server (image loads don't need CORS, remember §02), and the local server encoded its status into the pixel dimensions of the image. The page read img.width to learn the result.
Clever. Except CORS was never the thing in the way — it was the thing protecting users. Since the trick worked from zoom.us, it worked from every website on the internet. Any page you visited could command your Zoom client: join a meeting, camera on, no confirmation. It got worse — the same channel could trigger reinstalling Zoom after you'd deleted it.
And no, localhost is not exempt: browsers apply the same-origin policy to localhost like anywhere else. CORS wasn't broken here. CORS was the correct tool, deliberately routed around.
§ 05 — Pop quiz
True or false? Answer honestly — these come from real Stack Overflow answers with thousands of upvotes.
§ 06 — Take-home
Access-Control-Allow-Origin.Vary: Origin whenever the header depends on the request — or caches will serve one origin's permission to another.Access-Control-Allow-Credentials: true. The browser refuses * here — by design.OPTIONS preflights fast, and cache them with Access-Control-Max-Age.Access-Control-Allow-Origin: * on an authenticated API because a blog post said so.Origin header back with credentials enabled — that's * with extra steps, and worse.--disable-web-security. It "fixes" your app and disables the protection for every site in that browser.Keep reading: this page was inspired by Chris Foster's essay “Developers don't understand CORS” — the full Zoom write-up is worth your time. Then bookmark MDN's CORS reference for the day preflight caching bites you.