How PasswordAuthMiddleware Secures API Endpoints in Open Notebook

PasswordAuthMiddleware is a FastAPI middleware that intercepts every incoming request to verify a Bearer token against the OPEN_NOTEBOOK_PASSWORD environment variable, returning 401 Unauthorized for missing or invalid credentials while allowing configured public paths to bypass authentication.

The open-notebook project implements a lightweight authentication layer using Starlette-based middleware to protect its REST API surface. Located in api/auth.py, the PasswordAuthMiddleware class provides a single-password gate that validates HTTP requests before they reach your route handlers, making it ideal for self-hosted deployments where simplicity outweighs complex user management.

How PasswordAuthMiddleware Works

The middleware implements a seven-step protection strategy that processes every request before it reaches the application routers.

Password Source and Initialization

At startup, the middleware initializes by reading the secret OPEN_NOTEBOOK_PASSWORD environment variable (or Docker secret file) via the get_secret_from_env helper in open_notebook/utils/encryption.py. If this variable is missing, the middleware becomes a no-op, allowing the API to run without authentication. This design supports local development environments where password protection is unnecessary.

Path-Based Exclusions

The middleware accepts an excluded_paths parameter during registration in api/main.py. Requests matching any path in this list bypass the password check entirely. Common exclusions include root paths, health checks, and API documentation endpoints.


# api/main.py – middleware registration with excluded paths

app.add_middleware(
    PasswordAuthMiddleware,
    excluded_paths=[
        "/", "/health", "/docs", "/openapi.json", "/redoc",
        "/api/auth/status", "/api/config",
    ],
)

CORS Pre-flight Handling

OPTIONS requests for CORS pre-flight checks are automatically allowed without authentication. This prevents browsers from blocking legitimate cross-origin requests before the actual API call occurs.

Header Validation and Authentication Flow

For all non-excluded requests, the middleware enforces a strict validation sequence:

  1. Presence Check: If the Authorization header is missing, the middleware returns 401 Unauthorized with a WWW-Authenticate: Bearer header to prompt credential submission.

  2. Format Validation: The header must conform to the pattern Bearer {password}. Malformed headers return 401 with the message "Invalid authorization header format".

  3. Password Verification: The extracted token is compared to the stored password. A mismatch yields 401 with "Invalid password".

  4. Request Forwarding: When validation succeeds, the middleware hands the request to the downstream handler via call_next and returns the response unchanged.

Route-Level Protection with check_api_password

Beyond global middleware, the api/auth.py module exports check_api_password, a FastAPI dependency that individual routes can use to enforce authentication without applying the middleware to the entire application. This is useful for securing specific admin endpoints while keeping the rest of the API public.

from api.auth import check_api_password

@router.get("/admin")
async def admin_panel(valid: bool = Depends(check_api_password)):
    return {"msg": "You are authorized"}

Client Authentication Examples

When calling protected endpoints, clients must include the password in the Authorization header using the Bearer scheme.

curl -H "Authorization: Bearer my-secret-pw" \
     http://localhost:5055/api/notebooks

If authentication fails, the server responds with a 401 status code and a JSON detail message:

{
  "detail": "Invalid password"
}

Missing headers trigger a 401 response with the WWW-Authenticate: Bearer challenge header, prompting clients to resubmit with credentials.

Summary

  • PasswordAuthMiddleware intercepts all HTTP requests in api/auth.py before they reach FastAPI routers.
  • It reads the OPEN_NOTEBOOK_PASSWORD from environment variables via get_secret_from_env, becoming a no-op if unset.
  • The excluded_paths parameter in api/main.py allows public access to health checks, documentation, and configuration endpoints.
  • OPTIONS requests bypass authentication to support CORS pre-flight checks.
  • Invalid or missing Bearer tokens return 401 Unauthorized with specific error messages.
  • The check_api_password dependency enables per-route authentication without global middleware.

Frequently Asked Questions

What happens if OPEN_NOTEBOOK_PASSWORD is not set?

When the OPEN_NOTEBOOK_PASSWORD environment variable is missing, the middleware initializes in a no-op state. All requests pass through without authentication, allowing the API to run in unsecured mode—typically used for local development environments.

How do I exclude specific endpoints from authentication?

Pass a list of paths to the excluded_paths parameter when adding the middleware in api/main.py. Any request whose path matches an entry in this list bypasses the password check entirely. Common exclusions include /health, /docs, /openapi.json, and /redoc.

Can I use PasswordAuthMiddleware for individual routes only?

Yes. Instead of applying the middleware globally, import the check_api_password dependency from api/auth.py and add it to specific route handlers using FastAPI's Depends mechanism. This approach secures only selected endpoints while leaving others publicly accessible.

What is the correct format for the Authorization header?

The middleware expects the header in the format Authorization: Bearer {password} where {password} matches the value stored in OPEN_NOTEBOOK_PASSWORD. Requests missing the "Bearer" prefix or containing malformed tokens receive a 401 response with "Invalid authorization header format".

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 →