Configure Password Authentication Middleware for Production in Open Notebook
Enable production security by setting the OPEN_NOTEBOOK_PASSWORD environment variable or Docker secret, ensuring every API request includes a valid Authorization: Bearer <password> header.
Open Notebook secures its HTTP API with a lightweight PasswordAuthMiddleware that validates bearer tokens on every request. In development environments, the middleware automatically falls back to "no password" when OPEN_NOTEBOOK_PASSWORD is unset, but production deployments require explicit configuration to prevent unauthorized access. This guide covers the exact implementation details sourced from lfnovo/open-notebook to help you configure robust password authentication for production workloads.
How Password Authentication Works
The PasswordAuthMiddleware class defined in api/auth.py intercepts incoming requests and validates the Authorization header against a configured secret. When a request arrives, the middleware checks if the path is in the exclusion list (health checks, OpenAPI documentation, and internal status routes) or if the bearer token matches the expected password.
In api/main.py (lines 73–86), the middleware is instantiated before the CORS middleware. This ordering ensures that unauthenticated requests are rejected before any CORS handling occurs, preventing unauthorized access from reaching your business logic. The middleware supports two secret sources: a plain environment variable (OPEN_NOTEBOOK_PASSWORD) or a file-based Docker secret (OPEN_NOTEBOOK_PASSWORD_FILE), with the latter taking precedence when both are present.
Production Configuration Steps
Generate a Strong Password
Create a cryptographically secure password using your system's entropy source. The password should be at least 32 characters long and contain a mix of alphanumeric and special characters to prevent brute-force attacks.
Configure Environment Variables or Docker Secrets
The get_secret_from_env function in open_notebook/utils/encryption.py (lines 29–59) handles secret retrieval by first checking for a <VAR>_FILE pattern, then falling back to the plain environment variable. This design supports both Docker Swarm/Kubernetes secret mounts and traditional .env files.
For Docker-based deployments, use the secret file approach:
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
Your .env.production file should reference the secret file or contain the plain variable:
# Option 1: File-based secret (recommended for Docker)
# The _FILE suffix is automatically detected by get_secret_from_env
# Option 2: Plain environment variable
# OPEN_NOTEBOOK_PASSWORD=SuperSecretProdPass123!
CORS_ORIGINS=https://notebook.example.com
Restart the API Service
The password is read at process startup in api/main.py. After changing the secret, restart the container to ensure the middleware picks up the new value. Running processes do not reload the password dynamically.
Update Client Authorization Headers
The built-in client library in api/client.py automatically reads OPEN_NOTEBOOK_PASSWORD from the environment and adds the Authorization: Bearer <password> header to all requests. When using custom HTTP clients, implement the header manually:
import os
from open_notebook.api.client import OpenNotebookClient
# Ensure the environment variable is set
os.environ["OPEN_NOTEBOOK_PASSWORD"] = "SuperSecretProdPass123!"
client = OpenNotebookClient(base_url="https://api.example.com")
# All subsequent API calls include the Authorization header automatically
Implementation Details and Source Files
Middleware Registration in api/main.py
The middleware is registered with specific excluded paths for public endpoints:
# From api/main.py (lines 73-86)
app.add_middleware(
PasswordAuthMiddleware,
exclude_paths=["/health", "/docs", "/openapi.json", "/redoc"]
)
Secret Retrieval Logic
The get_secret_from_env utility in open_notebook/utils/encryption.py handles both file-based and environment-based secrets:
# Conceptual implementation from open_notebook/utils/encryption.py
def get_secret_from_env(var_name: str) -> str:
file_var = f"{var_name}_FILE"
if file_var in os.environ:
with open(os.environ[file_var], 'r') as f:
return f.read().strip()
return os.environ.get(var_name, "")
Optional Dependency for Fine-Grained Control
For specific routes requiring explicit authentication checks, use the check_api_password dependency:
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"}
Verifying Your Production Configuration
After restarting the API, test authentication using curl:
# This should return 401 Unauthorized
curl https://api.example.com/notes
# This should succeed with proper authorization
curl -H "Authorization: Bearer SuperSecretProdPass123!" https://api.example.com/notes
Public endpoints like /health and /docs should remain accessible without headers, while all business logic routes require the bearer token.
Summary
- Configure the
OPEN_NOTEBOOK_PASSWORDenvironment variable orOPEN_NOTEBOOK_PASSWORD_FILEDocker secret to enable production authentication. - Restart the API process after setting secrets, as the middleware reads passwords only at startup.
- Verify that excluded paths (health checks, documentation) remain public while all other routes require
Authorization: Bearer <password>headers. - Use the built-in
OpenNotebookClientfromapi/client.pyto automatically handle header injection, or manually implement the bearer token pattern in custom clients. - Reference
api/auth.py,api/main.py, andopen_notebook/utils/encryption.pyfor the underlying implementation details.
Frequently Asked Questions
What happens if OPEN_NOTEBOOK_PASSWORD is not set in production?
According to the source code in open_notebook/utils/encryption.py, the middleware falls back to an empty string when both OPEN_NOTEBOOK_PASSWORD and OPEN_NOTEBOOK_PASSWORD_FILE are unset. In this state, the authentication check passes for any request, effectively disabling password protection. This behavior is intended for development but creates a security vulnerability in production.
Which endpoints bypass authentication by default?
The middleware initialization in api/main.py excludes specific paths including /health (health checks), /docs (Swagger documentation), /redoc (alternative documentation), and /openapi.json (schema specification). These endpoints remain publicly accessible to support monitoring tools and API exploration, while all other routes require valid bearer tokens.
Can I configure multiple passwords or user accounts?
The current PasswordAuthMiddleware implementation in api/auth.py supports only a single global password. There is no built-in multi-user authentication or role-based access control. For multi-user deployments, you should implement an additional authorization layer or place Open Notebook behind an API gateway that handles user management and passes authenticated requests through.
How does the client library handle authentication automatically?
The OpenNotebookClient class in api/client.py reads the OPEN_NOTEBOOK_PASSWORD environment variable during initialization and stores it in the session headers. Every HTTP request made through this client automatically includes Authorization: Bearer <password>, eliminating the need to manually format headers for each API call. This ensures consistent authentication across all client interactions when the environment variable is properly configured.
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 →