Python Cors Configuration Guide

Written by

in

Cross‑origin resource sharing (CORS) is a cornerstone of modern web development, allowing browsers to securely request resources from a different domain than the one that served the page. If you’re building APIs or web services with Python, mastering CORS configuration is essential to keep your applications both functional and safe. In this guide we’ll walk through the fundamentals of CORS, explore common pitfalls, and provide step‑by‑step instructions for configuring CORS in the most popular Python frameworks – Flask, Django, and FastAPI. By the end, you’ll have a ready‑to‑use template that you can drop into any project and instantly eliminate those dreaded “No ‘Access‑Control‑Allow‑Origin’ header” errors.

What Is CORS and Why Does It Matter?

CORS (Cross‑Origin Resource Sharing) is a browser security feature that restricts web pages from making requests to a different domain, protocol, or port unless the target server explicitly permits it. Without proper CORS headers, a client‑side JavaScript call to https://api.example.com from https://app.myfrontend.com will be blocked, resulting in confusing console errors and a broken user experience.

Key reasons to configure CORS correctly in your Python applications:

  • Security: Only trusted origins receive access to your API.
  • Flexibility: Enables integration with SPAs, mobile apps, and third‑party services.
  • Performance: Proper pre‑flight handling reduces unnecessary network round‑trips.

Core CORS Headers Explained

Understanding the headers you’ll be setting helps you fine‑tune your policy:

  • Access-Control-Allow-Origin – Specifies which origin(s) may access the resource. Use * for public APIs, or a specific domain for tighter security.
  • Access-Control-Allow-Methods – Lists HTTP methods (GET, POST, PUT, DELETE, etc.) that are allowed.
  • Access-Control-Allow-Headers – Indicates which custom headers (e.g., Authorization, Content-Type) can be sent by the client.
  • Access-Control-Allow-Credentials – When set to true, browsers expose cookies and HTTP authentication to the request.
  • Access-Control-Max-Age – Caches the pre‑flight response for a given number of seconds.

Configuring CORS in Flask

Flask is lightweight, which means you’ll usually add CORS support via an extension. The most popular choice is flask‑cors.

Step‑by‑Step Installation

  1. Install the package:
pip install flask-cors
  1. Import and wrap your Flask app:
from flask import Flask
from flask_cors import CORS

app = Flask(__name__)

# Allow all origins (use with caution in production)
CORS(app)

# OR restrict to specific origins
CORS(app, resources={
    r"/api/*": {"origins": ["https://myfrontend.com", "https://admin.myfrontend.com"]},
    r"/public/*": {"origins": "*"}
})

Fine‑Tuning the Policy

You can pass additional arguments to CORS() to control methods, headers, and credentials:

CORS(app,
     resources={r"/api/*": {"origins": "https://myfrontend.com"}},
     methods=["GET", "POST", "PUT", "DELETE"],
     allow_headers=["Content-Type", "Authorization"],
     supports_credentials=True,
     max_age=86400)

Remember to test your configuration with tools like Postman or the browser’s developer console to verify that the expected headers appear in the response.

Configuring CORS in Django

Django’s “batteries‑included” philosophy means you’ll typically add a dedicated middleware for CORS. The de‑facto standard is django‑cors‑headers.

Installation and Setup

  1. Install the package:
pip install django-cors-headers
  1. Add the middleware to settings.py:
# settings.py
INSTALLED_APPS = [
    ...,
    "corsheaders",
]

MIDDLEWARE = [
    "corsheaders.middleware.CorsMiddleware",  # must be placed as high as possible
    "django.middleware.common.CommonMiddleware",
    ...,
]

Basic Configuration

Allow all origins (development only):

CORS_ALLOW_ALL_ORIGINS = True

Restrict to a whitelist (production‑ready):

CORS_ALLOWED_ORIGINS = [
    "https://myfrontend.com",
    "https://admin.myfrontend.com",
]

Advanced Options

  • CORS_ALLOW_METHODS – Customize allowed HTTP verbs.
  • CORS_ALLOW_HEADERS – Add custom request headers.
  • CORS_ALLOW_CREDENTIALS = True – Enable cookies and HTTP authentication.
  • CORS_EXPOSE_HEADERS – List response headers that browsers may access.

Example of a tight policy:

CORS_ALLOWED_ORIGINS = [
    "https://myfrontend.com",
]

CORS_ALLOW_METHODS = [
    "GET",
    "POST",
    "OPTIONS",
]

CORS_ALLOW_HEADERS = [
    "content-type",
    "authorization",
]

CORS_ALLOW_CREDENTIALS = True
CORS_MAX_AGE = 86400

Configuring CORS in FastAPI

FastAPI builds on Starlette, which already includes a simple CORS middleware. No extra dependencies are required beyond FastAPI itself.

Adding the Middleware

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

app = FastAPI()

# Allow all origins (development only)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Production‑grade example
app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        "https://myfrontend.com",
        "https://admin.myfrontend.com",
    ],
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE"],
    allow_headers=["Authorization", "Content-Type"],
    max_age=86400,
)

Testing the FastAPI CORS Setup

Run the server with uvicorn main:app --reload and then issue a request from a different origin (e.g., using a simple HTML page with fetch()). Check the response headers in the browser’s network tab – you should see Access-Control-Allow-Origin and the other CORS headers you configured.

Common CORS Pitfalls and How to Avoid Them

  • Using * with credentials: Browsers reject Access-Control-Allow-Origin: * when Access-Control-Allow-Credentials: true. Always specify explicit origins if you need cookies or HTTP auth.
  • Forgetting pre‑flight handling: Complex requests (custom headers, non‑simple methods) trigger an OPTIONS pre‑flight. Ensure your server returns the appropriate CORS headers for OPTIONS requests.
  • Mismatched header names: Header names are case‑insensitive, but some libraries expect them in a specific case. Stick to the canonical Access-Control-* spelling.
  • Over‑permissive policies in production: Opening * to the world can expose your API to abuse. Adopt a whitelist and regularly audit allowed origins.

Testing and Debugging CORS

When troubleshooting CORS, follow this checklist:

  1. Inspect response headers: Use the browser’s developer tools (Network tab) to verify that Access-Control-Allow-Origin matches the requesting domain.
  2. Check the pre‑flight response: Look for a 200 OK to the OPTIONS request and ensure it includes Access-Control-Allow-Methods and Access-Control-Allow-Headers.
  3. Use curl for quick validation:
curl -i -X OPTIONS https://api.example.com/resource \
     -H "Origin: https://myfrontend.com" \
     -H "Access-Control-Request-Method: POST" \
     -H "Access-Control-Request-Headers: Authorization,Content-Type"

The output should contain the CORS headers you configured. If not, revisit your framework’s CORS settings.

Best Practices for Secure CORS in Python

  • Maintain a whitelist of trusted origins and avoid using * in production.
  • Limit allowed methods to

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *