FastAPI’s CORS middleware is surprisingly simple to configure, but the devil is in the details when it comes to production readiness.

Let’s see it in action with a minimal FastAPI app:

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

app = FastAPI()

origins = [
    "http://localhost:3000",
    "https://your-frontend.com",
    "https://staging.your-frontend.com",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    allow_headers=["*"],
)

@app.get("/")
async def read_root():
    return {"message": "Hello, World!"}

@app.post("/items/")
async def create_item(item: dict):
    return item

When a browser makes a request from a different origin (e.g., http://localhost:3000 to http://localhost:8000), it first sends an OPTIONS request (a "preflight" request) to the server. The server’s response to this OPTIONS request tells the browser whether the actual request (e.g., a POST to /items/) is allowed.

The core problem FastAPI’s CORS middleware solves is enabling cross-origin requests, which are blocked by default by web browsers for security reasons. Without proper CORS configuration, your frontend running on one domain (or port) won’t be able to communicate with your backend API on another.

The key parameters for CORSMiddleware are:

  • allow_origins: A list of origins that are allowed to make requests. You can use "*" to allow all origins, but this is generally not recommended for production. Specific origins are safer.
  • allow_credentials: A boolean. If True, it allows cookies and authorization headers to be sent with cross-origin requests. If True, allow_origins cannot be ["*"]; you must specify actual origins.
  • allow_methods: A list of HTTP methods that are allowed. ["*"] allows all methods, but it’s better to be explicit.
  • allow_headers: A list of HTTP headers that are allowed. ["*"] allows all headers, but again, specificity is good. You’ll often need to include custom headers your frontend might send.

The mental model here is that the browser acts as a gatekeeper. For any cross-origin request, it first asks permission from the server using an OPTIONS request. The CORS headers in the server’s response (Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Allow-Credentials) are the server’s explicit instructions to the browser about what it’s allowed to do. FastAPI’s middleware automates the generation of these headers based on your configuration.

When you set allow_credentials=True, you’re telling the browser that the server is willing to accept credentials (like session cookies or API keys in headers) with cross-origin requests. This is crucial for authentication in many web applications. However, because of security implications, browsers enforce a strict rule: if allow_credentials is True, the Access-Control-Allow-Origin header must specify a concrete origin, not a wildcard ("*"). If you try to use allow_origins=["*"] and allow_credentials=True, the browser will reject the request because the Access-Control-Allow-Origin header cannot simultaneously be a wildcard and a specific origin.

One common pitfall is forgetting to include OPTIONS in allow_methods. The OPTIONS method is used for the preflight request itself. If it’s not allowed, the browser won’t even be able to send the preflight request, and thus, no actual requests will ever be made. Always ensure OPTIONS is present if you’re using allow_credentials=True or if you’re facing issues with preflight requests.

Another subtle point is how allow_headers interacts with allow_credentials. If your frontend sends custom headers (e.g., X-Requested-With, Authorization, or a custom X-API-Key), these must be explicitly listed in allow_headers or be covered by allow_headers=["*"]. If a custom header is sent and not allowed by the server’s CORS response, the browser will block the request, even if the origin and methods are permitted.

The next step to consider is how to manage CORS configurations across different environments (development, staging, production) and how to integrate this with your deployment strategy, potentially using a reverse proxy like Nginx.

Want structured learning?

Take the full Fastapi course →