# How Open Notebook's CORS Middleware Adapts to Production and Development Environments

> Learn how Open Notebook's CORS middleware smartly adapts to production and development environments by checking the CORS_ORIGINS environment variable for secure or permissive access.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: internals
- Published: 2026-07-04

---

**Open Notebook's FastAPI application dynamically configures Cross-Origin Resource Sharing (CORS) by checking the `CORS_ORIGINS` environment variable, automatically defaulting to a permissive wildcard (`*`) for local development while enforcing strict origin restrictions in production when specific domains are configured.**

The `lfnovo/open-notebook` repository implements an intelligent CORS middleware configuration that seamlessly transitions between development and deployment environments. By leveraging environment variable detection in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py), the application eliminates manual code changes when moving from local testing to production servers. This approach ensures developers can immediately run frontend and backend on separate ports during development while maintaining security best practices in live deployments.

## Parsing the CORS_ORIGINS Environment Variable

At module load time, the application parses the `CORS_ORIGINS` environment variable using the helper function `_parse_cors_origins` defined in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py). This function converts a comma-separated string into a list of allowed origins, defaulting to a wildcard (`"*"`) when the variable is absent.

The implementation tracks whether the default was applied using the `CORS_IS_DEFAULT_WILDCARD` flag:

```python

# api/main.py (lines 54-66)

def _parse_cors_origins(raw: str) -> list[str]:
    """Parse CORS_ORIGINS env value into a list of origins."""
    ...

_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

```

When `_cors_origins_raw` is `None`, the `CORS_IS_DEFAULT_WILDCARD` boolean evaluates to `True`, signaling that the application is running in development mode without explicit origin restrictions.

## Development Mode: Permissive Wildcard Configuration

When `CORS_ORIGINS` is not set, the application logs a startup warning to inform developers that the API accepts cross-origin requests from any origin. This configuration supports common local development workflows where the frontend runs on `http://localhost:3000` and the API on `http://localhost:5055`.

The startup logic in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) (lines 212-221) handles this detection:

```python
if CORS_IS_DEFAULT_WILDCARD:
    logger.warning(
        "CORS_ORIGINS is not set — API accepts cross-origin requests from any "
        "origin (default: '*'). For production deployments, set CORS_ORIGINS to "
        "your frontend origin(s), e.g. CORS_ORIGINS=https://notebook.example.com"
    )
else:
    logger.info(f"CORS allowed origins: {CORS_ALLOWED_ORIGINS}")

```

This warning ensures developers are aware of the permissive configuration before deploying to production environments.

## Production Mode: Strict Origin Validation

Setting the `CORS_ORIGINS` environment variable triggers production mode, where the middleware restricts cross-origin requests to explicitly declared domains. Multiple origins are supported via comma-separated values.

In [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) (lines 237-244), the FastAPI `CORSMiddleware` is instantiated with the parsed origin list:

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

```

**Configuration example for production:**

```bash

# .env (production)

CORS_ORIGINS=https://app.example.com,https://admin.example.com
FASTAPI_PORT=5055

```

When the server starts with this configuration, it logs the specific allowed origins instead of the wildcard warning:

```

2024-07-04 12:00:00.000 | INFO | CORS allowed origins: ['https://app.example.com', 'https://admin.example.com']

```

## Error Handling with CORS Compliance

The application includes a custom exception handler that augments every error response with appropriate CORS headers. This ensures that even failed requests respect the same-origin policy, preventing browsers from blocking error details due to missing CORS headers on 4xx or 5xx responses.

This handler is implemented in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) (lines 247-263) and operates independently of the middleware to ensure consistent header application across all response paths.

## Summary

Open Notebook's CORS middleware adapts to different environments through the following key mechanisms:

- **Environment variable detection**: The `CORS_ORIGINS` variable toggles between development and production modes without code changes.
- **Automatic wildcard fallback**: Missing configuration defaults to `*` for development convenience, with clear logging warnings.
- **Strict origin enforcement**: Explicit comma-separated origins in production restrict access to declared domains only.
- **Consistent header application**: Custom error handling ensures CORS headers are present even on failed requests.

## Frequently Asked Questions

### What happens if I don't set CORS_ORIGINS in my environment?

If `CORS_ORIGINS` is not set, the application defaults to allowing requests from any origin (`*`). It logs a warning at startup indicating that the API accepts cross-origin requests from any origin, which is suitable for local development but not recommended for production deployments.

### How do I configure multiple allowed origins for production?

Set the `CORS_ORIGINS` environment variable to a comma-separated list of URLs without spaces. For example: `CORS_ORIGINS=https://app.example.com,https://admin.example.com`. The `_parse_cors_origins` function in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) splits this string into a list passed to the FastAPI `CORSMiddleware`.

### Why does the API require `allow_credentials=True` when using specific origins?

The `allow_credentials=True` setting in the `CORSMiddleware` configuration (line 239) enables cookies and authorization headers to be included in cross-origin requests. When combined with a specific `CORS_ORIGINS` list rather than a wildcard, this allows secure authentication flows between your frontend and API while maintaining origin restrictions.

### How does the custom error handler ensure CORS compliance?

According to the implementation in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) (lines 247-263), the custom exception handler adds CORS headers to error responses that might otherwise lack them. This prevents browsers from blocking error details due to CORS policy violations when requests fail authentication or validation, ensuring frontend applications can properly handle error messages from the API.