How CORS Middleware is Configured for Production in Open Notebook
Open Notebook configures production CORS through a CORS_ORIGINS environment variable parsed at startup in api/main.py, falling back to a wildcard * if unset, with the middleware added last to ensure proper header injection on all responses including errors.
Open Notebook is a FastAPI-based application that uses CORSMiddleware to handle cross-origin requests. Understanding how CORS middleware is configured for production in Open Notebook ensures your deployment restricts API access to trusted front-end domains while maintaining full functionality for authenticated requests.
Parsing the Allowed Origins
At module import time, the application invokes _parse_cors_origins to process the CORS_ORIGINS environment variable. This helper converts the raw string into a Python list of permitted origins.
If CORS_ORIGINS is omitted, the system defaults to a wildcard ("*"), allowing any origin to access the API. The parsed result is stored in CORS_ALLOWED_ORIGINS, while a boolean flag CORS_IS_DEFAULT_WILDCARD tracks whether the fallback was activated.
Source: [api/main.py – lines 53‑64](https://github.com/lfnovo/open-notebook/blob/main/api/main.py#L53-L64)
Production Warning on Startup
When the server initializes, it checks CORS_IS_DEFAULT_WILDCARD. If true, a warning log message alerts the operator that the API is currently accepting requests from any origin, urging explicit configuration of CORS_ORIGINS with the production front-end URL(s).
Source: [api/main.py – lines 63‑70](https://github.com/lfnovo/open-notebook/blob/main/api/main.py#L63-L70)
Middleware Registration and Execution Order
The CORS middleware is added after the password authentication middleware but registered last in the FastAPI stack. Because FastAPI processes middleware in reverse order of addition, placing CORS last ensures it runs first on every request, guaranteeing that headers are injected before other layers execute.
The configuration permits credentials, allows all HTTP methods, and accepts any headers using the parsed CORS_ALLOWED_ORIGINS list.
Source: [api/main.py – lines 88‑95](https://github.com/lfnovo/open-notebook/blob/main/api/main.py#L88-L95)
Error Response Handling
A custom exception handler named _cors_headers mirrors Starlette’s native CORS logic to ensure error responses (4xx/5xx) include the appropriate Access-Control-Allow-Origin and related headers. Without this handler, browsers would block the error body when receiving responses from cross-origin requests due to missing CORS headers.
Source: [api/main.py – lines 66‑88](https://github.com/lfnovo/open-notebook/blob/main/api/main.py#L66-L88)
Production Configuration Examples
Configure your production environment by explicitly setting CORS_ORIGINS to your front-end domain(s).
Environment Variable Setup
For a single production domain:
CORS_ORIGINS=https://notebook.example.com
For multiple origins, separate with commas:
CORS_ORIGINS=https://notebook.example.com,https://admin.example.com
Docker Compose Deployment
services:
api:
image: ghcr.io/lfnovo/open-notebook:latest
env_file: .env
restart: unless-stopped
ports:
- "5055:5055"
depends_on:
- surrealdb
Programmatic Access to Configuration
import os
from api.main import CORS_ALLOWED_ORIGINS, CORS_IS_DEFAULT_WILDCARD
print("CORS enabled for:", CORS_ALLOWED_ORIGINS)
print("Using default wildcard?", CORS_IS_DEFAULT_WILDCARD)
Note: Changes to CORS_ORIGINS require an API restart because the origin list is cached at module import time.
Summary
- Environment-driven: CORS origins are defined solely via the
CORS_ORIGINSvariable, parsed at startup inapi/main.py. - Security fallback: An unset variable defaults to wildcard (
*), triggering a startup warning to prevent accidental open production deployments. - Middleware ordering: CORS is registered last so it executes first on the request stack, ensuring headers are present before authentication checks.
- Error coverage: The custom
_cors_headershandler guarantees CORS headers appear on 4xx/5xx responses, preventing browser blocking of error details. - Restart required: Updates to origin lists require an application restart due to import-time caching.
Frequently Asked Questions
What happens if I don't set CORS_ORIGINS in production?
If CORS_ORIGINS is unset, Open Notebook defaults to accepting requests from any origin (*). While this allows immediate connectivity, it exposes your API to cross-site request risks and triggers a warning log on startup. Production deployments should explicitly set this to the front-end URL.
Why is the CORS middleware added last in the stack?
FastAPI processes middleware in reverse order of registration. By adding CORSMiddleware last in api/main.py, it executes first on incoming requests and last on outgoing responses. This ensures CORS headers are injected before authentication middleware runs and before error responses are finalized.
How do I configure multiple allowed origins?
Separate multiple URLs with commas in the CORS_ORIGINS variable:
CORS_ORIGINS=https://app.example.com,https://staging.example.com
The _parse_cors_origins function splits this string into a list that the middleware uses for origin validation.
Does the CORS configuration affect error responses?
Yes. Without the custom _cors_headers exception handler implemented in api/main.py, error responses (4xx/5xx) would lack CORS headers, causing browsers to block the error body on cross-origin requests. The handler ensures all responses include proper Access-Control-Allow-Origin headers.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →