---
title: "What Is CORS and Why Is It Blocking My Request?"
url: https://apyhub.com/blog/what-is-cors-and-why-is-it-blocking-my-request
author: ApyHub
published: 2026-09-09T08:27:29.340392Z
---

# 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.

## Why 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.

## What Counts as a Different Origin

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

| From                    | To                           | Same origin?       |
| ----------------------- | ---------------------------- | ------------------ |
| https://app.example.com | https://app.example.com/api  | Yes                |
| https://app.example.com | http://app.example.com       | No, scheme differs |
| https://app.example.com | https://api.example.com      | No, host differs   |
| https://app.example.com | https://app.example.com:8080 | No, port differs   |
| http://localhost:3000   | http://localhost:8000        | No, port differs   |

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

## The 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.

## The 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](https://apyhub.com/blog/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.

## How 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.

## FAQ

### 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.

## Related

* [405 Method Not Allowed](https://apyhub.com/blog/405-method-not-allowed) - what happens when OPTIONS is not handled
* [What Is a Bearer Token?](https://apyhub.com/blog/what-is-a-bearer-token) - the header that most often triggers a preflight
* [API Fundamentals](https://apyhub.com/blog/api-fundamentals-what-an-api-is-and-how-to-use-one-without-writing-code) - requests, headers and responses from scratch

Source: [MDN: Cross-Origin Resource Sharing](https://developer.mozilla.org/docs/Web/HTTP/CORS)

***

## About ApyHub

[ApyHub](https://apyhub.com/) is a curated API catalog for developers, teams and AI agents: [file conversion](https://apyhub.com/catalog/file-conversion), [data validation](https://apyhub.com/catalog/data-validation), [OCR and extraction](https://apyhub.com/catalog/artificial-intelligence) and more across 20 categories. One key covers all of it, every endpoint is [MCP-ready](https://apyhub.com/mcp) 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**](https://apyhub.com/catalog) | [**Get a free API key**](https://apyhub.com/auth/signup) - no credit card required.
