Skip to content
TabBench

CORS errors explained, and how to fix them

By TabBenchHow we check our guides

“Access to fetch at … has been blocked by CORS policy” is one of the most searched error messages in web development, and one of the most misunderstood. The request usually reached the server and got an answer; the browser then refused to hand that answer to your JavaScript because the server did not say your site was allowed to read it.

CORS is a browser rule, enforced on the client but fixed on the server. This guide explains what triggers it, how to read the error, and exactly which headers to send, including the traps with credentials, preflight requests and caching.

Open the HTTP Header GeneratorFree, no sign-up, and your file never leaves your browser.

Step by step

  1. Understand the same-origin policy

    An origin is the combination of scheme, host and port. By default, a page on https://app.example.com may not read responses from https://api.example.com, because they are different origins. Cross-Origin Resource Sharing is the opt-in mechanism: the other server names the origins that may read its responses using Access-Control-Allow-Origin.

  2. Tell simple requests from preflighted ones

    A GET, HEAD or plain form POST with only basic headers is sent straight away, and the browser checks the response headers afterwards. Anything else (PUT, PATCH, DELETE, a JSON Content-Type, or a custom header such as Authorization) makes the browser send an OPTIONS preflight first, asking whether the real request is allowed. If the preflight fails, the real request is never sent.

  3. Read the error message

    “No Access-Control-Allow-Origin header is present” means the response did not include the header. “The value of the Access-Control-Allow-Origin header must not be the wildcard * when credentials mode is include” means you send cookies, so the server must name the exact origin. “Request header field … is not allowed by Access-Control-Allow-Headers” and “Method … is not allowed” refer to the preflight answer. “Response to preflight request doesn't pass access control check” often means the OPTIONS request was redirected, needed authentication or returned an error status.

  4. Send the right headers from the server

    On the real response add Access-Control-Allow-Origin with your exact origin, and Vary: Origin if the value depends on the request. For preflights, answer OPTIONS with a 204 status and Access-Control-Allow-Methods, Access-Control-Allow-Headers and optionally Access-Control-Max-Age. If the page sends cookies or an Authorization header with credentials, add Access-Control-Allow-Credentials: true. The HTTP Header Generator builds these and outputs them for nginx, Apache, Express and other servers.

  5. Test with the response in front of you

    Open the Network tab and look at both the OPTIONS request and the real one. Paste the response headers into the HTTP Header Analyzer, which checks for the wildcard-with-credentials mistake and a missing Vary: Origin. Retest after every change, and clear the browser's cached preflight if needed.

Things worth knowing

  • Do not fix CORS with a public “CORS proxy” or by disabling web security in your browser. Both hide the problem and expose your users.
  • CORS does not protect your server from other clients: curl and other servers ignore it. It protects users' browsers.
  • The wildcard * cannot be combined with credentials, and * in Access-Control-Allow-Headers is treated literally when credentials are used.
  • If the allowed origin is chosen dynamically, check it against a fixed allow-list and always add Vary: Origin.

Frequently asked questions

Why does my request work in Postman but not in the browser?

Postman is not a browser and does not apply the same-origin policy. The browser will only let your page read the response if the server sends the right CORS headers, so the request can succeed on the network and still be blocked in JavaScript.

Why is there an OPTIONS request I never made?

It is the preflight. The browser sends it automatically before a cross-origin request that uses a non-simple method, a JSON content type or custom headers, to ask the server for permission first.

Can I set Access-Control-Allow-Origin to *?

For public, non-credentialed data, yes. For anything tied to a user, or whenever the page sends cookies, you must name the specific origin instead. Browsers reject * together with credentials.

Do I need CORS for localhost development?

Yes if the front end and the API run on different ports, because a different port is a different origin. Either allow the development origin on the API or use your dev server's proxy so both appear on one origin.