LEARN · DEBUGGING GUIDE

Debugging CORS Errors in Browser-Based APIs

CORS errors can block crucial API calls in web apps and often stump even experienced devs. Here's how to diagnose and fix them quickly.

BeginnerHTTP / Networking5 min read

What this usually means

A CORS error happens when a browser-enforced security policy blocks a frontend JavaScript application from making cross-origin HTTP requests to a backend that hasn't explicitly allowed the browser's origin. The browser inspects the response headers like 'Access-Control-Allow-Origin', and if they're missing or incorrect, the request is blocked at the client — often with misleading status codes or errors. Sometimes, backend misconfigurations or network proxies strip CORS headers unnoticed. Strict default headers (esp. for credentials, wildcards, or custom headers) add tricky edge cases.

( 01 )Fast diagnosis

The first ten minutes — establish facts before touching code.

  • 1Check Chrome DevTools > Network tab for the failed request; examine the Response Headers (look for 'Access-Control-Allow-Origin', 'Vary', etc.)
  • 2Open Console tab; copy exact CORS error message and note the origin and endpoint
  • 3Repeat the same API call using curl with -v; if it works, the issue is browser CORS enforcement.
  • 4Check if preflight (OPTIONS) requests are sent and what status/headers are returned (click on OPTIONS in network panel)
  • 5Look for differences in behavior when testing from localhost vs. deployed frontend
  • 6If using authentication, verify 'Access-Control-Allow-Credentials' and ensure 'Allow-Origin' is not '*'
( 02 )Where to look

The specific files, logs, configs, and dashboards that usually own this bug.

  • searchAPI server response headers, especially 'Access-Control-Allow-Origin' and 'Access-Control-Allow-Credentials'
  • searchWeb server/reverse proxy configs (nginx.conf, .htaccess, AWS API Gateway settings)
  • searchFrontend code for fetch/XHR parameters (credentials: 'include', custom headers)
  • searchBrowser network inspector > Headers tab for preflight and main requests
  • searchBackend CORS middleware config files (e.g., cors.js for Express, CORS policy in Spring Boot)
  • searchCloud/PaaS configuration dashboards for CORS or header rewrites (Firebase, Netlify, S3, API Gateway)
( 03 )Common root causes

Practical causes, not theory. These are the things you will actually find.

  • warning'Access-Control-Allow-Origin' missing or not matching frontend origin
  • warningBackend fails to respond to preflight OPTIONS requests (405/403 error)
  • warning'Allow-Origin' is '*', but credentials are required (cookies or Authorization header)
  • warningProxy or CDN strips or overrides CORS headers
  • warningCORS middleware misconfigured, e.g. wrong 'allowedOrigins' in Express or Spring
  • warningMismatch between 'Origin' header in request and allowed origins in backend
  • warningFrontend sends custom headers (e.g. X-Auth-Token), triggering preflight, but server doesn't handle OPTIONS
( 04 )Fix patterns

Concrete fix directions. Pick the one that matches your root cause.

  • buildExplicitly set 'Access-Control-Allow-Origin' to the exact frontend origin (e.g. 'https://app.example.com')
  • buildHandle OPTIONS requests with correct CORS headers and a 200 response in backend or proxy
  • buildIf credentials are required, also add 'Access-Control-Allow-Credentials: true' and never use '*' for origin
  • buildFor development, configure your backend to allow 'http://localhost:3000' (or relevant port)
  • buildDouble-check that proxies and CDNs pass through CORS headers unmodified
  • buildUse official CORS middleware and configure allowed headers, methods, and origins precisely
( 05 )How to verify

A fix you cannot prove is a guess. Close the loop.

  • verifiedReload browser, clear cache, and confirm API calls no longer trigger CORS errors in console
  • verifiedObserve OPTIONS and actual requests both returning correct headers in DevTools
  • verifiedTest with credentials (cookies, Authorization headers) and confirm data is exchanged successfully
  • verifiedRepeat curl or Postman test and ensure headers now match what browser expects
  • verifiedDeploy fix to staging and test from both localhost and production domains
( 06 )Mistakes to avoid

Things that make this bug worse or harder to find.

  • warningSetting 'Access-Control-Allow-Origin: *' when using 'credentials: true' in frontend requests
  • warningForgetting to handle OPTIONS requests leading to 405 errors (common with custom middlewares)
  • warningAssuming working in Postman/curl means browser will work (browser enforces CORS, curl does not)
  • warningAllowing all origins in production (security risk, enables CSRF)
  • warningTesting only in one environment; deploys to Netlify, Vercel, or S3 may require additional CORS config
