FastAPI Advanced: Security, Async and Production
Middleware, CORS and Settings
In this lesson you will
- Write simple HTTP middleware
- Configure CORS with an explicit origin list
- Load configuration from environment variables
Introduction
Some behaviour applies to every request: timing, logging, security headers, browser access rules. Middleware handles these in one place. Configuration, such as secrets and URLs, should come from the environment and not from your code. This lesson covers both. All the outputs shown were produced by running the code.
Middleware
Middleware is a function that wraps each request: it can act before the endpoint, call it and then act on the response.
Python
import time
from fastapi import Request
@app.middleware("http")
async def add_timing(request: Request, call_next):
start = time.perf_counter()
response = await call_next(request) # run the endpoint
elapsed = time.perf_counter() - start
response.headers["X-Process-Time"] = f"{elapsed:.4f}"
return responseEvery response now carries an X-Process-Time header (I confirmed it was present). Use middleware for things like request IDs, logging and security headers. Keep it fast, because it runs on every request.
CORS
Browsers block a web page at one origin (for example https://app.example.com) from calling an API at another unless the API says it allows it. This rule is the same-origin policy, and the opt-in mechanism is CORS (cross-origin resource sharing). CORS protects browsers, not your API from other programs, so it is not a replacement for authentication.
Python
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["https://app.example.com"],
allow_methods=["GET", "POST"],
allow_headers=["Authorization"],
)I tested it with preflight requests, the browser's check before a real call:
OPTIONS /me Origin: https://app.example.com -> 200, allow-origin: https://app.example.com
OPTIONS /me Origin: https://evil.example -> 400, no allow-origin headerGuidance:
- List exact origins. Avoid
["*"](any origin) on APIs that use cookies or credentials. - Allow only the methods and headers you need.
- If you use cookies,
allow_credentials=Truerequires specific origins, not a wildcard. - During development you may allow
http://localhost:3000. Do not leave development origins in production.
Quick quiz
What does CORS protect?
Settings from the environment
Hard-coded secrets end up in repositories. Use environment variables and validate them at start-up with pydantic-settings.
Terminal
pip install pydantic-settingsPython
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
secret_key: str = "dev-only-change-me-dev-only-change-me"
token_minutes: int = 15
database_url: str = "sqlite:///library.db"
settings = Settings()Field names map to environment variables, case-insensitively. Setting SECRET_KEY=... and TOKEN_MINUTES=30 in the environment overrides the defaults, and values are converted to the declared type. If a value cannot be converted, the app fails at start-up with a clear error, which is better than failing later.
Tips:
- Defaults are for development only. In production, make secrets required by removing their defaults, so the app refuses to start without them.
- Keep a local
.envfile out of version control, and provide a.env.examplewith fake values. - Never log secrets.
- Use your host's secret store for production.
Other useful settings
- Turn off or protect the interactive docs in production if the API is private (
FastAPI(docs_url=None, redoc_url=None)). - Set explicit timeouts and limits at the proxy or server.
- Add security headers through your proxy or middleware.
Try it yourself
Add a middleware that adds an X-Request-ID header with a random UUID, and logs the path and status code. Move your secret key and token lifetime into a Settings class and run the app with TOKEN_MINUTES set differently.
Summary
- Middleware wraps every request and suits timing, logging and headers.
- CORS is a browser control: list exact allowed origins, methods and headers, and keep real authentication.
- Load settings and secrets from the environment with validation, and never commit secrets.
Lesson complete
+20 XP
Nice work. Keep going while it is fresh.
Sources and further reading