Introduction
It is 4:47 PM on a Thursday. You are one feature away from finishing your sprint.
You wire up a fetch() call to the new API endpoint, flip to the browser, and
there it is:
Access to fetch at 'https://api.example.com/v1/users' from origin
'http://localhost:3000' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the requested resource.
Your stomach drops for exactly half a second before muscle memory takes over. You open a new tab. You type "cors error fix" into the search bar. You click the first Stack Overflow result. You copy a header. You paste it into your server config. The error goes away. You ship it. You go home.
You have just done the software engineering equivalent of silencing a smoke detector by removing the batteries.
This works, of course. It works the way leaving your front door unlocked "works"
when you keep losing your keys. The problem is not that you got the error to stop
appearing. The problem is that you have no idea why it appeared, what you just
changed, or what you just exposed. And next Thursday, when a slightly different
CORS error shows up — one involving preflights, or credentials, or an OPTIONS
request that your server doesn't handle — you'll be right back on Stack Overflow,
copying a different snippet from a different answer, hoping this one sticks too.
This book exists to break that cycle.
What This Book Is About
This is a book about Cross-Origin Resource Sharing. Not "how to make the red error go away," though you will certainly learn that. This is a book about understanding the mechanism — what it does, why it exists, how each piece fits together, and what you are actually saying to the browser when you set a CORS header.
Here is the single most important thing you will learn, and you are going to learn it right now, for free, in the introduction: CORS is not the thing blocking your request. The Same-Origin Policy is the thing blocking your request. CORS is the mechanism that allows cross-origin requests to happen despite the Same-Origin Policy. CORS is the escape hatch. CORS is your friend.
Read that again if you need to.
Every time you curse at a "CORS error," you are blaming the fire exit for the fire. The browser's default behavior is to block cross-origin requests. That is the Same-Origin Policy, and it has been protecting users on the web since the late 1990s. CORS is the standardized way for a server to say, "No, it's fine, let this one through." The error you see in your console is the browser telling you that the server hasn't said that yet. The fix is not to fight the browser. The fix is to understand what the server needs to communicate and then communicate it correctly.
That distinction — between the policy that blocks and the mechanism that permits — is the foundation everything else in this book rests on.
Why Understanding Matters
You can get through a surprising amount of your career by copy-pasting CORS headers. Plenty of people do. But eventually, one of these things will happen:
-
You will set
Access-Control-Allow-Origin: *on an endpoint that uses cookies, and it will silently fail. You will spend two hours debugging before discovering that the wildcard origin is not allowed when credentials are involved. -
You will add the right
Access-Control-Allow-Originheader but forgetAccess-Control-Allow-Headers, and yourContent-Type: application/jsonrequest will trigger a preflight that returns a 405 because your server does not handleOPTIONS. -
A penetration tester will flag your API for reflecting the
Originheader directly intoAccess-Control-Allow-Originwithout validation, and you will not understand why that matters. -
You will configure CORS on your Express server, put Nginx in front of it, and watch in horror as Nginx strips the headers your application carefully set.
-
You will need to explain to a junior developer why their localhost is being "blocked" and what to do about it, and "just add this header" will not be a sufficient answer.
When any of these happen — and they will — the cost of not understanding CORS stops being theoretical. You need a mental model, not a cheat sheet.
What You Will Learn
This book is structured in five parts, each building on the last.
Part I: The Problem CORS Solves starts at the beginning. Before you can
understand CORS, you need to understand what it is responding to. We will cover
the Same-Origin Policy — what it is, why browsers enforce it, and what counts
as an "origin" in the first place. If you have ever been confused about why
http://localhost:3000 and http://localhost:8080 are considered different
origins, this is where that gets cleared up. We will also walk through the
historical attacks that made the Same-Origin Policy necessary, because
understanding the threat model makes the restrictions feel a lot less arbitrary.
Part II: How CORS Actually Works is the mechanical core of the book. This is
where we crack open the protocol and examine every moving part. You will learn
the difference between simple requests and preflighted requests, and why that
distinction exists. You will understand the OPTIONS dance — what the browser
sends, what the server must respond with, and what happens when any piece is
missing. Every CORS header will be explained: what it does, when it is required,
what values it accepts, and what happens when you get it wrong. We will cover
credentials — cookies, authorization headers, TLS client certificates — and
the special rules that apply when they are involved. And we will look at how to
cache preflight responses so you are not paying the latency cost of an extra
round trip on every request.
Part III: CORS in the Wild takes the theory and applies it to the situations you actually encounter. How does CORS interact with the Fetch API versus the older XMLHttpRequest? What about WebSockets — do they even use CORS? (The answer may surprise you.) What are the special rules for fonts and static assets? How does CORS work — or fail to work — in single-page applications? And what happens when you introduce an API gateway or reverse proxy between your client and your server?
Part IV: Server-Side Configuration is the practical section. This is where you learn how to actually configure CORS on real servers. We will cover Express and Node.js, Go, Rust, Python, Nginx, Apache, serverless functions, and edge workers. The goal is not just to give you config snippets to copy — though you will get those too — but to make sure you understand what each line of configuration is doing, so you can adapt it when your situation does not match the example.
Part V: Debugging and Security ties everything together. You will learn how
to read CORS errors like a human — how to look at the browser's console output
and the network tab and immediately identify what is wrong. We will catalog
the most common mistakes and their fixes. We will discuss CORS as a security
boundary: what it protects against, what it does not protect against, and how
it fits into a broader security posture. And yes, we will talk about when
Access-Control-Allow-Origin: * is actually fine — because sometimes it is,
and knowing when is just as important as knowing when it is not.
Who This Book Is For
Frontend developers who have encountered CORS errors and want to stop
treating them as inscrutable acts of browser hostility. If you have ever stared
at a fetch() call that works perfectly in Postman but fails in the browser,
and you want to understand why those two things behave differently, this book
is for you.
Backend developers who have been asked to "add CORS headers" and want to know what they are actually adding, what the security implications are, and how to get it right without opening a hole they did not intend to open.
Full-stack developers who want one coherent mental model that spans both sides of the request, instead of two sets of half-understood fixes stitched together with hope.
DevOps and platform engineers who configure reverse proxies, API gateways,
CDNs, and load balancers, and need to understand how CORS headers interact with
these layers — because nothing ruins your afternoon quite like Nginx silently
eating the Access-Control-Allow-Origin header your application set.
Tech leads and senior engineers who are tired of reviewing pull requests
that "fix CORS" by adding Access-Control-Allow-Origin: * to every endpoint,
and who want a resource they can point their team to instead of explaining the
same thing for the fifteenth time. (Hello. I see you. This book is especially
for you.)
You do not need to be a security expert. You do not need to have read any RFCs. You should have some basic familiarity with HTTP — requests, responses, headers, status codes — and with how web browsers interact with servers. If you have ever opened your browser's developer tools and looked at the Network tab, you know enough to start.
What This Book Is Not
This is not a book about web security in general. CORS is one piece of the browser security model, and we will be thorough about that piece, but we are not going to cover Content Security Policy, CSRF tokens, XSS prevention, or any of the other topics that belong in a broader security book. Where those topics intersect with CORS — and they do — we will point it out, but we will not go down those rabbit holes.
This is also not a cookbook. You will find configuration examples and code snippets throughout, but the point of every example is to illustrate a concept. If you are looking for a file you can copy into your project without reading anything, you have the wrong book. (You also have the wrong approach, but that is a conversation for another time.)
How to Read This Book
If you are new to CORS, read it front to back. Each chapter builds on the ones before it, and the early chapters establish vocabulary and concepts that the later chapters assume you know.
If you already have a working understanding and you are here to fill in gaps, skip to the parts that interest you. The chapter titles are descriptive enough that you should be able to find what you need. But if you find yourself confused by something in a later chapter, resist the urge to google it — the answer is almost certainly in an earlier chapter.
If you are in the middle of a production incident and you need to fix a CORS error right now, go directly to Chapter 19, "Reading CORS Errors Like a Human," and Chapter 20, "Common Mistakes and How to Fix Them." Fix your immediate problem. Then come back and read the rest, so the next incident is one you prevent rather than one you react to.
A Note on the Examples
The code examples in this book use a variety of languages and frameworks. On the client side, you will see JavaScript using the Fetch API. On the server side, you will see Node.js with Express, Go, Rust, Python, Nginx config files, and more. The HTTP exchanges are shown as raw request/response pairs whenever possible, because CORS is an HTTP-level protocol and understanding the actual headers being exchanged matters more than understanding any particular library's API for setting them.
When a concept applies universally, the examples use raw HTTP. When implementation details matter, the examples use real code. In all cases, the examples are minimal — just enough to illustrate the point, and no more.
Let's get started.