"""Authentication middleware and utilities.""" from typing import Optional from fastapi import Depends, HTTPException, Query, Request, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from .config import settings security = HTTPBearer(auto_error=False) async def verify_token( request: Request, credentials: HTTPAuthorizationCredentials = Depends(security), ) -> str: """Verify the API token from the Authorization header. Args: request: The incoming request credentials: The bearer token credentials Returns: The validated token Raises: HTTPException: If the token is missing or invalid """ if credentials is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing authentication token", headers={"WWW-Authenticate": "Bearer"}, ) if credentials.credentials != settings.api_token: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid authentication token", headers={"WWW-Authenticate": "Bearer"}, ) return credentials.credentials class TokenAuth: """Dependency class for token authentication.""" def __init__(self, auto_error: bool = True): self.auto_error = auto_error async def __call__( self, request: Request, credentials: HTTPAuthorizationCredentials = Depends(security), ) -> str | None: """Verify the token and return it or raise an exception.""" if credentials is None: if self.auto_error: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing authentication token", headers={"WWW-Authenticate": "Bearer"}, ) return None if credentials.credentials != settings.api_token: if self.auto_error: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid authentication token", headers={"WWW-Authenticate": "Bearer"}, ) return None return credentials.credentials async def verify_token_or_query( credentials: HTTPAuthorizationCredentials = Depends(security), token: Optional[str] = Query(None, description="API token as query parameter"), ) -> str: """Verify the API token from header or query parameter. Useful for endpoints that need to be accessed via URL (like images). Args: credentials: The bearer token credentials from header token: Token from query parameter Returns: The validated token Raises: HTTPException: If the token is missing or invalid """ # Try header first if credentials is not None: if credentials.credentials == settings.api_token: return credentials.credentials # Try query parameter if token is not None: if token == settings.api_token: return token raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing or invalid authentication token", headers={"WWW-Authenticate": "Bearer"}, )