How Password Authentication Middleware Protects API Endpoints in Open Notebook
Open Notebook uses a shared-secret middleware that intercepts every HTTP request and validates a Bearer token against an environment variable, rejecting unauthorized calls with a 401 response.
The lfnovo/open-notebook repository implements a lightweight security layer using FastAPI middleware to gate all API access behind a single password. This password authentication middleware ensures that every endpoint—from notebook management to search queries—requires valid credentials before processing requests. By centralizing authentication logic at the framework level, the application avoids duplicating security checks across individual routers.
How Password Authentication Middleware Works
The protection mechanism relies on a custom PasswordAuthMiddleware class defined in api/auth.py. When the FastAPI application initializes in api/main.py, this middleware is mounted at the top of the stack before any route handlers are registered.
Middleware Registration in the Application Stack
In api/main.py, the middleware is added immediately after the FastAPI app instantiation:
# api/main.py
from fastapi import FastAPI
from .auth import PasswordAuthMiddleware
app = FastAPI()
app.add_middleware(PasswordAuthMiddleware) # Protects every endpoint
Because the middleware is added before routers are mounted, it wraps the entire application. This ensures that every incoming request—whether targeting /api/notebooks, /api/sources, or search endpoints—passes through the authentication check before reaching business logic.
The Dispatch Flow
The PasswordAuthMiddleware implements the standard ASGI middleware interface with a dispatch method that processes every request. The flow follows these steps:
- Secret Loading – On construction, the middleware reads the
OPEN_NOTEBOOK_PASSWORDenvironment variable. If the variable is unset, the middleware skips authentication entirely, allowing unrestricted access for local development. - Header Extraction – For each request, the middleware inspects the
Authorizationheader, expecting the formatBearer <password>. - Validation – It compares the extracted token against the loaded secret.
- Response Handling – If the header is missing or the password is incorrect, the middleware returns a 401 Unauthorized response with a JSON payload
{"detail": "Invalid password"}. - Passthrough – When the token matches, the request flows to the downstream handler.
Practical Usage Examples
Adding the Middleware
The following pattern from api/main.py demonstrates how to install the middleware:
# api/main.py
from fastapi import FastAPI
from .auth import PasswordAuthMiddleware
app = FastAPI()
app.add_middleware(PasswordAuthMiddleware) # Protects every endpoint
Calling a Protected Endpoint
Clients must include the password in the Authorization header. The repository includes api/client.py as a reference implementation showing automatic header injection:
import os
import requests
BASE = "http://localhost:5055"
pwd = os.getenv("OPEN_NOTEBOOK_PASSWORD") # same secret as the server
headers = {"Authorization": f"Bearer {pwd}"}
resp = requests.get(f"{BASE}/api/notebooks", headers=headers)
print(resp.json()) # works only with correct password
Handling Authentication Errors
When credentials are missing or invalid, the middleware returns a standard JSON error response:
{
"detail": "Invalid password"
}
Configuration for Development vs. Production
The middleware behavior depends entirely on the OPEN_NOTEBOOK_PASSWORD environment variable:
- Production: Set
OPEN_NOTEBOOK_PASSWORDto a strong secret. All requests must includeAuthorization: Bearer <password>. - Development: Leave
OPEN_NOTEBOOK_PASSWORDunset. The middleware detects the absence of the variable and automatically permits all requests, eliminating friction during local testing.
This design allows the same codebase to run in both secure and open modes without code changes, as implemented in api/auth.py.
Summary
- Centralized Protection: The
PasswordAuthMiddlewareinapi/auth.pygates every API endpoint without requiring per-route authentication logic. - Bearer Token Validation: Requests must include
Authorization: Bearer <password>where the password matches theOPEN_NOTEBOOK_PASSWORDenvironment variable. - Automatic Fail-Open: When the environment variable is unset, the middleware skips checks, enabling seamless local development.
- Standard HTTP Response: Invalid or missing credentials trigger a 401 response with a JSON detail message.
Frequently Asked Questions
How do I configure the password for production deployment?
Set the OPEN_NOTEBOOK_PASSWORD environment variable to a cryptographically secure random string before starting the application. The middleware will automatically enforce Bearer token validation on every request once this variable is present.
What happens if I don't set OPEN_NOTEBOOK_PASSWORD?
According to the implementation in api/auth.py, the middleware skips the authentication check entirely when the environment variable is missing. This fail-open behavior is intended for local development convenience but should never be used in production.
Does the middleware protect WebSocket connections?
Yes. Because app.add_middleware(PasswordAuthMiddleware) is called before router registration in api/main.py, the middleware wraps the entire ASGI application. This includes HTTP routes, WebSocket endpoints, and any other ASGI sub-applications mounted on the FastAPI instance.
Can I combine this middleware with other authentication schemes?
While the current implementation in api/auth.py uses a simple shared-secret approach, FastAPI supports multiple middleware layers. You could add additional authentication middleware (such as OAuth2 or API key validation) alongside PasswordAuthMiddleware, provided you understand the order of execution in the middleware stack.
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 →