Files
rehearshalhub/api/src/rehearsalhub/dependencies.py
2026-04-08 15:10:52 +02:00

49 lines
1.5 KiB
Python
Executable File

"""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