FastAPI Middleware: How to Handle Cross-Origin, Authentication, and Other Request Interceptions

FastAPI Middleware: Handling Cross-Origin and Authentication Request Interception

In web development, we often need to perform unified checks or processing on requests before they reach the backend logic. For example, verifying user permissions to access APIs or handling frontend cross-origin requests. FastAPI’s Middleware acts as an “interceptor” for such functionalities—it can modify, validate, or directly return responses before the request enters the application and after the response is returned to the client, allowing flexible control over the request lifecycle.

I. What is Middleware?

Middleware is a function that is called before a request reaches the route function (when entering the application) and after the response is returned to the client (when leaving the application). Think of it as a “checkpoint”: all requests must pass this checkpoint to proceed, and responses can be adjusted before being sent back.

Each middleware has two core functions:
1. Process Requests: Validate, modify, or intercept request data before it reaches the route.
2. Process Responses: Uniformly handle response data before it is sent back (e.g., adding CORS headers, modifying status codes).

The execution order of middleware is critical: Earlier-registered middleware executes first, and returns in reverse order (later-registered middleware executes first).

II. Handling Cross-Origin Requests (CORS)

When a frontend page (e.g., http://localhost:3000) calls a backend API (e.g., http://localhost:8000), browsers block cross-origin requests due to the “Same-Origin Policy” (when protocols, domains, or ports differ). To resolve this, the backend must configure Cross-Origin Resource Sharing (CORS) to allow specified frontend sources to access the API.

1. Install and Configure CORS Middleware

FastAPI uses CORSMiddleware to handle CORS. First, install dependencies if not already installed:

pip install fastapi uvicorn

Then configure the middleware in your code:

from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse

app = FastAPI()

# Configure CORS middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Allowed frontend origins; use "*" only in development
    allow_credentials=True,  # Allow cookies to be sent
    allow_methods=["*"],  # Allowed HTTP methods (GET/POST etc.)
    allow_headers=["*"],  # Allowed request headers
)

# Test route
@app.get("/api/hello")
async def hello():
    return {"message": "Hello, Cross-Origin!"}

2. Key Parameter Explanations

  • allow_origins: List of allowed frontend domains. In production, specify exact domains (e.g., ["https://your-frontend.com"]) to avoid security risks.
  • allow_methods: Allowed HTTP methods (e.g., ["GET", "POST"]); avoid "*" in production.
  • allow_headers: Allowed request headers (e.g., ["Authorization"]); include custom headers if needed (e.g., for tokens).

III. Authentication Interception: Verify User Identity

Many APIs require user authentication (e.g., checking tokens). Middleware can intercept all requests before they reach the route to verify permissions. If authentication fails, return a “401 Unauthorized” error immediately to block the request from entering the route function.

1. Dependencies vs. Middleware

  • Dependencies: More flexible, applied per route/function with explicit declaration.
  • Middleware: Global by default, no need to declare in each route; ideal for universal logic (e.g., global authentication checks).

Implement global token verification with middleware:

from fastapi import Request, HTTPException
from fastapi.security import OAuth2PasswordBearer

# Simulate token validation (use JWT in production)
def verify_token(token: str) -> bool:
    return token == "valid_token"

# Extract token from Authorization header (format: "Bearer {token}")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

# Define authentication middleware
class AuthMiddleware:
    async def __call__(self, request: Request, call_next):
        # 1. Get token from request headers
        auth_header = request.headers.get("Authorization")
        if not auth_header or not auth_header.startswith("Bearer "):
            raise HTTPException(status_code=401, detail="Invalid or missing token format")

        # 2. Extract token (remove "Bearer " prefix)
        token = auth_header.split(" ")[1]

        # 3. Validate token
        if not verify_token(token):
            raise HTTPException(status_code=401, detail="Token is invalid or expired")

        # 4. Proceed to next middleware/route
        response = await call_next(request)
        return response

# Add middleware to the app
app.add_middleware(AuthMiddleware)

# Protected route
@app.get("/api/protected")
async def protected_route():
    return {"message": "This is an authenticated API!"}

2. Testing

Use curl or Postman to test:

# Valid token (returns 200 OK)
curl -H "Authorization: Bearer valid_token" http://localhost:8000/api/protected

# Invalid token (returns 401 Unauthorized)
curl -H "Authorization: Bearer invalid_token" http://localhost:8000/api/protected

IV. Middleware Best Practices

  1. Execution Order: Multiple middleware execute in registration order; responses reverse this order. For example:
   app.add_middleware(Middleware1)
   app.add_middleware(Middleware2)

Requests flow through Middleware1Middleware2 → route; responses reverse to Middleware2Middleware1.

  1. Avoid Over-Interception: Keep middleware logic lightweight to prevent performance bottlenecks (e.g., avoid complex database operations).

  2. Scene Differentiation: Use middleware for universal logic (CORS, global auth); use dependencies for route-specific logic (e.g., granular permissions).

V. Summary

Middleware is a versatile tool in FastAPI for request interception, enabling cross-origin handling, global authentication, and logging. Use CORSMiddleware for cross-origin issues and custom middleware for global auth to build efficient, secure APIs.

Tips:
- Use allow_origins=["*"] for development, but replace with specific domains in production.
- Prioritize token validation in authentication middleware with clear error messages.

Start integrating middleware into your FastAPI projects to enhance API robustness!

Xiaoye