How to Configure Password Authentication Middleware for Production in Open Notebook
To secure the Open Notebook API in production, set the OPEN_NOTEBOOK_PASSWORD environment variable or mount a secret file to OPEN_NOTEBOOK_PASSWORD_FILE, then restart the service so the PasswordAuthMiddleware enforces Authorization: Bearer <password> on all incoming requests.
Open Notebook uses a lightweight PasswordAuthMiddleware to protect its HTTP API from unauthorized access. While development mode allows unrestricted access when the password is unset, production deployments require explicit configuration of the OPEN_NOTEBOOK_PASSWORD environment variable. This guide explains how to configure password authentication middleware for production using the source code from the lfnovo/open-notebook repository.
How the Password Authentication Middleware Works
The authentication layer is implemented in api/auth.py as PasswordAuthMiddleware, which is registered in api/main.py at lines 73-86. The middleware intercepts every HTTP request and validates the Authorization: Bearer <token> header against a secret value retrieved via get_secret_from_env in open_notebook/utils/encryption.py (lines 29-59).
This utility function first checks for a <VAR>_FILE pattern to support Docker Secrets and Kubernetes secret mounts, then falls back to plain environment variables. If the password is not configured, the middleware permits all requests, making it safe for local development but requiring explicit secrets for production.
Production Configuration Steps
Set the OPEN_NOTEBOOK_PASSWORD Environment Variable
Create a strong, random password and export it as an environment variable. This value is read once at process startup, so changes require a restart.
Mount Secrets in Docker or Kubernetes
For containerized environments, use the OPEN_NOTEBOOK_PASSWORD_FILE variable to reference a mounted secret file rather than exposing the password in environment variables. This pattern supports Docker Swarm secrets and Kubernetes secrets mounted as volumes.
Restart the API Service
The middleware reads the password during application initialization in api/main.py. Any change to the secret requires restarting the container to reload the PasswordAuthMiddleware with the new credentials.
Update Client Authorization Headers
Clients must include Authorization: Bearer <password> in all HTTP requests. The built-in api/client.py automatically injects this header when OPEN_NOTEBOOK_PASSWORD is present in the environment.
Production Deployment Examples
Docker Compose with Secrets
Store the password as a Docker secret file to avoid exposing it in environment variables:
services:
api:
image: lfnovo/open-notebook:latest
env_file: .env.production
secrets:
- open_notebook_password
ports:
- "5055:5055"
secrets:
open_notebook_password:
file: ./secrets/open_notebook_password.txt
Environment Configuration File
Reference the secret file in your .env.production or use a plain environment variable:
# Option 1: File-based secret (recommended for Docker/Kubernetes)
# OPEN_NOTEBOOK_PASSWORD_FILE is set automatically by Docker secret mount
# Option 2: Direct environment variable
# OPEN_NOTEBOOK_PASSWORD=SuperSecretProdPass
CORS_ORIGINS=https://notebook.example.com
Python Client Authentication
The api/client.py wrapper automatically adds the authorization header when the environment variable is set:
import os
from api.client import OpenNotebookClient
# Ensure the password env var is visible to the process
os.environ["OPEN_NOTEBOOK_PASSWORD"] = "SuperSecretProdPass"
client = OpenNotebookClient(base_url="https://api.example.com")
# All subsequent calls will include:
# Authorization: Bearer SuperSecretProdPass
FastAPI Route Protection
For fine-grained control within specific routes, use the optional dependency from api/auth.py:
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"}
Security Architecture and Middleware Ordering
The app.add_middleware(PasswordAuthMiddleware, ...) call in api/main.py places authentication before CORS middleware processing. This architectural choice ensures that unauthenticated requests are rejected prior to any CORS handling, preventing information leakage through preflight responses and ensuring that only authenticated traffic reaches your business logic.
The middleware configuration excludes specific public paths—including health check endpoints, OpenAPI documentation, and internal status routes—allowing monitoring tools and API discovery to remain accessible without credentials while protecting sensitive operations.
Summary
- Set
OPEN_NOTEBOOK_PASSWORDorOPEN_NOTEBOOK_PASSWORD_FILEto enable production protection - Configure secrets via Docker or Kubernetes for secure credential management compatible with
get_secret_from_env - Restart the API after changing passwords to reload the middleware initialized in
api/main.py - Include
Authorization: Bearer <password>headers in client requests, or useapi/client.pyfor automatic handling - Public endpoints remain accessible for health checks and documentation as configured in the middleware exclusions
Frequently Asked Questions
What happens if OPEN_NOTEBOOK_PASSWORD is not set?
According to the source code in open_notebook/utils/encryption.py, the middleware falls back to a "no password" mode that permits all requests. This configuration is only safe for development environments and leaves production deployments vulnerable to unauthorized access.
How do I rotate the password in a running container?
Password changes require a container restart because get_secret_from_env is called once during middleware initialization in api/main.py (lines 73-86). Update the secret file or environment variable, then restart the process to load the new value into PasswordAuthMiddleware.
Which endpoints bypass password authentication?
The middleware configuration in api/main.py excludes specific public paths including health check endpoints, OpenAPI schema documents, and Swagger UI routes. This allows monitoring tools and API documentation to remain accessible without credentials while protecting business logic routes.
Can I use Kubernetes secrets with this middleware?
Yes. Mount your Kubernetes secret as a file in the container and set OPEN_NOTEBOOK_PASSWORD_FILE to the mount path. The utility function in open_notebook/utils/encryption.py (lines 29-59) automatically detects the _FILE suffix and reads the file-based secret, making it compatible with Kubernetes secret volumes.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →