Implementing API Authentication for Open Notebook: A Complete Technical Guide

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, 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. This utility supports both plain environment variables and Docker secrets through a dual-path lookup strategy.


# 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 (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 (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. 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:

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:


# 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 (lines 13-23) allows clients to discover whether authentication is required:

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

A configured server returns:

{
  "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:


# 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:

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 to support both environment variables and Docker secrets (OPEN_NOTEBOOK_PASSWORD_FILE).
  • Request validation is handled by PasswordAuthMiddleware in 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 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →