Skip to content

FastAPI CORS Middleware — Configuring Cross-Origin Requests in Python Async APIs

DodaTech Updated 2026-06-28 3 min read

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

  1. What class does FastAPI use for CORS?
  2. How do you allow multiple origins in FastAPI?
  3. Can you use allow_origins=["*"] with allow_credentials=True?
  4. How does FastAPI handle OPTIONS preflight requests?
  5. What parameter controls preflight caching duration?

Answers:

  1. CORSMiddleware from fastapi.middleware.cors.
  2. Pass a list of origin strings to allow_origins.
  3. No. This combination is blocked by the CORS specification.
  4. CORSMiddleware automatically intercepts OPTIONS requests and responds with appropriate CORS headers.
  5. 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

Does FastAPI's CORSMiddleware handle all HTTP methods?

Yes. It handles OPTIONS preflight requests automatically and adds CORS headers to all response types including GET, POST, PUT, DELETE, and PATCH.

Can I use regular expressions for origins in FastAPI CORS?

No. FastAPI's CORSMiddleware requires exact origin strings. For pattern matching, implement a custom middleware that validates origins against regex patterns.

How do I add CORS headers to error responses in FastAPI?

Create a custom middleware that catches exceptions and adds CORS headers to the error response. The default CORSMiddleware only adds headers to successful responses.

What is the performance impact of CORSMiddleware?

Minimal. CORSMiddleware runs before your route handler and adds headers to the response. It adds less than 1ms to request processing time.

Does FastAPI support per-route CORS configuration?

Not directly. CORSMiddleware is applied globally. For per-route CORS, create a custom dependency or middleware that checks the route path and applies different configurations.

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