# How CORS is Configured in the FastAPI Application: Open Notebook's Environment-Driven Approach

> Learn how to configure CORS in FastAPI applications using the environment-driven approach from Open Notebook. Dynamically set allowed origins or default to wildcard for flexibility.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: how-to-guide
- Published: 2026-06-12

---

**The Open Notebook API configures Cross-Origin Resource Sharing (CORS) through FastAPI's `CORSMiddleware`, dynamically reading allowed origins from the `CORS_ORIGINS` environment variable and falling back to a permissive wildcard (`"*"`) with security warnings when unset.**

The `lfnovo/open-notebook` repository implements a flexible, security-conscious CORS setup for its FastAPI backend. Located in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py), the configuration parses environment variables at startup to determine which origins can access the API, making it adaptable for both local development and production deployments.

## Environment-Driven Origin Configuration

At application startup, the code retrieves the raw CORS origins string from the environment and processes it through a parsing utility.

```python
_cors_origins_raw = os.getenv("CORS_ORIGINS")
CORS_ALLOWED_ORIGINS = _parse_cors_origins(_cors_origins_raw or "*")
CORS_IS_DEFAULT_WILDCARD = _cors_origins_raw is None

```

(see lines 62‑64 of [[`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py)](https://github.com/lfnovo/open-notebook/blob/main/api/main.py#L62-L64))

The `_parse_cors_origins` function converts the environment string into a list of allowed origins. When `CORS_ORIGINS` is undefined, the system defaults to `"*"`, enabling all origins but flagging this as a default configuration for security monitoring.

## Middleware Registration in api/main.py

After initializing the password authentication middleware, the application registers FastAPI's built-in `CORSMiddleware` with the computed origin list.

```python
app.add_middleware(
    CORSMiddleware,
    allow_origins=CORS_ALLOWED_ORIGINS,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

```

(see lines 88‑95 of [[`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py)](https://github.com/lfnovo/open-notebook/blob/main/api/main.py#L88-L95))

This configuration explicitly:
- **Allows credentials** to support cookie-based authentication
- **Permits all HTTP methods** (`"*"`) to enable RESTful operations
- **Accepts all headers** (`"*"`) for content-type flexibility

## Security Warnings and Default Behavior

The application includes explicit logging to warn administrators when running with the insecure wildcard default.

```python
if CORS_IS_DEFAULT_WILDCARD:
    logger.warning(
        "CORS_ORIGINS is not set — API accepts cross‑origin requests from any origin ..."
    )
else:
    logger.info(f"CORS allowed origins: {CORS_ALLOWED_ORIGINS}")

```

(see lines 63‑71 of [[`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py)](https://github.com/lfnovo/open-notebook/blob/main/api/main.py#L63-L71))

If `CORS_ORIGINS` is not set, the API logs a warning indicating it accepts cross-origin requests from any origin. This behavior facilitates local development but requires explicit configuration for production security.

## CORS Headers for Error Responses

Beyond the middleware, the application ensures CORS compliance for error responses through a dedicated `_cors_headers` helper function. This utility constructs proper `Access-Control-Allow-*` headers for custom exception handlers, ensuring that client browsers receive CORS headers even when the API returns error payloads.

(see lines 67‑88 of [[`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py)](https://github.com/lfnovo/open-notebook/blob/main/api/main.py#L67-L88))

This prevents cross-origin errors from masking actual API error messages, maintaining debuggability while preserving security boundaries.

## Practical Configuration Examples

Restrict CORS to specific domains in production:

```bash
export CORS_ORIGINS="https://notebook.example.com"
uv run uvicorn api.main:app --reload

```

For Docker or Docker Compose deployments:

```yaml
environment:
  - CORS_ORIGINS=https://notebook.example.com,https://app.example.com

```

To inspect the parsed origins at runtime:

```python
import os
from api.main import CORS_ALLOWED_ORIGINS
print("Allowed origins:", CORS_ALLOWED_ORIGINS)

```

## Summary

- **Environment-driven configuration**: The API reads `CORS_ORIGINS` from environment variables and parses it via `_parse_cors_origins` in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py).
- **Wildcard fallback**: When unset, defaults to `"*"` with logged warnings to alert developers of insecure configurations.
- **Permissive middleware**: Registers `CORSMiddleware` with `allow_credentials=True`, `allow_methods=["*"]`, and `allow_headers=["*"]`.
- **Error handling coverage**: Uses the `_cors_headers` helper to ensure CORS headers appear on error responses.

## Frequently Asked Questions

### What happens if CORS_ORIGINS is not set?

The API falls back to a wildcard (`"*"`) allowing all origins and logs a warning message. This facilitates local development but should never be used in production environments where explicit origin restrictions are required.

### Can I configure multiple allowed domains?

Yes. The `_parse_cors_origins` function accepts a comma-separated list or array-formatted string from the `CORS_ORIGINS` environment variable, converting it into a list of allowed origins for the middleware.

### Why are CORS headers needed for error responses?

Standard FastAPI middleware only processes successful responses. The `_cors_headers` helper ensures custom exception handlers include proper `Access-Control-Allow-*` headers, preventing browsers from blocking error payload visibility due to CORS policy violations.

### Does the CORS configuration allow authentication cookies?

Yes. The middleware explicitly sets `allow_credentials=True`, which permits browsers to send authenticated requests including cookies and authorization headers to the API.