“Has been blocked by CORS policy”: what your exact message means

Every CORS error starts the same way, but the part after the colon is different, and it tells you precisely which header is missing or wrong. Find your ending below. Each one has its own fix.

Access to fetch at 'https://api.example.com/users' from origin 'http://localhost:3000'
has been blocked by CORS policy: <this part is what matters>
Find your message
  1. No 'Access-Control-Allow-Origin' header is present
  2. Response to preflight request … does not have HTTP ok status
  3. must not be the wildcard '*' when the request's credentials mode is 'include'
  4. Request header field … is not allowed by Access-Control-Allow-Headers
  5. Method … is not allowed by Access-Control-Allow-Methods
  6. The 'Access-Control-Allow-Origin' header contains multiple values
  7. … has a value that is not equal to the supplied origin
  8. The value of 'Access-Control-Allow-Credentials' … must be 'true'
  9. Redirect is not allowed for a preflight request
  10. Cross origin requests are only supported for protocol schemes…
  11. The Firefox wording

First, one thing that applies to all of them: CORS is enforced by the browser, not the server. The request usually reached your API and it may even have run. The browser just won't let your JavaScript read the reply. That's why the same call works in curl or Postman. The fix almost always goes on the server that answered.

No 'Access-Control-Allow-Origin' header is present on the requested resource

The most common one. The response had no Access-Control-Allow-Origin at all. The server has to send it:

Access-Control-Allow-Origin: http://localhost:3000

If you already set it and still see this, check three things:

Response to preflight request doesn't pass access control check: It does not have HTTP ok status

Before a request with a JSON body, an Authorization header, or a method like PUT or DELETE, the browser sends an OPTIONS request to ask permission. Your server answered that with an error, usually:

Fix: let OPTIONS through before authentication and answer it with 204. In Express, register CORS before the auth middleware:

app.use(cors({ origin: "http://localhost:3000" }));  // answers OPTIONS itself
app.use(requireLogin);

This is the one no browser extension can fix, because the failure is the status code, not a missing header.

The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'

Your request sends cookies (credentials: "include" in fetch, withCredentials: true in axios) and the server said *. With cookies, the browser insists on the exact origin:

Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Credentials: true
Vary: Origin

If you need several origins, check the request's Origin against an allow-list and echo it back. Never echo any origin you receive, because that lets any website read your users' data with their cookies.

Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response

Your request sends a header (here Authorization, often Content-Type or an X- header) that the preflight answer didn't list. Add it:

Access-Control-Allow-Headers: Content-Type, Authorization

Method PUT is not allowed by Access-Control-Allow-Methods in preflight response

Same idea for the method. List every method the front end uses:

Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE

The 'Access-Control-Allow-Origin' header contains multiple values '…, …', but only one is allowed

Two layers are each adding the header: typically your app and nginx, or your app and a CDN rule. The browser sees two values and rejects both. Set it in exactly one place. You can't list several origins in one header either; echo the one that matched.

The 'Access-Control-Allow-Origin' header has a value 'https://example.com' that is not equal to the supplied origin

The server allows a different origin from the one you're on. Common causes: localhost vs 127.0.0.1, a missing port, http vs https, www. vs no www., or a trailing slash (https://example.com/ never matches, since origins have no path). Or a CDN cached a response that was made for another origin: add Vary: Origin.

The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'

You're sending cookies and the server allowed the origin but didn't say credentials are fine. Add Access-Control-Allow-Credentials: true, or stop sending credentials if the call doesn't need them.

Redirect is not allowed for a preflight request

The OPTIONS request got a 301 or 302, usually from http to https, or from adding or removing a trailing slash. Call the final URL directly so there is no redirect.

Cross origin requests are only supported for protocol schemes: http, data, … https

You opened your page as a file (file:///C:/project/index.html). Browsers won't let file pages fetch other files. Serve the folder instead:

npx serve .        # or
python3 -m http.server 8000

The Firefox wording

Firefox says the same things differently, with a reason code in brackets:

Firefox saysSame as
CORS header 'Access-Control-Allow-Origin' missingNo 'Access-Control-Allow-Origin' header
CORS preflight response did not succeedPreflight does not have HTTP ok status
Credential is not supported if the CORS header 'Access-Control-Allow-Origin' is '*'Wildcard with credentials
missing token 'authorization' in CORS header 'Access-Control-Allow-Headers'Header not allowed
CORS header 'Access-Control-Allow-Origin' does not matchNot equal to the supplied origin
Multiple CORS header 'Access-Control-Allow-Origin' not allowedMultiple values

When you can't change the server

A third-party API, a staging server someone else runs, or you just want to confirm CORS is the only problem before you file a ticket. You can add the missing headers to responses in your own browser, for one site only. Your users still need the server fix.

HeaderForge (Chrome, free)

When a request on the current tab is blocked by CORS, HeaderForge names the server that refused it and offers to allow CORS for that site in one click, and says plainly when the failure is a rejected preflight that headers can't fix. No account, no tracking.

Get HeaderForge for Chrome

To see exactly what a URL sends back to a cross-origin request, paste it into the free CORS tester. For the background, see what CORS is and the longer CORS error guide. On Firefox, see how to disable CORS in Firefox.

More on this topic: Access-Control-Allow-Origin: values, multiple origins and server examples · Preflight request (CORS OPTIONS): when it happens and how to fix it · How to disable CORS in Chrome (and the safer way to test) · TypeError: Failed to fetch — what it actually means, and how to tell which cause