What Is a CORS Error?

A CORS error is not a network failure and not a bug in your JavaScript. It is the browser enforcing a rule on the server's behalf, and the server is where the fix goes.

What Is a CORS Error? — Troiana insight cover

In short

A CORS (cross-origin resource sharing) error occurs when JavaScript on one origin, such as https://app.example.com, requests a resource from another, such as https://api.example.com, and the browser blocks the response because the server did not include headers permitting that origin. It exists to stop malicious pages reading data from sites you are logged into. The fix is on the server: respond with Access-Control-Allow-Origin naming the calling origin (not a wildcard when credentials are involved), handle the OPTIONS preflight, and allow the methods and headers the request uses. Nothing in the front-end code can bypass it, and nothing should.

The rule underneath

Browsers enforce the same-origin policy: a script running on one origin, meaning the combination of scheme, host and port, may not read responses from a different origin. Without it, any page you visited could quietly fetch your bank's account page using your logged-in cookies and read the balance. The policy is one of the oldest security foundations of the web.

CORS is the mechanism that relaxes it, deliberately and per server. A server that wants to be called from other origins says so in response headers; the browser reads them and allows or blocks the response accordingly. When the headers are missing or wrong, the browser blocks, and it logs the error that brought you here.

Reading the error

The console message is specific, if verbose. "Access to fetch at 'https://api.example.com/data' from origin 'https://app.example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource." Three facts are in there: the resource requested, the origin making the request, and which header the browser expected and did not find. Variants name a mismatched origin, a disallowed method or header, a failed preflight, or a credentials conflict.

Two things the message does not mean. It does not mean the request failed to reach the server; it usually did, and the server usually responded. And it does not mean the server rejected the request; the browser rejected the response. Tools such as curl and Postman, which are not browsers, make the same request successfully, which is the standard way to confirm a CORS problem rather than an API problem.

The headers that fix it

On the server, for responses to cross-origin requests:

  • Access-Control-Allow-Origin: the origin permitted, such as https://app.example.com. A wildcard * permits any origin and is acceptable for public, unauthenticated APIs, but is refused by browsers when the request includes credentials. To allow several specific origins, the server checks the request's Origin header against a list and echoes the matching one, adding Vary: Origin.
  • Access-Control-Allow-Methods: the HTTP methods permitted, for anything beyond simple GET and POST.
  • Access-Control-Allow-Headers: request headers permitted, such as Authorization or Content-Type: application/json.
  • Access-Control-Allow-Credentials: true if cookies or HTTP authentication should be sent, in which case the origin must be explicit and the client must opt in with credentials: 'include'.
  • Access-Control-Max-Age: how long the browser may cache the preflight result.

Most frameworks have a CORS middleware that sets these correctly from a short configuration; use it rather than hand-writing headers.

Preflight

For requests that are not "simple", meaning methods other than GET, HEAD or POST, custom headers, or content types other than form data and plain text, the browser first sends an OPTIONS request to the same URL asking what is allowed. The server must answer that OPTIONS request with the CORS headers and a success status, quickly and without requiring authentication. A common failure is an API that handles GET and POST correctly but returns 404 or 401 for OPTIONS, so every JSON request with an Authorization header fails preflight. Another is a proxy or firewall in front of the API that does not pass OPTIONS through.

The mistakes that make it worse

Adding headers in the front end. CORS headers are response headers from the server; setting them on the request does nothing except sometimes trigger a preflight that then fails.

Wildcard with credentials. Browsers reject * when cookies are sent. Echo the specific origin.

Disabling the browser's security. Extensions and flags that turn CORS off make the error vanish on the developer's machine and change nothing for users.

Allowing every origin on a private API. That reopens the vulnerability CORS exists to close. Allow the origins that need access, and nothing else.

Fixing it at the CDN when the origin also sets headers, producing duplicate Access-Control-Allow-Origin values that browsers reject.

Confusing CORS with authentication. A correct CORS setup lets the browser read the response; whether the request is authorised is a separate question the API still has to answer.

When a proxy is the right answer

If you do not control the server, such as a third-party API with no CORS headers, the browser cannot be made to accept its responses. The correct pattern is a small endpoint on your own origin that makes the request server-side and returns the result, adding whatever authentication the third party needs without exposing keys to the browser. This is also the secure way to handle API keys, which never belong in front-end code regardless of CORS.

Checking it

Inspect the failing request in the browser's network panel: the OPTIONS preflight, if any, and the actual request, with their response headers. Confirm the server sets Access-Control-Allow-Origin matching the page's origin exactly, including scheme and port. Confirm OPTIONS returns 200 or 204 with the allow headers. Confirm credentials mode matches on both sides. Then retest from the real deployed origin, since localhost and production origins differ and a configuration that allows one may not allow the other.

CORS sits alongside content security policy and other headers as part of a site's browser-enforced security. If an integration is failing and the console blames CORS, book a call; it is usually a ten-minute server change once the request and response are seen side by side.

Common questions

How do I fix a CORS error?

On the server that receives the request, not in the browser or front-end code: add an Access-Control-Allow-Origin header naming the calling origin, respond to OPTIONS preflight requests with the allowed methods and headers, and set Access-Control-Allow-Credentials with an explicit origin if cookies are sent. Most frameworks have CORS middleware that does this from a short configuration.

Why does my API work in Postman but give a CORS error in the browser?

Because CORS is enforced by browsers only. Postman, curl and server-side code are not subject to the same-origin policy and receive the response normally. The browser received it too, then blocked your JavaScript from reading it because the server's response lacked the headers permitting your page's origin.

Can I fix CORS from the front end?

No. CORS headers are response headers the server must send; nothing set on the request changes the browser's decision. If you do not control the server, route the request through a small endpoint on your own origin that calls the third-party API server-side and returns the result. Browser extensions that disable CORS only affect the developer's machine.

What is a CORS preflight request?

An OPTIONS request the browser sends automatically before a cross-origin request that uses methods other than GET or simple POST, custom headers such as Authorization, or a JSON content type. The server must answer it with the CORS allow headers and a success status. APIs that return 404 or 401 for OPTIONS fail every such request.

Is it safe to set Access-Control-Allow-Origin to *?

For public, unauthenticated data, yes. For anything involving cookies, sessions or user data, no: browsers refuse the wildcard when credentials are included, and allowing every origin on a private API recreates the vulnerability CORS exists to prevent. Allow the specific origins that need access and echo the matching one with Vary: Origin.

Have something worth building right?