( 07 )War story

Frontend Fails to Fetch User Profile Due to CORS, Production Outage

Full Stack EngineerReact frontend (Vercel), Node.js Express backend (AWS Elastic Beanstalk), CloudFront CDN

Timeline

  1. 14:02Frontend deploy triggers spike in user errors fetching /api/profile
  2. 14:05Users report blank dashboard; console shows CORS policy errors
  3. 14:09Engineer checks API with Postman—works fine, suspects frontend bug
  4. 14:13DevTools reveal missing 'Access-Control-Allow-Origin' on profile API calls
  5. 14:17curl -v shows response headers present, but CloudFront is stripping CORS headers
  6. 14:22CDN configuration updated to forward all headers; CORS headers restored
  7. 14:24Frontend fetches work, error rate drops to zero

Our React app suddenly stopped loading user profiles after a routine frontend deployment. I initially suspected a breaking change in state management, but the API worked perfectly in Postman. However, in Chrome DevTools, all XHR requests to /api/profile failed with a 'blocked by CORS policy' error.

Digging into the network inspector, I noticed the absence of 'Access-Control-Allow-Origin' on the failing requests. Oddly, the same route worked fine when accessed directly via curl. This pointed to something in the request path (proxy or CDN) interfering with headers.

Turns out, CloudFront was not configured to forward the 'Origin' header or return custom response headers from the backend. Once I added the appropriate header forwarding rules, CORS headers came through as expected and the problem disappeared.

Root cause

CloudFront CDN config didn't forward the necessary CORS headers from backend to browser.

The fix

Altered CloudFront behavior to forward all headers and cache based on Origin, so 'Access-Control-Allow-Origin' passed through.

The lesson

Always check every hop (proxy, CDN) for header modifications in CORS issues—browser enforcement can hide backend correctness.

( 08 )How Browsers Enforce CORS: The Actual Blocking Point

CORS is enforced entirely by browsers, not by servers. Even if your server supports cross-origin requests, if the response headers aren't exactly right, the browser will refuse to deliver the response to JavaScript. This means you'll often see status code 0 or misleading failures—even when the request hits your backend and gets a real response.

I've seen teams burn hours debugging the backend when the real culprit was a missing header on a CDN or an nginx config. Always confirm headers in the browser's network inspector first.

( 09 )Decoding Preflight Requests and Why They Fail

Browsers send a preflight OPTIONS request for non-simple requests—those using custom headers, methods like PUT/PATCH/DELETE, or credentials. If your backend doesn't explicitly allow OPTIONS or fails to return proper CORS headers on that method, the browser blocks the actual request.

Many frameworks require you to explicitly add middleware to handle OPTIONS with the right headers. Don't just return 200—check the headers.

( 10 )Role of Proxies, CDNs, and Serverless Gateways in CORS

Even if your backend sends the correct headers, intermediate layers like nginx, AWS CloudFront, API Gateway, or Netlify can strip or override them.

If your API works in development but not in production, or only fails for some endpoints, immediately suspect header stripping along the request path. Always test in the deployed environment using DevTools.

( 11 )Dealing with Credentials: Why Wildcard Origins Don’t Work

If your frontend sends credentials (cookies, Authorization header), never use 'Access-Control-Allow-Origin: *'. Browsers will block the response by design. The allowed origin must exactly match the requesting origin.

This is a frequent source of 'it works locally, fails in prod' bugs—make sure your CORS config is as specific as your authentication needs.

Frequently asked questions

Why does my API work in Postman but fails in the browser with CORS?

Postman and curl do not enforce CORS; browsers do. A missing or incorrect CORS header will block browser JavaScript, but won't affect server-to-server or tool requests.

What is a preflight OPTIONS request?

It's an automatic browser request for certain cross-origin calls, asking the server which methods and headers are allowed. If your server doesn't handle OPTIONS correctly, the actual request will never reach it.

How do I debug CORS when using a CDN or reverse proxy?

Check if the CDN/proxy is configured to forward and return CORS headers. Use browser DevTools to inspect headers, then compare with direct requests (bypassing the CDN) using curl.

Can I just use 'Access-Control-Allow-Origin: *' to fix all CORS errors?

Only if you do not send credentials (cookies, HTTP auth). For credentialed requests, the origin must be explicit—'*' will be ignored and blocked by the browser.