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:
- Early bypass: If no password is configured (
self.passwordis falsy), the middleware allows all requests to pass through, making the API public. - Whitelist checking: Routes like
/,/health,/docs, and/api/auth/statusare exempt from authentication. - CORS preflight:
OPTIONSrequests are allowed without tokens to handle browser preflight checks. - Header validation: Extracts the
Authorizationheader, enforces theBearerscheme, and compares the token to the stored password. - Failure response: Returns HTTP 401 with a
WWW-Authenticate: Bearerheader 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
PasswordAuthMiddlewareonly 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}_FILEpattern for sensitive configuration.
Summary
- Password retrieval uses
get_secret_from_envinopen_notebook/utils/encryption.pyto support both environment variables and Docker secrets (OPEN_NOTEBOOK_PASSWORD_FILE). - Request validation is handled by
PasswordAuthMiddlewareinapi/auth.py, which intercepts all requests and validatesBearertokens against the configured password. - Public routes including
/health,/docs, and/api/auth/statusare whitelisted and accessible without authentication. - FastAPI integration occurs in
api/main.pywhere the middleware is mounted before CORS processing to ensure proper header handling. - Client authentication requires sending
Authorization: Bearer <password>headers, with the/api/auth/statusendpoint 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →