28. CORS in depth: same-origin policy, preflight, credentials
The same-origin policy is the browser's foundational security boundary:
scripts from https://a.example.com cannot read responses from
https://b.example.com unless b.example.com explicitly opts in via CORS
headers. "Origin" is the exact triple (scheme, host, port) — http:// vs
https://, or a different port, is a different origin even on the same
domain.
// From https://app.example.com, this request goes out on the wire regardless —
// CORS does NOT stop the request from being SENT. It stops the BROWSER from
// letting your JS READ the response, unless the server says it's allowed to.
fetch("https://api.other.com/data");
The server must respond with Access-Control-Allow-Origin: https://app.example.com
(or * for fully public APIs) or the browser blocks JS from reading the
response — the response bytes did arrive over the network; CORS is enforced
by the browser, not the server or the network, which is why CORS errors
are invisible to tools like curl.
A preflight request (OPTIONS) is sent automatically by the browser
before certain requests — non-"simple" methods (PUT, DELETE, PATCH),
or custom headers like Authorization — to ask the server's permission
before sending the real request with credentials or a non-trivial body:
Browser preflight (automatic, you never write this):
OPTIONS /api/users/42
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: authorization
Server must respond:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: DELETE
Access-Control-Allow-Headers: authorization
Only THEN does the browser send the actual DELETE request.
Sending cookies cross-origin requires both sides to opt in explicitly — a common source of "my auth cookie isn't being sent" bugs:
fetch("https://api.example.com/me", { credentials: "include" });
// AND the server must respond with:
// Access-Control-Allow-Credentials: true
// Access-Control-Allow-Origin: https://app.example.com (NOT "*" — wildcard is
// forbidden together with credentials)