When a browser reports that a fetch request was blocked by CORS, the failure is usually a mismatch between the page origin, the request, and the API response. This checklist shows how to identify that mismatch, distinguish a simple request from a CORS preflight request, read the relevant response headers, and apply a server-side fix without weakening access controls unnecessarily.
Overview
Cross-Origin Resource Sharing, or CORS, is a browser-controlled mechanism for allowing a web page from one origin to request resources from 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 because their hosts differ. Likewise, an HTTP development URL and an HTTPS production URL are different origins.
The browser sends the request, but it decides whether frontend JavaScript may read the response. The API must explicitly communicate that permission with response headers such as Access-Control-Allow-Origin. A CORS error is therefore not normally fixed by changing JSON parsing, adding a frontend header, or disabling a browser security feature. The API, gateway, reverse proxy, or serverless function must return headers that match the browser's request.
Start with the browser's developer tools. Open Network, reproduce the failure, and inspect both the actual request and any preceding OPTIONS request. Record the page origin, request URL, HTTP method, request headers, status code, redirect behavior, and response headers. If the request never reaches your application handler, check the proxy, load balancer, CDN, or platform configuration before changing application code.
For related API debugging work, a structured response inspector can help you read headers and payloads more clearly. The Online Developer Tools Toolbox and JSON Formatter and Validator guide are useful companions when the CORS problem is mixed with malformed or unexpected API data.
Checklist by scenario
Scenario 1: A basic GET request is blocked
- Copy the exact frontend origin from the request context, including scheme and port.
- Compare it with the API's allowed origin configuration. Do not assume that a similar hostname is equivalent.
- Check whether the API response includes
Access-Control-Allow-Originwith the expected value. - Confirm that the header is present on error responses as well as successful responses. A server may handle CORS for a normal 200 response but omit it on a 401, 403, or 500 response.
- Look for redirects. A redirect to a different host, login route, or HTTP endpoint can change the request path and produce a separate CORS or mixed-content failure.
A typical response for a public endpoint might include:
Access-Control-Allow-Origin: https://app.example.com
Use the precise origin rather than a broad pattern when the endpoint contains private data. The value is an origin, not a full URL with a path, query string, or trailing route.
Scenario 2: The browser sends an OPTIONS preflight
A browser may send a CORS preflight before the application request when the method or request headers require permission. The preflight uses OPTIONS and tells the server which origin, method, and headers the browser intends to use. A representative request looks like this:
OPTIONS /v1/profile HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: PATCH
Access-Control-Request-Headers: authorization, content-type
The server must respond successfully and include compatible permission headers, for example:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, PATCH, OPTIONS
Access-Control-Allow-Headers: authorization, content-type
The exact allowed methods and headers should match the API's intended contract. Make sure the infrastructure accepts OPTIONS, does not require application authentication for the preflight unless deliberately configured to do so, and does not return a redirect where the browser expects a valid preflight response.
Scenario 3: The request uses cookies or credentials
If the frontend sends cookies or uses credentialed fetch behavior, the server must opt into credentials. The client and server settings must agree:
fetch('https://api.example.com/account', {
credentials: 'include'
});
The corresponding response needs Access-Control-Allow-Credentials: true and a specific allowed origin. A wildcard origin is not compatible with credentialed CORS access. Also check cookie attributes, domain scope, secure transport, and the server's authentication path; a CORS header cannot make an incorrectly scoped or expired cookie work.
Scenario 4: The API works in a command-line client but not in the browser
Tools such as curl or an API client are valuable for testing server behavior, but they do not enforce the browser's same-origin rules in the same way. A successful command-line response proves that the server is reachable; it does not prove that browser JavaScript is allowed to read it. Reproduce the request with an Origin header and inspect the response, then test the real browser request including its method, credentials, and custom headers.
Scenario 5: Development works but deployment fails
Compare the deployed frontend origin with the development origin. Common differences include a new hostname, HTTPS instead of HTTP, a preview deployment domain, or a nondefault port. Store allowed origins as environment-specific configuration, but validate the resulting value at startup so a missing variable does not silently create an invalid header. If a static frontend was recently deployed, review its domain, DNS, HTTPS, and cache setup using the static HTML cloud deployment guide.
What to double-check
| Check | Question | Typical corrective action |
|---|---|---|
| Origin | Does the allowed value exactly match scheme, host, and port? | Update the API or gateway allowlist. |
| Preflight | Does OPTIONS return the required CORS headers? | Handle OPTIONS before authentication or routing rejects it. |
| Methods | Is the requested method listed? | Add only the methods the endpoint needs. |
| Headers | Are requested headers allowed? | Allow required headers such as authorization or content-type. |
| Credentials | Are cookies or authenticated browser credentials involved? | Use a specific origin and enable credentials consistently. |
| Proxy layer | Does the final response preserve the application headers? | Inspect gateway, CDN, ingress, and serverless response rules. |
| Cache | Could a shared cache serve a response for the wrong origin? | Review cache variation and invalidate stale configuration where appropriate. |
When a server allows multiple origins dynamically, it should return the requesting origin only after validating it against an explicit allowlist. In that design, review whether caches vary responses by the Origin request header. A correct application rule can still appear inconsistent if an intermediary reuses a response generated for another origin.
Common mistakes
- Adding
Access-Control-Allow-Originto the frontend request. This is a response permission, so adding it as a request header does not grant access and may itself trigger a preflight. - Using
mode: 'no-cors'as a fix. This can produce an opaque response that frontend code cannot inspect normally. It is not a general solution for API calls that need JSON, status handling, or authentication. - Allowing every origin during production troubleshooting. A broad setting may hide the configuration mistake and expose data more widely than intended. Use a temporary, controlled test and replace it with an explicit allowlist.
- Fixing only successful responses. Authentication failures, validation errors, and server exceptions also need a consistent response strategy if the frontend must read their status or body.
- Confusing CORS with server authorization. CORS controls whether browser code can read a response. It does not replace authentication, authorization, CSRF defenses, input validation, or rate limiting.
- Testing the wrong origin. A local page opened with a file URL, a development server, and a deployed HTTPS site can all produce different origins. Verify the actual page URL in the browser rather than relying on memory.
If the console message is vague, inspect the Network panel and server logs together. A missing header, a failed preflight, a refused connection, a certificate problem, and a server authorization failure can appear close together in the UI but require different fixes.
When to revisit
Keep this checklist with the integration rather than treating CORS as a one-time setup task. Revisit it whenever a frontend or API changes domains, ports, schemes, authentication methods, HTTP methods, custom headers, proxy layers, or deployment environments. It is especially useful before a seasonal planning cycle or release window, when preview environments and infrastructure changes are often introduced together.
When a workflow or platform tool changes, retest the complete browser path: open the deployed page, make the real request, inspect any preflight, verify success and error responses, and confirm that credentials behave as intended. Record the approved origins and required methods in the API documentation or deployment configuration. If the request fails again, begin with the exact origin and Network panel evidence instead of applying a broad workaround. That habit turns a vague “fetch blocked by CORS” message into a short, repeatable troubleshooting process.