# How Password Authentication Middleware Protects API Endpoints in Open Notebook

> Discover how Open Notebooks password authentication middleware secures API endpoints by validating Bearer tokens and rejecting unauthorized requests with a 401 response.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: how-to-guide
- Published: 2026-06-25

---

**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`](https://github.com/lfnovo/open-notebook/blob/main/api/auth.py). When the FastAPI application initializes in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py), the middleware is added immediately after the FastAPI app instantiation:

```python

# 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:

1. **Secret Loading** – On construction, the middleware reads the `OPEN_NOTEBOOK_PASSWORD` environment variable. If the variable is unset, the middleware skips authentication entirely, allowing unrestricted access for local development.
2. **Header Extraction** – For each request, the middleware inspects the `Authorization` header, expecting the format `Bearer <password>`.
3. **Validation** – It compares the extracted token against the loaded secret.
4. **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"}`.
5. **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`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) demonstrates how to install the middleware:

```python

# 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`](https://github.com/lfnovo/open-notebook/blob/main/api/client.py) as a reference implementation showing automatic header injection:

```python
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:

```json
{
  "detail": "Invalid password"
}

```

## Configuration for Development vs. Production

The middleware behavior depends entirely on the `OPEN_NOTEBOOK_PASSWORD` environment variable:

- **Production**: Set `OPEN_NOTEBOOK_PASSWORD` to a strong secret. All requests must include `Authorization: Bearer <password>`.
- **Development**: Leave `OPEN_NOTEBOOK_PASSWORD` unset. 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`](https://github.com/lfnovo/open-notebook/blob/main/api/auth.py).

## Summary

- **Centralized Protection**: The `PasswordAuthMiddleware` in [`api/auth.py`](https://github.com/lfnovo/open-notebook/blob/main/api/auth.py) gates every API endpoint without requiring per-route authentication logic.
- **Bearer Token Validation**: Requests must include `Authorization: Bearer <password>` where the password matches the `OPEN_NOTEBOOK_PASSWORD` environment 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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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`](https://github.com/lfnovo/open-notebook/blob/main/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.