Capture the exact browser origin and failing request stage, repair the permitted server response policy, and verify allowed and denied origins alongside normal authentication.

A browser says “blocked by CORS,” but the API works when you paste its URL into a tab. Those observations can both be correct. Opening a URL as a page is different from allowing JavaScript on one origin to read a response from another. The useful investigation follows the browser’s exact request, not a generic “enable CORS” switch.
Identify the caller, destination and failing stage before changing a server. This guide uses invented domains and request examples. It does not suggest disabling browser security, reflecting every origin or placing private API keys in a public page.
Write down the two actual origins
An origin includes the scheme, hostname and port. A page at https://app.example and an API at https://api.example are different origins, even when the same organisation operates both. Switching from HTTP to HTTPS or using a different development port can also change the origin.
MDN describes CORS as a browser-enforced mechanism through which a server declares permitted cross-origin response access. It is not a login system. A caller outside a browser does not become authorised merely because it can send a request.
Record the page’s displayed origin, the request’s final URL after any redirects, its method and the browser-supplied Origin value. A configuration permitting the apex domain may not permit the www hostname or a preview subdomain. Compare exact values rather than assuming that related names are interchangeable.
Capture the request that breaks the feature
Open the browser’s Network and Console panels, reproduce one harmless action and locate its failing request. An entire page can load while a single API call fails. Keep the relevant status, method, request headers and response headers, plus a timestamp or sanitized request identifier for server logs.
The CORS error reference explains why the browser console is important: JavaScript often receives only a limited failure message. Read the specific reason rather than treating every console entry as an absent Allow-Origin header.
- If OPTIONS appears, inspect it and the intended request separately.
- If the intended request is missing, determine whether the preflight failed first.
- If the intended request returned an error, investigate its server result as well as CORS.
- If no HTTP response exists, check connection, TLS and other network evidence before editing response headers.
Sanitize cookies, tokens, private form fields and personal query values before sharing a trace. Do not paste a complete private request into a public support thread.
Understand why a preflight appears
Some cross-origin requests require the browser to ask permission before sending the intended request. A JSON content type or a custom request header can trigger this preflight. The browser sends OPTIONS describing the intended method and relevant headers; your application code does not need to invent that exchange manually.
For a fictional preview API, the diagnostic sequence could begin with this request. It contains no real credential, and the example does not establish that the destination should allow every caller.
OPTIONS /preview HTTP/1.1
Origin: https://app.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
MDN’s OPTIONS reference explains the preflight’s role. The server must evaluate the requested origin, method and headers against its intended policy. A generic 200 response with no relevant CORS permissions does not grant the browser what it requested.
Keep preflight permission separate from endpoint authentication
A preflight does not carry the user’s normal request credentials. If a login middleware redirects every OPTIONS request to a sign-in screen, the browser may never reach the actual API call. Configure the supported preflight handling so it can evaluate allowed origins and operations without requiring that login exchange.
This does not mean removing authentication from the real endpoint. The subsequent POST or GET still needs its normal identity, authorisation, validation and abuse controls. An allowed origin is a statement about browser response access, not proof that a person may read a particular account record.
Review the whole route: edge rules, web server, application middleware and API handler. A fix in the handler cannot help when a proxy rejects OPTIONS before the application receives it. Ask each owner for the matched request and rule rather than disabling protection broadly.
Return the policy on the actual response too
A successful preflight is only the permission stage. The actual response must also contain the appropriate CORS headers. Inspect ordinary success, validation failures, expired sessions and server errors. Otherwise, a real 401 or 500 may be hidden behind another browser CORS message.
| Observed exchange | Likely investigation |
|---|---|
| OPTIONS is rejected or redirected to login | Preflight routing and middleware order. |
| OPTIONS permits POST, but the POST response lacks permission | Actual response and error-path header ownership. |
| The response names a different origin | Exact hostname, scheme, port and environment allowlist. |
| Two Allow-Origin headers appear | Competing proxy and application configuration. |
| The API logs an internal exception | The application failure first, then correct error-response access. |
Preserve the real status and error meaning during the repair. Turning every failure into 200 or exposing internal stack traces to make a console warning disappear is not a reliable resolution.
Handle credentialed access deliberately
Decide whether the request needs browser credentials at all. A public catalogue and a private account endpoint may have different requirements. Do not add credentials everywhere merely because a copied example includes them.
For a permitted credentialed browser request, Access-Control-Allow-Origin must identify the permitted origin rather than use a wildcard, and the relevant response must allow credentials. A fictional response could include these fields after checking that origin against the server’s allowlist:
Access-Control-Allow-Origin: https://app.example
Access-Control-Allow-Credentials: true
Vary: Origin
Do not reflect an arbitrary Origin value and simultaneously permit credentials. If responses vary by permitted origin, Vary: Origin helps caches keep those variants separate. It does not replace an allowlist, and personalised data still needs an appropriate private cache policy.
Cookie restrictions remain independent. A correct CORS exchange cannot force a browser to send a cookie blocked by its privacy policy. Our embedded-form storage guide covers that different diagnostic boundary.
Reject shortcuts that hide the evidence
Setting fetch to no-cors does not make a protected cross-origin response readable. It produces an opaque response in the relevant case, which cannot supply the normal response data your feature expects. Likewise, a browser extension that disables checks only changes the developer’s browser; it does not repair visitors’ access.
Do not route private traffic through an untrusted public CORS proxy. If the architecture should use a server-side integration you control, design its authentication, destination restrictions and secret handling deliberately. That is a new trust boundary, not a harmless header workaround.
CORS also does not replace CSRF protection: some cross-origin requests can be sent without the preflight you might expect. Keep the endpoint’s request protection even when a browser cannot read its response.
Verify both permission and refusal
Retest from the real permitted production origin and a deliberately unapproved test origin. Include the actual method and headers, authenticated and signed-out states where relevant, and a controlled validation failure. Confirm that the allowed caller can read the intended result while an unauthorised account still receives the correct denial.
Preflight responses can be cached, so record whether the test used a fresh browser session or a previously cached permission decision. Keep the successful OPTIONS exchange, actual response and application result as separate evidence. Finish with the allowed origins, owning configuration, remaining limits and rollback plan; “works in my terminal” is not the browser acceptance check.
Sources and verification
Editorial review 2026-10-14. Source check dates are recorded separately. Notes describe what each source supports and its limits.
View sources
- MDN: Cross-Origin Resource SharingChecked Origins, browser response-access policy, preflight conditions, credentials and third-party cookie limitations.
Limits: CORS is not authentication or a substitute for server-side authorisation and CSRF protection. - MDN: CORS errorsChecked Browser diagnostics and the need to inspect detailed console and network evidence.
Limits: JavaScript error messages can withhold the detailed cause, and an apparent CORS failure can accompany a network or server failure. - MDN: Access-Control-Allow-OriginChecked Explicit allowed origins, wildcard credential restrictions and Vary: Origin for dynamic permitted responses.
Limits: A response header alone does not prove an origin allowlist is safe or an endpoint is authorised. - MDN: OPTIONSChecked OPTIONS use in CORS preflight and requested methods and headers.
Limits: A successful OPTIONS exchange is separate from the actual application response. - MDN: Same-origin policyChecked Origin comparison by scheme, host and port, and distinctions between cross-origin writes and reads.
Limits: Does not supply an application-specific authentication or CSRF implementation. - MDN: Using the Fetch APIChecked The opaque response limitation of no-cors and deliberate credentialed fetch behavior.
Limits: Client request options cannot grant server-side CORS permission or override cookie policy.