Skip to main content

Overview

CORS (Cross-Origin Resource Sharing) is a security mechanism that controls which domains can access your API. This guide explains the current CORS setup and how to configure it for production environments.

Current CORS Configuration

The API currently uses permissive CORS settings suitable for development:
main.py (lines 15-22)
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# 🔥 Permitir que React (localhost:3000) se conecte al backend
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 👈 en producción es mejor poner solo ["http://localhost:3000"]
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
Security Alert: The current configuration allows all origins (["*"]). This is acceptable for development but should be restricted in production.

CORS Parameters Explained

Current Value: ["*"]Description: List of origins (domains) allowed to access the APIWildcard (*): Allows requests from any domainSecurity Impact: High risk in production - allows anyone to call your API from any websiteRecommended: Specify exact domains in production
Current Value: TrueDescription: Whether to allow cookies and authentication headersWhen True:
  • Accepts cookies with requests
  • Allows Authorization headers
  • Enables session-based authentication
Note: Cannot be used with allow_origins=["*"] in browsers - must specify exact origins
Current Value: ["*"]Description: HTTP methods allowed for cross-origin requestsWildcard (*): Allows all methods (GET, POST, PUT, DELETE, PATCH, OPTIONS, etc.)Recommended: Specify only needed methods (e.g., ["GET", "POST"])
Current Value: ["*"]Description: HTTP headers allowed in cross-origin requestsWildcard (*): Allows all headersCommon Headers:
  • Content-Type
  • Authorization
  • Accept
  • Origin
Recommended: Specify only required headers

Production CORS Configuration

For production deployments, restrict CORS to specific trusted domains:
main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        "https://yourdomain.com",  # Production domain
    ],
    allow_credentials=True,
    allow_methods=["GET", "POST"],  # Only needed methods
    allow_headers=["Content-Type", "Authorization"],  # Only needed headers
)
This configuration:
  • Only allows requests from https://yourdomain.com
  • Enables credentials (cookies/auth)
  • Restricts to GET and POST methods
  • Limits headers to Content-Type and Authorization

Configuration by Use Case

Public API

Scenario: API available to any domain
allow_origins=["*"]
allow_credentials=False  # Must be False with "*"
allow_methods=["GET", "POST"]
allow_headers=["Content-Type"]
Only use for truly public APIs without authentication

Single Page Application

Scenario: React/Vue/Angular frontend
allow_origins=["https://app.example.com"]
allow_credentials=True
allow_methods=["GET", "POST", "PUT", "DELETE"]
allow_headers=["Content-Type", "Authorization"]

Mobile App Backend

Scenario: API for mobile applications
# CORS not needed for native mobile apps
# Mobile apps don't have CORS restrictions
# Use API keys or JWT tokens instead
Native mobile apps bypass CORS. Focus on authentication instead.

Internal Tools

Scenario: Admin dashboards and internal tools
allow_origins=[
    "https://admin.example.com",
    "https://internal.example.com"
]
allow_credentials=True
allow_methods=["*"]  # All methods for full admin access
allow_headers=["*"]

Testing CORS Configuration

Using cURL

Test CORS headers from command line:
Test Preflight Request
curl -i -X OPTIONS http://localhost:8000/process_excel \
  -H "Origin: https://yourdomain.com" \
  -H "Access-Control-Request-Method: POST" \
  -H "Access-Control-Request-Headers: Content-Type"
Expected Response Headers:
HTTP/1.1 200 OK
access-control-allow-origin: https://yourdomain.com
access-control-allow-methods: GET, POST
access-control-allow-headers: Content-Type, Authorization
access-control-allow-credentials: true

Using Browser Console

Test from browser’s JavaScript console:
// Replace with your API URL
fetch('http://localhost:8000/docs', {
  method: 'GET',
  credentials: 'include',
  headers: {
    'Content-Type': 'application/json'
  }
})
.then(response => response.text())
.then(data => console.log('Success:', data))
.catch(error => console.error('CORS Error:', error));

Common CORS Errors

Error Message:
Access to fetch at 'http://localhost:8000/process_excel' from origin 'http://localhost:3000' 
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present.
Cause: CORS middleware not configured or origin not in allowed listSolution:
  1. Verify CORS middleware is added to FastAPI app
  2. Check that requesting origin is in allow_origins list
  3. Ensure middleware is added before route definitions
Error Message:
The value of the 'Access-Control-Allow-Origin' header must not be the wildcard '*' 
when the request's credentials mode is 'include'.
Cause: Using allow_origins=["*"] with allow_credentials=TrueSolution:
  • Change allow_origins to specific domains, OR
  • Set allow_credentials=False
# Option 1: Specify origins
allow_origins=["http://localhost:3000"]
allow_credentials=True

# Option 2: Remove credentials
allow_origins=["*"]
allow_credentials=False
Error Message:
Method POST is not allowed by Access-Control-Allow-Methods
Cause: The HTTP method is not in allow_methods listSolution: Add the required method:
allow_methods=["GET", "POST", "PUT", "DELETE"]
Error Message:
Request header field authorization is not allowed by Access-Control-Allow-Headers
Cause: Custom header not in allow_headers listSolution: Add the required header:
allow_headers=["Content-Type", "Authorization", "X-Custom-Header"]

Security Best Practices

1

Never Use Wildcards in Production

Avoid allow_origins=["*"] in production environments.
allow_origins=["*"]
2

Restrict HTTP Methods

Only allow methods your API actually uses.
# If your API only has GET and POST endpoints:
allow_methods=["GET", "POST"]

# Don't allow all methods unless necessary:
# allow_methods=["*"]  ❌
3

Limit Headers

Specify only required headers.
# Most APIs only need these:
allow_headers=["Content-Type", "Authorization"]

# Add custom headers only if needed:
allow_headers=["Content-Type", "Authorization", "X-API-Key"]
4

Use HTTPS in Production

Always use HTTPS URLs in production allow_origins.
allow_origins=["http://yourdomain.com"]
5

Validate Origin Dynamically

For complex scenarios, validate origins programmatically:
main.py
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# List of allowed origin patterns
ALLOWED_ORIGIN_PATTERNS = [
    "https://yourdomain.com",
    "https://*.yourdomain.com",  # All subdomains
]

def is_origin_allowed(origin: str) -> bool:
    """Check if origin matches allowed patterns"""
    for pattern in ALLOWED_ORIGIN_PATTERNS:
        if pattern.endswith("*"):
            # Wildcard subdomain matching
            base = pattern.replace("*.", "")
            if origin.endswith(base):
                return True
        elif origin == pattern:
            return True
    return False

@app.middleware("http")
async def validate_cors_origin(request: Request, call_next):
    origin = request.headers.get("origin")
    if origin and is_origin_allowed(origin):
        response = await call_next(request)
        response.headers["Access-Control-Allow-Origin"] = origin
        response.headers["Access-Control-Allow-Credentials"] = "true"
        return response
    return await call_next(request)

Monitoring CORS Issues

Logging CORS Requests

Add logging to track CORS requests:
main.py
import logging
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = FastAPI()

@app.middleware("http")
async def log_cors_requests(request: Request, call_next):
    origin = request.headers.get("origin")
    if origin:
        logger.info(f"CORS request from origin: {origin}")
    response = await call_next(request)
    return response

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://yourdomain.com"],
    allow_credentials=True,
    allow_methods=["GET", "POST"],
    allow_headers=["Content-Type", "Authorization"],
)

Additional Resources

FastAPI CORS Guide

Official FastAPI CORS documentation

MDN CORS Guide

Comprehensive CORS reference

Docker Deployment

Configure CORS in Docker containers

API Reference

Test CORS with API endpoints

Quick Reference

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=False,
    allow_methods=["*"],
    allow_headers=["*"],
)

Build docs developers (and LLMs) love