"""FastAPI dependency providers.""" from __future__ import annotations import uuid from fastapi import Depends, HTTPException, Request, status from fastapi.security import OAuth2PasswordBearer from sqlalchemy.ext.asyncio import AsyncSession from rehearsalhub.db.engine import get_session from rehearsalhub.db.models import Member from rehearsalhub.services.auth import decode_token from rehearsalhub.repositories.member import MemberRepository # auto_error=False so we can fall back to cookie auth without a 401 from the scheme itself oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login", auto_error=False) async def get_current_member( request: Request, bearer_token: str | None = Depends(oauth2_scheme), session: AsyncSession = Depends(get_session), ) -> Member: # Prefer Authorization: Bearer header; fall back to httpOnly cookie token = bearer_token or request.cookies.get("rh_token") credentials_exc = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid or expired token", headers={"WWW-Authenticate": "Bearer"}, ) if not token: raise credentials_exc try: payload = decode_token(token) member_id_str: str | None = payload.get("sub") if member_id_str is None: raise credentials_exc member_id = uuid.UUID(member_id_str) except Exception: raise credentials_exc repo = MemberRepository(session) member = await repo.get_by_id(member_id) if member is None: raise credentials_exc return member