apyhub
Cover illustration for What Is CORS and Why Is It Blocking My Request?
ApyHub

What Is CORS and Why Is It Blocking My Request?

What Is CORS and Why Is It Blocking My Request?

CORS is the browser refusing to let your JavaScript read a response from a different origin, because the server did not say it was allowed.

The two things people get wrong immediately:

Your server is not blocking you. The browser is. The request usually reaches the server and the server usually responds. The browser then refuses to hand that response to your code.

Only the browser enforces it. The same call from curl, Postman or your backend works fine. CORS is not a firewall. It is a rule browsers apply to protect users.

01Why It Exists

Without CORS, any website you visited could make authenticated requests to any other site using your cookies, and read the answers. Your bank, your email, your admin panel.

The same-origin policy blocks that by default. CORS is the mechanism a server uses to say "requests from this specific other origin are fine."

So CORS is not the restriction. The same-origin policy is the restriction. CORS is the way to relax it deliberately.

02What Counts as a Different Origin

An origin is scheme + host + port. All three must match, or it is cross-origin.

That last row is why nearly every developer meets CORS in their first week.

03The Preflight Request

The part that confuses people most is the request they never made.

For anything beyond a simple request, the browser first sends an OPTIONS request asking permission:

http

OPTIONS /api/users HTTP/1.1 Origin: https://app.example.com Access-Control-Request-Method: POST Access-Control-Request-Headers: content-type, authorization

The server must answer with what it allows:

http

HTTP/1.1 204 No Content Access-Control-Allow-Origin: https://app.example.com Access-Control-Allow-Methods: GET, POST, PUT, DELETE Access-Control-Allow-Headers: content-type, authorization Access-Control-Max-Age: 86400

Only then does the browser send the real request.

A request avoids preflight only if it uses GET, HEAD or POST, sends no custom headers, and uses a Content-Type of text/plain, multipart/form-data or application/x-www-form-urlencoded.

Which means sending Content-Type: application/json triggers a preflight. Almost every modern API call does.

04The Five Causes of a CORS Error

  1. The server sends no Access-Control-Allow-Origin header at all. The most common cause. Nothing is configured.
  2. The header is present but does not match your origin. Including a trailing slash mismatch, or http where you sent https.
  3. The preflight is not handled. The server returns 404 or 405 to OPTIONS because no route exists for it. Related: 405 Method Not Allowed.
  4. A header is not on the allow list. You send Authorization and the server never declared it in Access-Control-Allow-Headers.
  5. Credentials plus a wildcard. If you send cookies with credentials: 'include', the server cannot reply Access-Control-Allow-Origin: *. It must name your exact origin, and also send Access-Control-Allow-Credentials: true.

That last one catches people who "fixed" CORS with a wildcard and then added authentication.

05How To Fix It Properly

Configure the server. This is the only real fix. Set Access-Control-Allow-Origin to the origins you actually want, plus the methods and headers you accept. Every framework has middleware for it.

Do not use * in production if the API is authenticated. A wildcard means any website can call your API from a user's browser. Name your origins.

Handle OPTIONS explicitly. If your router does not answer preflight requests, nothing else you configure matters.

Set Access-Control-Max-Age. It tells the browser to cache the preflight result, so you are not doubling every request.

Use a proxy in development. Most dev servers can proxy /api to your backend, making everything same-origin locally. This removes the problem rather than working around it.

Do not use a browser extension that disables CORS. It fixes your machine and nobody else's, and it hides the problem until production.

06FAQ

What does a CORS error actually mean?

The browser blocked your JavaScript from reading a response from a different origin because the server did not send headers permitting it. The request usually succeeded; you are just not allowed to see the result.

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

Postman is not a browser and does not enforce the same-origin policy. CORS is a browser rule, so tools outside the browser are unaffected. This is normal and it means the server is fine.

What is a preflight request?

An automatic OPTIONS request the browser sends before the real one, asking the server which origins, methods and headers it permits. Any request with a custom header or Content-Type: application/json triggers one.

Can I fix CORS from the frontend?

No. The headers must come from the server. Anything that appears to fix it client-side is either a dev-server proxy, which is legitimate, or a browser extension, which is not a fix.

Is Access-Control-Allow-Origin: * safe?

For a public read-only API, generally yes. For an authenticated one, no. It also cannot be used at all with credentialed requests, where the server must name the exact origin.

Why does localhost:3000 get CORS errors calling localhost:8000?

Because an origin is scheme, host and port together. Different ports are different origins even on the same machine. Use a dev-server proxy or configure the backend to allow the frontend's origin.

Does CORS protect my API?

Not really. It protects your users' browsers from other websites making authenticated requests on their behalf. Anything not a browser ignores CORS entirely, so it is not access control. Use authentication for that.

07Related

Source: MDN: Cross-Origin Resource Sharing

08About ApyHub

ApyHub is a curated API catalog for developers, teams and AI agents: file conversion, data validation, OCR and extraction and more across 20 categories. One key covers all of it, every endpoint is MCP-ready so AI agents can discover and call them directly, and every service page has a playground for testing before you build.

EU-based and EU-hosted, which keeps data residency simple for teams with GDPR obligations.

Browse the catalog | Get a free API key - no credit card required.