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.
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:5173vshttp://127.0.0.1:5173(hostname differs)http://localhost:5173vshttps://localhost:5173(scheme differs)http://localhost:5173vshttp://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
- Add
CORSMiddlewarewith your frontend's exact origin. - Match the origin precisely — scheme, host, and port, no trailing slash.
- Using cookies/auth? List explicit origins; don't pair
"*"withallow_credentials=True. - Check server logs — a 500 masquerades as a CORS error.
- 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.
Stop reading, start building
This pairs with a hands-on BytExplorer course — do it on your own machine and actually keep the skill.