Python Cors Configuration Guide

Written by

in

Cross‑Origin Resource Sharing (CORS) is a critical security feature that browsers enforce to protect users from malicious websites. If you’ve ever built a Python API and struggled with “blocked by CORS policy” errors, you’re not alone. This guide walks you through everything you need to know to configure CORS correctly in popular Python frameworks such as Flask, Django, and FastAPI. By the end, you’ll have a solid, SEO‑friendly understanding of how to enable safe cross‑origin requests, avoid common pitfalls, and keep your applications both functional and secure.

What is CORS and Why It Matters in Python Web Apps

CORS is a set of HTTP headers that tells browsers whether a web page from origin A (e.g., https://example.com) is allowed to request resources from origin B (e.g., https://api.example.com). Without proper CORS configuration, browsers will block these requests, leading to frustrating errors for developers and users alike.

How Browsers Enforce CORS

  • Simple requests: Browsers automatically add an Origin header and expect an Access-Control-Allow-Origin response.
  • Preflight requests: For methods like PUT or custom headers, browsers send an OPTIONS request first to verify permissions.
  • Credentials: Cookies, HTTP authentication, and client‑side SSL certificates require the Access-Control-Allow-Credentials header.

When your Python server fails to include the correct headers, the browser halts the request, and you see the dreaded “CORS policy” error in the console.

Common Python Frameworks and Their CORS Solutions

Flask with Flask‑CORS

Flask is lightweight, making it a favorite for micro‑services. The Flask‑CORS extension adds the necessary headers with minimal code.

Django with django‑cors‑headers

Django’s “batteries‑included” philosophy means you often need a dedicated middleware like django‑cors‑headers to handle CORS across all apps.

FastAPI with Starlette’s CORS middleware

FastAPI, built on Starlette, includes a built‑in CORS middleware that’s both fast and type‑safe, perfect for modern async APIs.

Step‑by‑Step CORS Configuration for Each Framework

Installing the Required Packages

# Flask
pip install Flask-CORS

# Django
pip install django-cors-headers

# FastAPI
pip install fastapi[all]   # includes starlette

Configuring Flask

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)

# Basic configuration – allow all origins (not recommended for production)
CORS(app)

# Fine‑grained control
CORS(app, resources={
    r"/api/*": {
        "origins": ["https://example.com", "https://admin.example.com"],
        "methods": ["GET", "POST", "PUT", "DELETE"],
        "allow_headers": ["Content-Type", "Authorization"],
        "supports_credentials": True
    }
})

@app.route("/api/data")
def data():
    return {"message": "CORS configured!"}

Key points:

  • Use the resources dict to limit CORS to specific routes.
  • Set supports_credentials=True only when you truly need cookies or auth headers.

Configuring Django

First, add the middleware and app to settings.py:

# settings.py
INSTALLED_APPS = [
    # …
    "corsheaders",
    # …
]

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

# Allow specific origins
CORS_ALLOWED_ORIGINS = [
    "https://example.com",
    "https://app.example.com",
]

# Optional: restrict methods and headers
CORS_ALLOW_METHODS = [
    "GET",
    "POST",
    "PUT",
    "PATCH",
    "DELETE",
]

CORS_ALLOW_HEADERS = [
    "content-type",
    "authorization",
    "x-requested-with",
]

# Enable credentials if needed
CORS_ALLOW_CREDENTIALS = True

Remember to restart the Django server after updating settings.py.

Configuring FastAPI

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

app = FastAPI()

origins = [
    "https://example.com",
    "https://dashboard.example.com",
]

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

@app.get("/items/")
async def read_items():
    return {"message": "CORS is active!"}

FastAPI’s middleware approach makes it easy to toggle CORS on or off per deployment environment.

Advanced CORS Settings and Best Practices

Limiting Origins and Methods

Never use a wildcard (*) in production. Instead, maintain a whitelist of trusted domains. This reduces the attack surface and prevents accidental data leakage.

  • Origins: Use exact scheme, host, and port (e.g., https://api.example.com:443).
  • Methods: Only enable HTTP verbs your API truly supports.
  • Headers: Restrict to the minimal set required for your client.

Handling Credentials Securely

If Access-Control-Allow-Credentials is set to true, the Access-Control-Allow-Origin header cannot be a wildcard. Always pair them with a specific origin list. Additionally, consider the following security measures:

  1. Set SameSite=Lax or Strict on cookies to mitigate CSRF.
  2. Use HTTPS everywhere to protect authentication tokens.
  3. Implement short‑lived JWTs instead of long‑lived session cookies.

Testing CORS with Browser DevTools and Curl

Before deploying, verify your headers:

  • Browser: Open the Network tab, inspect the request, and look for Access-Control-Allow-* headers in the response.
  • Curl example:
curl -i -X OPTIONS https://api.example.com/data \
  -H "Origin: https://example.com" \
  -H "Access-Control-Request-Method: POST" \
  -H "Access-Control-Request-Headers: Authorization,Content-Type"

The response should include Access-Control-Allow-Origin, Access-Control-Allow-Methods, and any other headers you configured.

Frequently Asked Questions

Can I disable CORS completely?

Disabling CORS (Access-Control-Allow-Origin: * with no restrictions) is only safe for public APIs that do not rely on cookies or authentication. For private or user‑specific data, always enforce a strict whitelist.

How to allow subdomains?

Most libraries accept regular expressions or dynamic checks. For Flask‑CORS:

CORS(app, resources={r"/api/*": {"origins": r"https?://.*\.example\.com"}})

In Django, you can compute CORS_ALLOWED_ORIGINS at runtime based on ALLOWED_HOSTS.

What about WebSockets?

WebSockets use the Upgrade header, not standard CORS. However, browsers still enforce the same origin policy. In FastAPI, you can set allow_origins in the WebSocket route decorator, and in Django Channels you can configure allowed_hosts similarly.

Conclusion

Proper CORS configuration is a cornerstone of modern Python web development. By selecting the right library for your framework—Flask‑CORS, django‑cors‑headers, or FastAPI’s built‑in middleware—you can tailor cross‑origin permissions to your exact security requirements. Remember to whitelist trusted origins

Comments

Leave a Reply

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