CORS — Cross-Origin Resource Sharing
CORS is one of the most commonly misunderstood parts of web development — not because it's conceptually difficult, but because the error message it produces in the console rarely explains what's actually wrong. This chapter covers the underlying policy CORS exists to relax, what a "preflight" request actually is, and how to read a real CORS error well enough to fix it directly rather than guessing.
The Same-Origin Policy — What CORS Exists to Relax
Browsers enforce a default security rule called the Same-Origin Policy: JavaScript running on one origin cannot read the response of a request made to a different origin, unless that other origin explicitly allows it. An "origin" is the combination of scheme, host, and port — all three have to match exactly.
| URL | Compared to https://osztromok.com | Same origin? |
|---|---|---|
| https://osztromok.com/linux | Different path only | ✅ Same origin |
| http://osztromok.com | Different scheme (http vs https) | ❌ Different origin |
| https://blog.osztromok.com | Different host (subdomain) | ❌ Different origin |
| https://osztromok.com:8080 | Different port | ❌ Different origin |
osztromok.com and blog.osztromok.com are different origins as far as the Same-Origin Policy is concerned, even though they're clearly part of the same overall website. This is exactly why Chapter 2's Domain cookie attribute exists — it's one of the few mechanisms that deliberately bridges origins within the same site.
What CORS Actually Does
CORS is a set of HTTP headers that let a server explicitly opt in to allowing requests from other origins — without it, the Same-Origin Policy blocks the response from being readable by the requesting page's JavaScript, even if the request itself technically succeeded on the server's end.
Access-Control-Allow-Origin: https://osztromok.com
// Or, less restrictively (use with caution — see warning below):
Access-Control-Allow-Origin: *
Preflight Requests — The OPTIONS Request You Didn't Write
For anything beyond a simple GET/POST with standard headers, the browser sends an automatic OPTIONS request first — a "preflight" — asking the server's permission before sending the real request at all.
What triggers a preflight
- Non-GET/HEAD/POST methods — PUT, DELETE, PATCH always trigger a preflight.
- Custom headers — anything beyond the small set of "CORS-safelisted" headers (like a custom
AuthorizationorX-Custom-Header) triggers a preflight. - Content-Type other than the simple set —
application/json(extremely common for APIs) triggers a preflight;text/plaindoesn't.
Access-Control-Allow-Origin: https://osztromok.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Reading Real CORS Error Messages
Debugging a Real CORS Issue, Step by Step
- Check the Network tab first, not just the console error. Find the actual failed request, check if there's a preceding OPTIONS request, and look at its response headers directly.
- Confirm the request even reached the server successfully. A 404 or 500 response often shows up looking like a CORS error in the console, even though the real problem is unrelated to CORS at all.
- Match the origin exactly.
http://vshttps://, or a trailing slash difference, is enough to make an otherwise-correct Allow-Origin header not match.
Chapter 5 Quick Reference
- Same-Origin Policy — scheme + host + port must all match for two URLs to share an origin
- CORS — server-sent headers that explicitly opt in to cross-origin reads; enforced by the browser, not the server
- Preflight (OPTIONS) — automatic browser check before non-simple requests (custom methods/headers, JSON content-type)
- Access-Control-Allow-Origin/Methods/Headers — the core response headers a server needs for CORS to work
- Wildcard (*) + credentials don't mix — browsers block this combination deliberately, for good security reasons
- Debug via the Network tab — check for a preflight, confirm the request actually succeeded server-side, verify exact origin matching
- Next chapter: security headers from the browser's perspective — CSP, HSTS, X-Frame-Options