# How to Set Up Password Authentication Middleware for Production in Open Notebook

> Secure Open Notebook in production by setting OPEN_NOTEBOOK_PASSWORD. Learn to implement password authentication middleware for secure access via Authorization header.

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

---

**To secure Open Notebook in production, set the `OPEN_NOTEBOOK_PASSWORD` environment variable (or mount a Docker secret to `OPEN_NOTEBOOK_PASSWORD_FILE`) so that the `PasswordAuthMiddleware` requires an `Authorization: Bearer <password>` header on every request.**

Open Notebook (the `lfnovo/open-notebook` repository) provides a FastAPI-based HTTP API that runs without authentication in development for convenience. For production environments, you must enable the built-in password authentication middleware to protect sensitive notebook data. This configuration relies on the `PasswordAuthMiddleware` class defined in [`api/auth.py`](https://github.com/lfnovo/open-notebook/blob/main/api/auth.py) and registered in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) (lines 73‑86), which validates Bearer tokens against a secret you provide via environment variables or Docker secrets.

## How the Password Authentication Middleware Works

The middleware is instantiated in **[`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py)** and wraps the entire FastAPI application. When `OPEN_NOTEBOOK_PASSWORD` is present, every incoming request—except for a configured list of public paths—must include the header `Authorization: Bearer <password>` where `<password>` matches the configured secret. 

The middleware is deliberately added **before** the CORS middleware (see `app.add_middleware(PasswordAuthMiddleware, …)` in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py)). This ensures that unauthenticated requests are rejected before any cross-origin handling occurs, preventing unauthorized access from reaching your business logic. Excluded paths typically include health-check endpoints, OpenAPI documentation (`/docs`, `/redoc`), and internal status routes, allowing monitoring tools to reach the service without credentials.

## Configuring Production Secrets

The actual password value is retrieved via **`get_secret_from_env`** in [`open_notebook/utils/encryption.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/encryption.py) (lines 29‑59). This helper supports two secure input methods:

### Using Environment Variables

Set the secret directly in your shell or `.env` file:

```bash
export OPEN_NOTEBOOK_PASSWORD=SuperSecretProdPass

```

Restart the API process after setting this variable; the middleware reads the value once at startup.

### Using Docker Secrets

For Docker Swarm or Kubernetes deployments, store the password in a file and reference it via the `_FILE` suffix variable:

```bash

# Create the secret file

echo "SuperSecretProdPass" > ./secrets/open_notebook_password.txt

```

Then mount it as a secret and set `OPEN_NOTEBOOK_PASSWORD_FILE=/run/secrets/open_notebook_password` (or let Docker Compose handle the path automatically).

## Docker-Compose Configuration Example

Below is a production-ready [`docker-compose.yml`](https://github.com/lfnovo/open-notebook/blob/main/docker-compose.yml) that mounts the password as a Docker secret rather than exposing it in environment variables:

```yaml
services:
  api:
    image: lfnovo/open-notebook:latest
    env_file: .env.production          # contains CORS_ORIGINS, etc.

    secrets:
      - open_notebook_password
    ports:
      - "5055:5055"

secrets:
  open_notebook_password:
    file: ./secrets/open_notebook_password.txt

```

If you prefer environment variables over secret files, omit the `secrets:` section and add the variable directly to `env_file: .env.production`:

```dotenv
OPEN_NOTEBOOK_PASSWORD=SuperSecretProdPass
CORS_ORIGINS=https://notebook.example.com

```

## Client-Side Authentication

Once the middleware is active, all API clients must include the authorization header.

### Python Client Automatic Handling

The built-in client in **[`api/client.py`](https://github.com/lfnovo/open-notebook/blob/main/api/client.py)** automatically detects the `OPEN_NOTEBOOK_PASSWORD` environment variable and injects the header for you:

```python
import os
from api.client import OpenNotebookClient

# Ensure the password is visible to the process

os.environ["OPEN_NOTEBOOK_PASSWORD"] = "SuperSecretProdPass"

client = OpenNotebookClient(base_url="https://api.example.com")

# All subsequent requests include: Authorization: Bearer SuperSecretProdPass

```

### Manual Header Addition

For custom HTTP clients, add the header manually:

```python
headers = {
    "Authorization": "Bearer SuperSecretProdPass"
}
response = requests.get("https://api.example.com/api/notes", headers=headers)

```

## Fine-Grained Route Protection (Optional)

While the middleware protects all routes globally, you can also use the **`check_api_password`** dependency from [`api/auth.py`](https://github.com/lfnovo/open-notebook/blob/main/api/auth.py) for fine-grained control within specific route handlers:

```python
from fastapi import APIRouter, Depends, HTTPException
from api.auth import check_api_password

router = APIRouter()

@router.get("/admin/status")
async def admin_status(auth_ok: bool = Depends(check_api_password)):
    if not auth_ok:
        raise HTTPException(status_code=401, detail="Unauthorized")
    return {"msg": "All systems nominal"}

```

This dependency is rarely necessary because the middleware already enforces authentication, but it is available for specialized access control logic.

## Summary

- **Enable authentication** by setting `OPEN_NOTEBOOK_PASSWORD` or mounting a file to `OPEN_NOTEBOOK_PASSWORD_FILE`; the middleware reads this at process start via `get_secret_from_env` in [`open_notebook/utils/encryption.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/encryption.py).
- **Restart required**: The API does not hot-reload secrets; you must restart the container after changing the password.
- **Public endpoints**: Health checks and OpenAPI documentation remain accessible without authentication, as configured in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py).
- **Client compatibility**: The provided `OpenNotebookClient` in [`api/client.py`](https://github.com/lfnovo/open-notebook/blob/main/api/client.py) automatically handles header injection when the environment variable is present.
- **Request order**: Authentication is enforced before CORS processing, ensuring rejected requests never trigger cross-origin logic.

## Frequently Asked Questions

### What happens if I don't set OPEN_NOTEBOOK_PASSWORD in production?

If the environment variable and secret file are both absent, `PasswordAuthMiddleware` allows all requests unrestricted access. This behavior is intended for local development only; production deployments must explicitly provide the secret to enable protection.

### Can I use multiple passwords or user accounts with this middleware?

No, the current implementation in [`api/auth.py`](https://github.com/lfnovo/open-notebook/blob/main/api/auth.py) supports only a single master password. It is a simple shared-secret model rather than a multi-user authentication system. For multi-user scenarios, you would need to implement a custom authentication layer or place Open Notebook behind an authenticating reverse proxy.

### How do I rotate the production password without downtime?

You must perform a rolling restart of your API containers. Because `get_secret_from_env` reads the password once at process startup (in [`open_notebook/utils/encryption.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/encryption.py)), changes to the underlying secret file or environment variable are not detected until the process restarts. Update the secret, then restart containers one by one if running a cluster.

### Are WebSocket connections also protected by this middleware?

Yes, the `PasswordAuthMiddleware` processes all HTTP requests, including WebSocket upgrade requests. Clients must include the `Authorization: Bearer <password>` header when establishing the WebSocket connection, or the middleware will reject the handshake before it reaches the application code.