Skip to content

Add HTTP Basic Auth middleware for /docs, /redoc, /openapi.json #526

@lbedner

Description

@lbedner

Summary

Port the docs authentication middleware from sector-7g that password-protects FastAPI's built-in documentation endpoints (/docs, /redoc, /openapi.json) behind HTTP Basic Auth.

Designed as a drop-in, auto-discovered middleware — no custom route overrides needed.

Implementation

1. New file: app/components/backend/middleware/docs_auth.py

  • Uses the existing register_middleware(app) auto-discovery pattern
  • Intercepts requests to /docs, /redoc, /openapi.json
  • Returns 401 with WWW-Authenticate: Basic header if credentials are missing/invalid
  • Uses secrets.compare_digest for timing-safe credential comparison
  • No-ops entirely when DOCS_AUTH_ENABLED=False (dev-friendly default)
  • Zero extra dependencies — only stdlib + starlette (already in stack)
PROTECTED_PATHS = {"/docs", "/redoc", "/openapi.json"}

def register_middleware(app: FastAPI) -> None:
    if not settings.DOCS_AUTH_ENABLED:
        return

    @app.middleware("http")
    async def docs_basic_auth(request, call_next):
        if request.url.path not in PROTECTED_PATHS:
            return await call_next(request)
        # Validate Basic auth header, 401 if missing/invalid

2. Config additions: app/core/config.py

Add to the Settings class:

DOCS_AUTH_ENABLED: bool = False  # Off by default for dev
DOCS_USERNAME: str = "admin"
DOCS_PASSWORD: str = "changeme"

3. Env file updates: .env.example

# Docs authentication (HTTP Basic Auth for /docs, /redoc, /openapi.json)
# DOCS_AUTH_ENABLED=false
# DOCS_USERNAME=admin
# DOCS_PASSWORD=changeme

Known Gotcha

The middleware inspector (app/services/backend/middleware_inspector.py) may fail to serialize the @app.middleware("http") dispatch function stored in middleware kwargs. Fix: filter non-serializable values before JSON serialization:

config = {
    k: v
    if isinstance(v, str | int | float | bool | list | dict | None)
    else f"<{type(v).__name__}>"
    for k, v in middleware_kwargs.items()
}

Verification

  • make lint passes
  • make serve → visit /docs → browser prompts for username/password
  • Wrong credentials → 401
  • Correct credentials → Swagger UI loads
  • /redoc and /openapi.json also protected
  • DOCS_AUTH_ENABLED=false → docs accessible without auth

Reference

Working implementation: sector-7g/app/components/backend/middleware/docs_auth.py

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions