Managing CORS in Python REST APIs
Cross-Origin Resource Sharing (CORS) is a critical browser security mechanism that restricts client-side web applications from making HTTP requests to a domain different from the one serving the front end. In Python, managing CORS in RESTful APIs requires instructing the backend framework to send specific HTTP response headers that explicitly grant permission to external origins. This article explains how CORS functions at a protocol level and demonstrates how Python frameworks—primarily FastAPI, Flask, and Django—implement and handle cross-origin traffic effectively.
How CORS Works in RESTful APIs
CORS is enforced entirely by the client's web browser, not the server. When a web application attempts to fetch resources from a different domain, port, or protocol, the browser initiates a CORS handshake.
For complex HTTP methods (such as PUT,
DELETE, or POST with
application/json), the browser first issues an automated
preflight request using the OPTIONS method. The Python
backend must intercept this preflight request and respond with specific
access-control headers:
Access-Control-Allow-Origin: Specifies which external domains can access the resource (e.g.,https://example.comor*for public access).Access-Control-Allow-Methods: Identifies the allowed HTTP verbs (e.g.,GET, POST, PUT, DELETE, OPTIONS).Access-Control-Allow-Headers: Declares which HTTP request headers the client can send (e.g.,Authorization,Content-Type).Access-Control-Allow-Credentials: A boolean flag indicating whether the client may send cookies, authorization headers, or TLS certificates with the request.
If the backend does not return the appropriate headers, the browser blocks the incoming response from being read by the client application.
Managing CORS in FastAPI
FastAPI provides native, highly optimized support for CORS through
Starlette's built-in CORSMiddleware. Because it operates at
the ASGI middleware level, it automatically intercepts incoming
preflight OPTIONS requests before they reach your route
handlers.
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = [
"https://example.com",
"http://localhost:3000",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/api/data")
def read_data():
return {"status": "success"}Managing CORS in Flask
Flask does not support CORS out of the box. The standard approach is
to use the flask-cors package, a dedicated WSGI extension
that applies CORS headers globally or to specific routes and
blueprints.
from flask import Flask, jsonify
from flask_cors import CORS
app = Flask(__name__)
# Apply CORS globally to specific origins
CORS(app, resources={r"/api/*": {"origins": ["https://example.com", "http://localhost:3000"]}})
@app.route("/api/data", methods=["GET"])
def get_data():
return jsonify({"status": "success"})flask-cors automatically responds to preflight
OPTIONS requests for matching paths without requiring
dedicated route definitions.
Managing CORS in Django
In Django and Django REST Framework (DRF), CORS is best managed using
the third-party library django-cors-headers. This library
provides middleware that attaches the necessary headers directly to
outgoing Django HttpResponse objects.
Once installed, it is configured in settings.py:
INSTALLED_APPS = [
...,
"corsheaders",
"rest_framework",
]
MIDDLEWARE = [
"corsheaders.middleware.CorsMiddleware", # Must be placed as high as possible
"django.middleware.common.CommonMiddleware",
...,
]
# Specify allowed origins
CORS_ALLOWED_ORIGINS = [
"https://example.com",
"http://localhost:3000",
]
CORS_ALLOW_CREDENTIALS = TrueBest Practices for Production
- Avoid Wildcards with Sensitive Data: Using
allow_origins=["*"]allows any website to make requests to your API. Never pair a wildcard origin withAccess-Control-Allow-Credentials: true, as browsers will reject the response for security reasons. - Handle Preflight Caching: Configure the
Access-Control-Max-Ageheader (supported by all major Python CORS tools) to cache preflight responses in the browser, reducing unnecessaryOPTIONSround trips. - Position Middleware Correctly: Ensure CORS middleware is placed near the top of the middleware stack so it runs before authentication, logging, or error-handling components that might terminate the request early.