FastAPI CORS Error: 'No Access-Control-Allow-Origin' — How to Fix It

Your frontend calls your FastAPI backend and the browser blocks it with a CORS error. The API is fine — the browser is enforcing a rule your server hasn't opted into. The fix is one middleware.

BytExplorer 6 min read July 18, 2026

Your React or Vue app calls the API and the console lights up:

Access to fetch at 'http://localhost:8000/users' from origin
'http://localhost:5173' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.

Nothing is wrong with your endpoint — curl it and it works fine. CORS is a browser rule, not a server error. When JavaScript on one origin (localhost:5173) calls another origin (localhost:8000), the browser refuses to hand the response back to your code unless the server explicitly says that origin is allowed. FastAPI doesn't say that by default. You have to opt in.

The fix: add CORSMiddleware

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:5173"],   # your frontend's exact origin
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Restart the server. The middleware now adds the Access-Control-Allow-Origin header the browser is looking for, and the request goes through.

Cause: the origin doesn't match exactly

allow_origins is matched character-for-character. All of these are different origins to a browser:

  • http://localhost:5173 vs http://127.0.0.1:5173 (hostname differs)
  • http://localhost:5173 vs https://localhost:5173 (scheme differs)
  • http://localhost:5173 vs http://localhost:5173/ (a trailing slash — leave it off)

List the origin your frontend actually runs on. If you're not sure, it's the origin printed in the error message.

Cause: you used allow_origins=["*"] with credentials

You cannot combine the wildcard with cookies/auth:

allow_origins=["*"], allow_credentials=True   # ❌ browser rejects this combo

The spec forbids Access-Control-Allow-Origin: * when credentials are sent. Either list explicit origins with allow_credentials=True, or use * without credentials. Pick based on whether you send cookies/Authorization.

Cause: it's actually a 500, not CORS

A handler that crashes returns a 500 without the CORS headers, so the browser reports it as a CORS error — misleading you. Check your server logs. If there's a stack trace, fix that first; the "CORS error" disappears once the endpoint returns cleanly.

The checklist

  1. Add CORSMiddleware with your frontend's exact origin.
  2. Match the origin precisely — scheme, host, and port, no trailing slash.
  3. Using cookies/auth? List explicit origins; don't pair "*" with allow_credentials=True.
  4. Check server logs — a 500 masquerades as a CORS error.
  5. Remember CORS is browser-enforced: curl/Postman won't show the problem.

Frequently Asked Questions

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

Postman and curl don't enforce CORS — it's a rule browsers apply to protect users. So a request that works in Postman can still be blocked in the browser until the server sends the right Access-Control-Allow-Origin header.

Can I just set allow_origins to ["*"]?

Only if you're not sending credentials (cookies or Authorization headers). The CORS spec forbids the * wildcard together with credentials, so for authenticated apps you must list explicit origins.

Where should add_middleware go?

Right after you create the app = FastAPI() instance, before defining routes. Middleware applies to all routes, so its position among route definitions doesn't matter — but it must be registered on the app.

Put it into practice

Stop reading, start building

This pairs with a hands-on BytExplorer course — do it on your own machine and actually keep the skill.

More in Troubleshooting