# How CORS Middleware is Configured for Production in Open Notebook

> Learn how Open Notebook configures production CORS using the CORS_ORIGINS environment variable in api main.py. Understand the fallback and middleware order for secure API access.

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

---

**Open Notebook configures production CORS through a `CORS_ORIGINS` environment variable parsed at startup in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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:

```env
CORS_ORIGINS=https://notebook.example.com

```

For multiple origins, separate with commas:

```env
CORS_ORIGINS=https://notebook.example.com,https://admin.example.com

```

### Docker Compose Deployment

```yaml
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

```python
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_ORIGINS` variable, parsed at startup in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/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_headers` handler 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`](https://github.com/lfnovo/open-notebook/blob/main/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:

```env
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`](https://github.com/lfnovo/open-notebook/blob/main/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.