Skip to main content

CORS Policy Configuration

This project implements a flexible Cross-Origin Resource Sharing (CORS) policy to ensure secure communication between the frontend application and the FastAPI backend. The configuration is managed through the Settings class and applied via Starlette's CORSMiddleware.

Configuration Parameters

The CORS policy is primarily controlled by two settings in backend/app/core/config.py:

  • FRONTEND_HOST: A string representing the primary URL of the frontend application (e.g., http://localhost:5173). This host is always included in the allowed origins.
  • BACKEND_CORS_ORIGINS: A list or comma-separated string of additional origins allowed to make requests to the API.

These values are typically loaded from the .env file located at the project root:

FRONTEND_HOST="http://localhost:5173"
BACKEND_CORS_ORIGINS="http://localhost,https://example.com"

Origin Processing and Validation

To provide flexibility in how environment variables are defined, the project uses a custom validator and a computed property within the Settings class.

Flexible Parsing with parse_cors

The parse_cors function acts as a Pydantic BeforeValidator. It allows BACKEND_CORS_ORIGINS to be provided as either a standard Python list or a comma-separated string, which is common in environment variable configurations.

# backend/app/core/config.py

def parse_cors(v: Any) -> list[str] | str:
if isinstance(v, str) and not v.startswith("["):
return [i.strip() for i in v.split(",") if i.strip()]
elif isinstance(v, list | str):
return v
raise ValueError(v)

Aggregation via all_cors_origins

The Settings class uses a @computed_field property named all_cors_origins to consolidate all allowed origins into a single list. This property performs two critical tasks:

  1. Normalization: It strips trailing slashes from all origins in BACKEND_CORS_ORIGINS to prevent common configuration errors where a trailing slash might cause a CORS mismatch.
  2. Merging: It appends the FRONTEND_HOST to the list of origins.
# backend/app/core/config.py

@computed_field
@property
def all_cors_origins(self) -> list[str]:
return [str(origin).rstrip("/") for origin in self.BACKEND_CORS_ORIGINS] + [
self.FRONTEND_HOST
]

Middleware Implementation

The CORS policy is enforced in backend/app/main.py during the FastAPI application initialization. If all_cors_origins contains any entries, the CORSMiddleware is added to the application stack.

# backend/app/main.py

from starlette.middleware.cors import CORSMiddleware
from app.core.config import settings

# ... (FastAPI app initialization)

# Set all CORS enabled origins
if settings.all_cors_origins:
app.add_middleware(
CORSMiddleware,
allow_origins=settings.all_cors_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

Security Defaults

The middleware is configured with the following defaults:

  • allow_credentials=True: Supports cookies and authentication headers in cross-origin requests.
  • allow_methods=["*"]: Permits all standard HTTP methods (GET, POST, PUT, DELETE, etc.).
  • allow_headers=["*"]: Allows all headers to be sent in the request.

By centralizing these settings in app.core.config.Settings, the project ensures that CORS behavior is consistent across different environments (local, staging, production) while remaining easy to update via environment variables.