from datetime import UTC, datetime from typing import Annotated from fastapi import APIRouter, Depends, HTTPException, Response, status from core.security import ( AuthContext, create_access_token, get_auth_context, verify_password, ) from models.auth import LoginInput, TokenResponse from repositories.auth import get_user_by_username, revoke_token router = APIRouter( prefix="/auth", tags=["Auth"], ) @router.post("/login", response_model=TokenResponse) async def login_handler(payload: LoginInput): user = await get_user_by_username(payload.username) if user is None or not verify_password(payload.password, user.password_hash): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid username or password", headers={"WWW-Authenticate": "Bearer"}, ) token = create_access_token(subject=user.username) return TokenResponse(access_token=token) @router.post("/logout", status_code=status.HTTP_204_NO_CONTENT) async def logout_handler( auth_context: Annotated[AuthContext, Depends(get_auth_context)], ) -> Response: expires_at = datetime.fromtimestamp(auth_context.payload.exp, tz=UTC) if expires_at > datetime.now(UTC): await revoke_token(jti=auth_context.payload.jti, expires_at=expires_at) return Response(status_code=status.HTTP_204_NO_CONTENT)