CORS errors can stop an otherwise healthy integration in seconds, and the browser messages are often just vague enough to waste an afternoon. This hub explains what cross-origin requests are, how the browser decides whether to allow them, and how to map common CORS failures to practical fixes on the client, server, proxy, or deployment layer. Keep it bookmarked as a troubleshooting reference whenever a frontend app needs to talk to an API across origins.
Overview
If you have seen messages like Cross-Origin Request Blocked, No 'Access-Control-Allow-Origin' header, or Response to preflight request doesn't pass access control check, you are dealing with the browser's same-origin policy and the CORS rules layered on top of it.
CORS stands for Cross-Origin Resource Sharing. It is not a server-side security feature by itself and it is not a browser bug. It is a browser enforcement model that determines whether frontend JavaScript running on one origin is allowed to read a response from another origin.
An origin is defined by three parts together:
- Protocol, such as
httporhttps - Host, such as
app.example.com - Port, such as
3000or443
That means these are different origins:
http://localhost:3000andhttp://localhost:5173https://app.example.comandhttps://api.example.comhttp://example.comandhttps://example.com
The key point is simple: your API may be reachable, healthy, and returning a correct payload, but the browser can still block your frontend from reading it if the response headers do not satisfy CORS.
In practical terms, most CORS debugging comes down to answering four questions:
- What is the requesting origin?
- What request method and headers are being sent?
- Did the browser send a preflight
OPTIONSrequest first? - Did the API respond with the exact headers the browser expected?
It also helps to remember what CORS is not. CORS is not relevant to backend-to-backend requests made outside the browser. A Python service calling another API with requests does not run into browser CORS checks. CORS problems appear when browser JavaScript tries to access a different origin.
When your fetch logic itself needs review, pair this guide with Fetch API Error Handling Patterns You Can Reuse in Production. Many integrations have both request handling issues and CORS issues at the same time, and separating them quickly saves time.
Topic map
Use this section as the fast path. Start with the browser error, then move to the likely cause and fix.
1. Error: No Access-Control-Allow-Origin header is present
What it usually means: The API responded, but it did not include an Access-Control-Allow-Origin header matching the requesting origin.
Typical fixes:
- Configure the API to return
Access-Control-Allow-Origin: https://your-frontend.example - For local development, allow the exact dev origin like
http://localhost:3000 - If using a reverse proxy or CDN, confirm it is forwarding or preserving CORS headers
Watch for: * is not valid in every case, especially if credentials are involved.
2. Error: Response to preflight request doesn't pass access control check
What it usually means: The browser sent an OPTIONS request before the real request, and the preflight response was missing required headers or returned the wrong status.
Typical fixes:
- Handle
OPTIONSon the API route or middleware layer - Return
Access-Control-Allow-Methodsincluding the real method, such asGET,POST, orPUT - Return
Access-Control-Allow-Headersincluding custom headers such asAuthorizationorContent-Type - Return an appropriate success status for
OPTIONS
Why preflight happens: Preflight is common when you use methods other than simple GET/POST, send JSON with certain headers, or include custom headers.
3. Error: Request header field Authorization is not allowed by Access-Control-Allow-Headers
What it usually means: Your frontend is sending a header the server did not explicitly allow during preflight.
Typical fixes:
- Add
AuthorizationtoAccess-Control-Allow-Headers - Also include any other custom headers you actually send
- Do not guess; inspect the browser network panel and compare request headers to server config
This is especially common when integrating token-based auth. If the request also depends on JWTs, see JWT Decoder Guide: How to Read Tokens Safely and Validate Claims and REST API Authentication Methods Compared: API Keys, OAuth, JWT, and Sessions.
4. Error: The value of the Access-Control-Allow-Origin header must not be * when credentials are included
What it usually means: The request uses cookies or credentials and the server replied with a wildcard origin.
Typical fixes:
- Replace
*with the exact requesting origin - Return
Access-Control-Allow-Credentials: trueif credentials are intended - On the client, only use
credentials: 'include'when required
Important: Credentialed requests require stricter matching. Wildcards and credentials do not mix.
5. Error: Method PUT or DELETE is not allowed by Access-Control-Allow-Methods
What it usually means: The preflight succeeded far enough to inspect allowed methods, but the method you need is missing.
Typical fixes:
- Add the method to
Access-Control-Allow-Methods - Verify the route actually supports that method server-side
- Check whether a load balancer, API gateway, or proxy is intercepting
OPTIONS
6. Error only happens in the browser, not in Postman or curl
What it usually means: This strongly suggests a CORS issue rather than a broken endpoint. Tools like Postman and curl do not enforce browser CORS rules the same way a browser does.
Typical fixes:
- Debug in browser DevTools, not only with external API clients
- Inspect both the preflight and actual request
- Confirm the frontend origin is the one your API allows
7. Error appears after deployment but not on localhost
What it usually means: Your production frontend origin differs from your local one, and the API allowlist or proxy config was never updated.
Typical fixes:
- Add the production domain to your allowed origins
- Check environment-specific CORS settings
- Confirm HTTPS is being used consistently in production
8. Error appears random across routes
What it usually means: CORS is applied inconsistently. Some routes may be covered by middleware while others bypass it.
Typical fixes:
- Apply CORS at a common middleware layer where appropriate
- Audit route groups, API gateway rules, and serverless function configs
- Compare a working route and a failing route side by side
Core headers to know
Access-Control-Allow-Origin: Which origin may access the responseAccess-Control-Allow-Methods: Which methods are permittedAccess-Control-Allow-Headers: Which request headers are permittedAccess-Control-Allow-Credentials: Whether cookies or credentials are allowedAccess-Control-Expose-Headers: Which response headers frontend code may readAccess-Control-Max-Age: How long preflight results may be cached
Quick debugging checklist
- Open DevTools and inspect the network tab
- Find the failing request and the preflight
OPTIONSrequest if present - Compare request origin, method, and headers to the response CORS headers
- Check whether credentials are being sent
- Confirm the API, proxy, CDN, and framework middleware all agree
// Example frontend request that may trigger preflight
fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer TOKEN'
},
body: JSON.stringify({ ok: true })
});The combination of JSON content type and an Authorization header often means you need a correctly handled preflight response.
Related subtopics
CORS bugs rarely live alone. The surrounding architecture often creates the real problem, so it helps to think in related buckets.
Frontend request design
Small frontend changes can alter CORS behavior. Adding an Authorization header, switching from form posts to JSON, enabling credentials, or moving from a relative path to a full API URL can all change how the browser treats the request. If you are building fetch wrappers or shared HTTP clients, keep CORS implications visible rather than hidden inside abstractions.
Authentication and cookies
Auth is one of the most common places where CORS gets complicated. Session cookies, bearer tokens, CSRF patterns, and same-site cookie settings all affect cross-origin flows. If your issue seems tied to login state rather than the endpoint itself, review the authentication model, not just the CORS headers. The guide on REST API Authentication Methods Compared: API Keys, OAuth, JWT, and Sessions is a useful companion here.
API gateways, reverse proxies, and CDNs
Many teams set CORS headers in the application but forget that a gateway or proxy may terminate requests before the app sees them. In those setups, the right fix may belong in Nginx, a cloud API gateway, serverless edge config, or a platform-level rule rather than in app code.
Local development vs production
Local development commonly uses separate ports and localhost origins, which makes CORS visible early. Production may use subdomains, HTTPS redirects, and proxy rewrites. A setup that feels simple locally can become more layered after deployment. Keep an environment matrix with frontend origins, backend origins, and credential requirements for each stage.
JSON payloads and content headers
Developers often assume the data format is the issue when the real issue is the request headers around it. If you are debugging payload handling too, it can help to validate and inspect the body separately using resources like JSON Formatter vs JSON Validator vs JSON Linter: What Each Tool Does. Clean payload debugging helps isolate the CORS layer from the data layer.
Server framework behavior
Express, FastAPI, Django, Flask, Spring, and serverless platforms all expose CORS differently. Some use middleware, some use decorators, and some require per-route settings. The concept is consistent even if the implementation is not: the response seen by the browser must contain the right headers for the actual origin, method, and headers involved.
Observability and logs
Application logs may show a successful request while the browser still reports a CORS failure, because the browser blocked access after receiving the response. That is why browser network inspection matters. If you operate APIs at scale, log request origin, method, and response CORS headers in development or non-sensitive debug modes to speed up diagnosis.
How to use this hub
When you hit a cross-origin problem, resist the urge to change three layers at once. Use a narrow, repeatable process.
- Start with the exact browser error. Copy the full message from DevTools. The wording often points directly to the missing header or invalid combination.
- Inspect the network request pair. Look for an
OPTIONSpreflight and the real request. If preflight fails, fix that first. - Write down the real origin. Include protocol, hostname, and port. A mismatch here explains many local and staging failures.
- List the request method and headers. Especially note
Authorization,Content-Type, and any custom headers. - Check credential usage. If cookies or
credentials: 'include'are involved, verify you are not using a wildcard origin. - Find the layer that owns the response. That might be app middleware, a framework config, a reverse proxy, or an API gateway.
- Test one change at a time. After each change, hard refresh and inspect the actual response headers again.
A simple mental model helps:
- If the server does not explicitly allow the browser request shape, the browser blocks it.
- If Postman works but the browser does not, stay focused on CORS before rewriting business logic.
- If one route works and another fails, compare configuration before changing frontend code.
For teams, this hub works well as a shared checklist in pull requests and deployment reviews. Before shipping a new frontend-to-API integration, verify:
- Allowed origins for each environment
- Allowed methods for each endpoint group
- Allowed headers for auth and tracing
- Credential policy for cookies or sessions
- Whether preflight is handled consistently
If your issue is partly masked by generic fetch failures, use the patterns in Fetch API Error Handling Patterns You Can Reuse in Production to separate transport, HTTP, and CORS concerns cleanly.
When to revisit
Return to this hub whenever the shape of your integration changes, because CORS problems usually appear at boundaries: new environments, new auth flows, new headers, or new infrastructure.
Revisit your CORS setup when:
- You add a new frontend domain, subdomain, port, or protocol
- You switch from local storage tokens to cookies or sessions
- You introduce
Authorization, custom headers, or tracing headers - You move an endpoint behind a proxy, gateway, CDN, or serverless platform
- You change request methods from simple reads to writes like
PUT,PATCH, orDELETE - You split a monolith into separate frontend and API deployments
- You see browser-only failures after an otherwise successful deployment
A good maintenance habit is to keep a short environment table in your project docs with:
- Frontend origin per environment
- API origin per environment
- Whether credentials are used
- Expected request headers
- Where CORS is configured
That small document often prevents repeat incidents better than memorizing one framework's CORS syntax.
Finally, treat CORS as a contract, not a one-time toggle. Every time your app changes how it talks to an API, verify that the browser-visible contract still matches. If you do that consistently, most cross-origin issues become quick header fixes instead of long debugging sessions.