"""Bearer-token auth — single static token from CASSANDRA_TOKEN env. If the env is empty, the app runs open (LAN-only / dev mode). Constant-time comparison via secrets.compare_digest. """ from __future__ import annotations import secrets from fastapi import Header, HTTPException, status from app.config import get_settings async def require_token( authorization: str | None = Header(default=None), ) -> None: expected = get_settings().CASSANDRA_TOKEN if not expected: return # open mode — no auth required if not authorization or not authorization.lower().startswith("bearer "): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Bearer token required", headers={"WWW-Authenticate": "Bearer"}, ) provided = authorization.split(" ", 1)[1].strip() if not secrets.compare_digest(provided.encode(), expected.encode()): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Invalid token", )