CORS Troubleshooting Guide: Fix Preflight, Credentials, and Origin Errors
CORSweb securityAPIsfrontend debuggingHTTP

CORS Troubleshooting Guide: Fix Preflight, Credentials, and Origin Errors

CCloud Dev Toolkit Editorial Team
2026-11-07
7 min read

A practical CORS troubleshooting checklist for preflight failures, credentials, redirects, origin mismatches, proxies, and serverless APIs.

When a browser blocks a cross-origin request, the visible error often points to CORS while hiding the actual mismatch. This guide gives you a repeatable way to troubleshoot CORS errors, preflight requests, credentials, redirects, proxy layers, and serverless deployments without weakening access controls unnecessarily.

Overview

Cross-Origin Resource Sharing, or CORS, is a browser-controlled permission system for requests made from one origin to another. An origin is the combination of scheme, host, and port. For example, https://app.example.com and https://api.example.com have different origins even though they share a parent domain. Likewise, http://localhost:3000 and http://localhost:8000 are different origins because their ports differ.

A CORS failure usually means the API response did not provide the headers the browser expected for the requesting origin. The API may still receive and process the request; the browser can nevertheless prevent frontend JavaScript from reading the response. CORS is primarily a browser enforcement mechanism, not an authentication system and not a replacement for authorization.

Start with the browser's developer tools. Open the Network panel, reproduce the request, and inspect both the request and response. Look for an OPTIONS request before the main request, the request's Origin header, the response status, redirects, and the presence or absence of Access-Control-* headers. A JSON formatter can help inspect a JSON error body, but the decisive evidence is usually in the HTTP headers.

Use this basic decision path:

  1. If there is an OPTIONS request, troubleshoot the preflight response first.
  2. If there is no preflight, compare the actual response's CORS headers with the request origin.
  3. If cookies or authorization credentials are involved, check the credentials rules on both sides.
  4. If the request redirects, remove or handle the redirect before debugging the final endpoint.
  5. If a proxy, CDN, gateway, or serverless function sits in front of the API, inspect the response at every layer.

Checklist by scenario

Scenario 1: The preflight request fails

A browser may send a CORS preflight request when the planned request uses a non-simple method, custom headers, or certain content types. The preflight normally uses OPTIONS and includes headers such as Origin, Access-Control-Request-Method, and sometimes Access-Control-Request-Headers.

Check that the server or edge layer:

  • Accepts the OPTIONS method for the route.
  • Returns a successful response suitable for your infrastructure, commonly a 2xx response.
  • Includes Access-Control-Allow-Origin with the exact requesting origin when a specific origin is required.
  • Includes Access-Control-Allow-Methods containing the planned method, such as POST or PATCH.
  • Includes Access-Control-Allow-Headers containing requested non-safelisted headers, such as Authorization or Content-Type.
  • Does not redirect the preflight to another URL.

For example, if the browser sends Access-Control-Request-Headers: authorization, content-type, the response must permit those headers according to the server's CORS configuration. Header names are generally compared case-insensitively, but spelling and configuration still need to match the request.

Scenario 2: The request uses cookies or credentials

Credentialed CORS requests require coordinated settings. The frontend must explicitly request credentials, such as with fetch(url, { credentials: 'include' }). The server must return Access-Control-Allow-Credentials: true and must identify a specific allowed origin. A wildcard origin, Access-Control-Allow-Origin: *, is not compatible with credentialed browser requests.

Also verify the cookie's own attributes. Its domain, path, SameSite setting, security requirements, and expiration can affect whether it is sent. A successful CORS response does not guarantee that a cookie will be attached. Conversely, adding Access-Control-Allow-Credentials does not make an unauthenticated request authorized.

Scenario 3: The origin appears to be allowed but still fails

Compare the value exactly. These are distinct origins:

  • https://example.com and https://www.example.com
  • http://example.com and https://example.com
  • https://example.com and https://example.com:8443
  • http://localhost:3000 and http://127.0.0.1:3000

Do not add a trailing slash to the origin value when configuring an allowlist. The browser's Origin header contains the scheme, host, and port, but not a path. If several environments are supported, use an explicit allowlist and return the matching origin rather than reflecting arbitrary input.

Scenario 4: A proxy, gateway, or serverless function is involved

Test the public URL, not only the application process. A reverse proxy may handle OPTIONS itself, remove CORS headers, cache a response for the wrong origin, or redirect HTTP to HTTPS. A gateway may require an explicit route for OPTIONS. A serverless platform may apply CORS settings separately to successful responses and error responses.

Inspect the response at the browser and at the origin service. If the application emits the right header but the browser does not receive it, check the proxy or gateway. If the origin service never sees the request, check routing, DNS, TLS, and edge configuration before changing application code.

Scenario 5: The request redirects

Redirects can complicate CORS, especially for preflighted requests. Check whether the frontend is calling an old API path, a URL without the required trailing path convention, or an HTTP endpoint that redirects to HTTPS. Prefer configuring the frontend with the final HTTPS API URL and make sure the final response, not only the redirect response, has the required CORS headers.

For a broader request-testing workflow, see API Testing Tools Compared. A direct request made with a command-line client can confirm server behavior, but it does not reproduce all browser CORS enforcement.

What to double-check

Header or settingWhat to verify
OriginIdentify the exact scheme, host, and port sent by the browser.
Access-Control-Allow-OriginUse the exact permitted origin when access is restricted. Do not assume a wildcard is suitable for private or credentialed APIs.
Access-Control-Allow-MethodsInclude the method used by the actual request and permitted by the API.
Access-Control-Allow-HeadersPermit the headers requested during preflight, especially custom headers and authorization headers.
Access-Control-Allow-CredentialsUse only when credentialed browser requests are intentionally supported, and pair it with a specific origin.
Access-Control-Expose-HeadersList response headers that frontend JavaScript must read when they are not exposed by default.
Vary: OriginConsider this when responses vary by origin and an intermediary cache could reuse a response for another origin.

Configuration should be consistent on success and failure paths. An API might return CORS headers for a normal 200 response but omit them on a 401, 403, 404, or 500 response, making the browser report a less useful CORS error. Add the headers at a shared middleware or edge layer where appropriate, then verify error responses separately.

Keep CORS separate from authentication and authorization. A valid CORS response only tells the browser that frontend code from an origin may read the response. The API still needs to validate sessions, tokens, permissions, and request data. When investigating token-related failures, avoid pasting live tokens into online tools; the JWT debugging guide covers safer inspection practices.

Minimal framework pattern

In an Express-style Node application, the important pattern is to decide whether the incoming origin is in a trusted allowlist, set the matching response headers, and answer OPTIONS requests before route-specific authentication rejects them. The exact middleware syntax varies by framework and version, so treat the following as a configuration model rather than a drop-in security policy:

const allowedOrigins = new Set([
  'https://app.example.com',
  'http://localhost:3000'
]);

function corsHeaders(req, res) {
  const origin = req.headers.origin;
  if (origin && allowedOrigins.has(origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
    res.setHeader('Access-Control-Allow-Credentials', 'true');
    res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
    res.setHeader('Vary', 'Origin');
  }
}

app.use((req, res, next) => {
  corsHeaders(req, res);
  if (req.method === 'OPTIONS') return res.sendStatus(204);
  next();
});

Before using this pattern, decide whether credentials are needed. If they are not, omit the credential setting and use the narrowest origin policy that meets the application requirement.

Common mistakes

  • Adding CORS headers only in the frontend. The browser evaluates the API response, so frontend code cannot grant itself permission.
  • Allowing every origin during a rushed fix. A broad policy can hide configuration problems and may be inappropriate for authenticated or sensitive responses.
  • Handling only GET and POST. Preflight and browser requests may require OPTIONS, and the application may use methods such as PATCH or DELETE.
  • Forgetting custom headers. An Authorization header or application-specific header can trigger preflight.
  • Using wildcard origin with credentials. Choose explicit origins when cookies or other browser credentials are involved.
  • Testing with a tool that is not a browser. A command-line request can show what the server returns, but it will not enforce CORS in the same way as a browser.
  • Ignoring caches. If the response changes by origin, an intermediary may need the response to vary by Origin.
  • Debugging only the happy path. Check redirects, authentication failures, validation errors, and server errors too.

For payload-related failures that appear alongside CORS errors, format the request and response separately. The JSON formatter and validator guide can help distinguish malformed data from a browser policy problem.

When to revisit

Return to this checklist whenever a frontend connects to a new API, a development origin changes, authentication moves from headers to cookies, or a deployment introduces a proxy, CDN, gateway, or serverless adapter. Recheck it after changing HTTP methods, adding custom headers, moving from HTTP to HTTPS, or changing the public API URL.

Make CORS verification part of deployment review rather than an emergency-only task. For each supported environment, record the frontend origin, API origin, credential model, allowed methods, required request headers, and the component responsible for handling OPTIONS. Then test a normal request, a preflighted request, an unauthorized response, and a failing response from the browser.

When a CORS error appears, use this short runbook:

  1. Copy the browser's exact Origin value.
  2. Identify whether an OPTIONS preflight was sent.
  3. Compare requested methods and headers with the preflight response.
  4. Check credential settings on both frontend and API.
  5. Remove redirects by calling the final API URL.
  6. Inspect proxy, gateway, cache, and serverless behavior.
  7. Retest both successful and error responses without exposing secrets.

This process keeps the fix focused: permit the intended cross-origin traffic, preserve authentication and authorization controls, and avoid treating a browser message as evidence that the underlying API is unavailable.

Related Topics

#CORS#web security#APIs#frontend debugging#HTTP
C

Cloud Dev Toolkit Editorial Team

Developer Tools Editors

Senior editor and content strategist. Writing about technology, design, and the future of digital media. Follow along for deep dives into the industry's moving parts.