# Implementing API Authentication for Open Notebook: A Complete Technical Guide

> Learn to implement API authentication for Open Notebook using Bearer tokens and FastAPI middleware. Secure your REST API by reading passwords from environment variables for every request.

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

---

**Open Notebook secures its REST API using a Bearer token authentication scheme that reads the password from environment variables and validates every request through FastAPI middleware.**

Open Notebook provides a configurable authentication layer for its REST API that can be toggled on or off through environment configuration. The system implements a password-based Bearer token scheme using three core components: a secret retrieval utility, a FastAPI middleware interceptor, and a status endpoint for client discovery. This architecture allows developers to secure deployments with a single environment variable while maintaining flexibility for local development.

## How Password-Based Authentication Works in Open Notebook

The authentication flow centers on the `PasswordAuthMiddleware` class defined in [`api/auth.py`](https://github.com/lfnovo/open-notebook/blob/main/api/auth.py), which intercepts incoming requests before they reach route handlers. When a password is configured, the middleware enforces Bearer token validation on all routes except an explicit whitelist.

### Environment-Based Password Retrieval

The system reads the API password from the environment using the `get_secret_from_env` function located in [`open_notebook/utils/encryption.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/encryption.py). This utility supports both plain environment variables and Docker secrets through a dual-path lookup strategy.

```python

# open_notebook/utils/encryption.py

def get_secret_from_env(var_name: str) -> Optional[str]:
    file_path = os.environ.get(f"{var_name}_FILE")
    if file_path:
        # Read secret from Docker secret file

        ...
    return os.environ.get(var_name)

```

The function first checks for a file path specified by `${VAR}_FILE` (e.g., `OPEN_NOTEBOOK_PASSWORD_FILE`). If the file exists and contains a non-empty string, it reads the password from that location; otherwise, it falls back to the standard environment variable `OPEN_NOTEBOOK_PASSWORD`. This pattern applies to both the API password and the encryption key (`OPEN_NOTEBOOK_ENCRYPTION_KEY`).

### The PasswordAuthMiddleware Implementation

The `PasswordAuthMiddleware` class in [`api/auth.py`](https://github.com/lfnovo/open-notebook/blob/main/api/auth.py) (lines 12-75) implements the request interception logic. It performs the following validation sequence for every incoming request:

1. **Early bypass**: If no password is configured (`self.password` is falsy), the middleware allows all requests to pass through, making the API public.
2. **Whitelist checking**: Routes like `/`, `/health`, `/docs`, and `/api/auth/status` are exempt from authentication.
3. **CORS preflight**: `OPTIONS` requests are allowed without tokens to handle browser preflight checks.
4. **Header validation**: Extracts the `Authorization` header, enforces the `Bearer` scheme, and compares the token to the stored password.
5. **Failure response**: Returns HTTP 401 with a `WWW-Authenticate: Bearer` header when validation fails.

### FastAPI Integration and OpenAPI Documentation

In [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) (lines 73-88), the middleware is mounted early in the application stack using `app.add_middleware(PasswordAuthMiddleware, ...)`. The registration occurs **before** the CORS middleware to ensure that authentication failures still include proper CORS headers.

The system also defines a reusable security scheme using `security = HTTPBearer(auto_error=False)` in [`api/auth.py`](https://github.com/lfnovo/open-notebook/blob/main/api/auth.py). When routes include `Depends(security)`, FastAPI renders an "Authorize" button in the Swagger UI, enabling interactive testing with Bearer tokens. The `check_api_password` dependency offers the same validation logic for routes that need per-endpoint checks instead of global middleware.

## Configuring API Authentication in Your Environment

Setting up authentication requires configuring the password through environment variables or Docker secrets.

### Setting the Password Variable

Define the `OPEN_NOTEBOOK_PASSWORD` environment variable before starting the application:

```bash
export OPEN_NOTEBOOK_PASSWORD=my-secure-password

```

If this variable is undefined, the middleware bypasses authentication entirely, which is useful for local development but should never be used in production.

### Using Docker Secrets

For containerized deployments, provide the password via Docker secrets by setting `OPEN_NOTEBOOK_PASSWORD_FILE` to point to the secret file:

```yaml

# docker-compose.yml example

secrets:
  api_password:
    file: ./secrets/api_password.txt

environment:
  - OPEN_NOTEBOOK_PASSWORD_FILE=/run/secrets/api_password

```

The `get_secret_from_env` function automatically detects and reads the file content, prioritizing the secret file over the environment variable when present.

## Making Authenticated API Requests

Once authentication is enabled, clients must include the Bearer token in the `Authorization` header for all protected routes.

### Checking Authentication Status

The `/api/auth/status` endpoint in [`api/routers/auth.py`](https://github.com/lfnovo/open-notebook/blob/main/api/routers/auth.py) (lines 13-23) allows clients to discover whether authentication is required:

```bash
curl http://localhost:5055/api/auth/status | jq .

```

A configured server returns:

```json
{
  "auth_enabled": true,
  "message": "Authentication is required"
}

```

When `auth_enabled` is `false`, clients may omit the `Authorization` header entirely.

### Client Implementation Examples

For command-line testing with curl:

```bash

# Export the password

export OPEN_NOTEBOOK_PASSWORD=my-secret

# Access a protected route (e.g., list notebooks)

curl -H "Authorization: Bearer $OPEN_NOTEBOOK_PASSWORD" \
     http://localhost:5055/api/notebooks

```

For Python applications using `httpx`:

```python
import httpx
import os

BASE_URL = "http://localhost:5055"
TOKEN = os.getenv("OPEN_NOTEBOOK_PASSWORD")

async def list_notebooks():
    async with httpx.AsyncClient(base_url=BASE_URL) as client:
        resp = await client.get(
            "/api/notebooks",
            headers={"Authorization": f"Bearer {TOKEN}"}
        )
        resp.raise_for_status()
        return resp.json()

```

## Security Best Practices for Production

When deploying Open Notebook in production environments, follow these security guidelines:

- **Set a strong password** via the environment or Docker secret; leaving it unset makes the API public.
- **Use Docker secrets** rather than plain environment variables to prevent password leakage through process listings and logs.
- **Restrict the whitelist** in `PasswordAuthMiddleware` only to endpoints that truly require public access (health checks and documentation).
- **Enable TLS/HTTPS** when exposing the API publicly to protect the Bearer token in transit.
- **Avoid hard-coding** credentials in source code or version control; always use the `${VAR}_FILE` pattern for sensitive configuration.

## Summary

- **Password retrieval** uses `get_secret_from_env` in [`open_notebook/utils/encryption.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/encryption.py) to support both environment variables and Docker secrets (`OPEN_NOTEBOOK_PASSWORD_FILE`).
- **Request validation** is handled by `PasswordAuthMiddleware` in [`api/auth.py`](https://github.com/lfnovo/open-notebook/blob/main/api/auth.py), which intercepts all requests and validates `Bearer` tokens against the configured password.
- **Public routes** including `/health`, `/docs`, and `/api/auth/status` are whitelisted and accessible without authentication.
- **FastAPI integration** occurs in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) where the middleware is mounted before CORS processing to ensure proper header handling.
- **Client authentication** requires sending `Authorization: Bearer <password>` headers, with the `/api/auth/status` endpoint available to check if authentication is active.

## Frequently Asked Questions

### How do I enable API authentication in Open Notebook?

Set the `OPEN_NOTEBOOK_PASSWORD` environment variable to a secure password before starting the application. The `PasswordAuthMiddleware` in [`api/auth.py`](https://github.com/lfnovo/open-notebook/blob/main/api/auth.py) automatically activates when this variable is present. For Docker deployments, use `OPEN_NOTEBOOK_PASSWORD_FILE` to point to a secret file instead.

### What happens if I don't set the OPEN_NOTEBOOK_PASSWORD variable?

If the password variable is undefined, the middleware bypasses authentication entirely, making all API endpoints public. This behavior is intended for local development but presents a security risk in production environments.

### Which routes are exempt from authentication?

The whitelist in `PasswordAuthMiddleware` includes the root path (`/`), health checks (`/health`), API documentation (`/docs`), the authentication status endpoint (`/api/auth/status`), and all CORS preflight (`OPTIONS`) requests. All other routes require a valid Bearer token.

### How can I check if authentication is required before making requests?

Query the `GET /api/auth/status` endpoint, which returns a JSON object containing `auth_enabled` (boolean) and a descriptive message. This endpoint is always accessible without authentication, allowing clients to adapt their request logic accordingly.