FastAPI CORS Middleware — Configuring Cross-Origin Requests in Python Async APIs
In this tutorial, you will learn about FastAPI CORS Middleware. We cover key concepts, practical examples, and best practices to help you master this topic.
FastAPI provides built-in CORSMiddleware that handles CORS headers and preflight requests automatically, supporting origins, methods, headers, credentials, and expose headers configuration.
What You'll Learn
- Adding CORSMiddleware to FastAPI applications
- Configuring origins, methods, and headers
- Handling credentials and preflight Caching
Why It Matters
FastAPI's async nature makes it ideal for high-performance APIs. Proper CORS configuration ensures these APIs are accessible from browser-based clients. DodaTech uses FastAPI for its real-time threat detection API, serving both web and browser extension clients.
sequenceDiagram
participant Client as Browser
participant FastAPI as FastAPI Server
Client->>FastAPI: OPTIONS /api/threats
Client->>FastAPI: Origin: https://dashboard.dodatech.com
FastAPI-->>Client: 200 OK
FastAPI-->>Client: Access-Control-Allow-Origin: *
Client->>FastAPI: GET /api/threats (actual request)
FastAPI-->>Client: 200 OK (threat data)
Code Examples
# FastAPI CORS configuration
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = [
"https://dashboard.dodatech.com",
"https://admin.dodatech.com",
"https://partners.dodatech.com",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_headers=["Content-Type", "Authorization", "X-API-Key"],
expose_headers=["X-RateLimit-Remaining", "X-Request-ID"],
max_age=3600,
)
@app.get("/api/threats")
async def get_threats():
return {"threats": []}
# Allow all origins (development only)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
# Dynamic origins with validation
from fastapi import Request
@app.middleware("http")
async def dynamic_cors(request: Request, call_next):
response = await call_next(request)
origin = request.headers.get("origin")
if origin and origin in ALLOWED_ORIGINS:
response.headers["Access-Control-Allow-Origin"] = origin
return response
# Test FastAPI CORS
curl -I -H "Origin: https://dashboard.dodatech.com" \
http://localhost:8000/api/threats | grep -i "access-control"
# Test blocked origin
curl -I -H "Origin: https://evil.com" \
http://localhost:8000/api/threats | grep -i "access-control"
Common Mistakes
1. Using allow_origins=["*"] with allow_credentials=True
FastAPI enforces the same restriction: wildcard and credentials cannot coexist.
2. Forgetting to Add OPTIONS Method
CORSMiddleware handles OPTIONS automatically. Do not add custom OPTIONS handlers.
3. Not Handling CORS for Error Responses
CORSMiddleware only adds headers to successful responses. Use a custom middleware for error responses.
4. Exposing Too Many Origins in Development
Use allow_origins=["*"] in development but restrict in production.
5. Setting max_age Too Low in Production
Increase max_age to 3600+ seconds to reduce preflight overhead.
Practice Questions
- What class does FastAPI use for CORS?
- How do you allow multiple origins in FastAPI?
- Can you use allow_origins=["*"] with allow_credentials=True?
- How does FastAPI handle OPTIONS preflight requests?
- What parameter controls preflight caching duration?
Answers:
- CORSMiddleware from fastapi.middleware.cors.
- Pass a list of origin strings to allow_origins.
- No. This combination is blocked by the CORS specification.
- CORSMiddleware automatically intercepts OPTIONS requests and responds with appropriate CORS headers.
- max_age (in seconds).
Challenge: Build a FastAPI application with multiple route groups, each with different CORS requirements. Use middleware to apply different CORS configurations for public, authenticated, and admin routes. Add automated pytest tests that verify each endpoint's CORS headers.
FAQ
Mini Project
Build a FastAPI application with three tiers of endpoints: public (any origin), partner (validated partner origins), and internal (specific IP ranges). Implement CORS with custom middleware for dynamic origin validation, add request logging for CORS rejections, and create automated tests using httpx with custom Origin headers.
What's Next
Explore Django CORS configuration with django-cors-headers, then learn Spring Boot CORS with @CrossOrigin annotation.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro