CORS Handbook
The complete guide to understanding and fixing CORS errors.
Built by headertest.com
A few months ago, I helped clean up a CORS mess on a small API running on Linode Akamai Compute. Nothing exotic: one frontend app, one backend API, both deployed fast, both working fine in local dev, and both breaking the minute a real browser got involved. That’s the pattern with CORS. Curl works. Postman works. Backend logs look healthy. Then the browser says no. This case study is for the setup I see all the time on Linode Akamai Compute: ...
CORS in Django REST Framework looks simple right up until your frontend starts throwing No 'Access-Control-Allow-Origin' header errors and every “quick fix” makes your API less safe. I’ve seen teams handle this in three common ways: disable CORS in development and forget about production slap Access-Control-Allow-Origin: * on everything actually configure it properly with environment-specific rules Only one of those scales without causing pain. The short version If you’re building a DRF API, your realistic CORS options are: ...
I’ve seen the same Cloud Run rollout go sideways more than once: the service works in curl, works in Postman, even works from server-side code — then the browser blocks it and everyone blames Google. Usually, Cloud Run is innocent. The app is returning the wrong CORS headers, returning them inconsistently, or forgetting that browsers send a completely separate preflight request before the “real” one. Here’s a real-world style case study based on a pattern I’ve had to fix in production. ...
CORS in a Flutter WebView trips people up because there are really two different worlds hiding behind one app: Flutter web, where your app runs in a browser and CORS rules fully apply. Flutter mobile with a WebView, where browser-like behavior exists, but native networking and embedded browser behavior can change the story. If you treat a WebView like “just Chrome inside Flutter,” you’ll misdiagnose bugs for hours. I’ve done that. The fix usually starts with one question: ...
CORS with GraphQL looks simple right up until the browser starts throwing vague errors and your API “works in curl” but fails in production. I’ve seen this a lot with Apollo Server because GraphQL teams tend to focus on schema design and resolvers, then treat HTTP as plumbing. Browsers do not care how elegant your schema is. If your CORS policy is wrong, the app breaks anyway. Here are the mistakes I see most often with Apollo Server, why they happen, and how to fix them without turning your API into Access-Control-Allow-Origin: * soup. ...
Internal dashboards are where bad CORS habits go to hide. I’ve seen teams lock down customer-facing APIs pretty well, then turn around and ship an admin panel that talks to five internal services with Access-Control-Allow-Origin: *, cookies flying around, and preflights failing randomly because nobody remembers which proxy strips which header. Internal tooling feels “safe” because it lives behind SSO, VPN, or a corporate network. That mindset causes sloppy CORS configs. Browsers don’t care that your app is “internal.” They still enforce the same rules, and attackers love soft targets with elevated access. ...
Cross-Origin-Embedder-Policy sounds abstract until it blows up a working app. I’ve seen this happen on teams that enabled Cross-Origin-Embedder-Policy: require-corp to unlock SharedArrayBuffer, improve isolation, or satisfy a performance-heavy feature using WebAssembly. Everything looked fine in local dev. Then production started blocking scripts, workers, fonts, and random third-party assets that had worked for years. The root problem usually isn’t COEP by itself. It’s that COEP forces you to be honest about cross-origin resource loading. And that means CORS suddenly matters for resources your app used to “just load.” ...
Tauri confuses people on CORS for one simple reason: it looks like a web app, but part of it behaves like a native app. That split changes what CORS does, where it applies, and how much protection you really get. If you build for the web first, your instinct is usually: “I’ll just fetch() the API from the frontend.” In Tauri, that can be correct, wrong, insecure, or just annoying depending on which runtime path you choose. ...
Retool makes it deceptively easy to wire up APIs fast. That’s great right up until the browser starts yelling about CORS and half the team decides “the API is broken.” Usually, the API is fine. The browser is doing exactly what it should do, and your Retool app is running into the same cross-origin rules as any other frontend. I’ve seen the same mistakes over and over with Retool setups: wrong origin assumptions, broken preflight handling, credentials mixed with wildcards, and APIs that technically work in Postman but fail instantly in the browser. Here’s the stuff that trips people up most often, and how I’d fix it. ...
WebTransport sits in an odd spot for people who already know CORS. You expect the usual fetch() rules, preflights, and response headers. Then you try WebTransport over HTTP/3 and realize the model is related to CORS, but not the same shape. Browsers still care about origin-based access control, but WebTransport uses its own handshake rules instead of classic OPTIONS preflight. If you build browser-facing infrastructure, this distinction matters. A lot. ...