from fastapi import APIRouter, Depends, HTTPException, Request, status from sqlalchemy.ext.asyncio import AsyncSession from app.auth.schemas import LoginRequest, RefreshRequest, TokenResponse, UserClaims from app.auth.service import AuthService from app.dependencies import get_current_user, get_db from app.services.audit_service import AuditService router = APIRouter(prefix="/auth", tags=["auth"]) auth_service = AuthService() audit_service = AuditService() @router.post("/login", response_model=TokenResponse) async def login( body: LoginRequest, request: Request, db: AsyncSession = Depends(get_db), ) -> TokenResponse: """Authenticate user and return access + refresh tokens.""" result = await auth_service.login(body.email, body.password, db) if result is None: await audit_service.log( db, action="login_failed", entity_type="user", entity_id=body.email, details={"reason": "Invalid credentials"}, ip_address=request.client.host if request.client else None, ) await db.commit() raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid email or password", ) # Extract user_id from the access token claims claims = auth_service.validate_token(result["access_token"]) user_id = claims["sub"] if claims else body.email await audit_service.log( db, action="login", entity_type="user", entity_id=str(user_id), user_id=user_id if claims else None, details={"email": body.email}, ip_address=request.client.host if request.client else None, ) await db.commit() return TokenResponse(**result) @router.post("/refresh", response_model=TokenResponse) async def refresh_token(body: RefreshRequest) -> TokenResponse: """Exchange a valid refresh token for a new token pair.""" result = auth_service.refresh_tokens(body.refresh_token) if result is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid or expired refresh token", ) return TokenResponse(**result) @router.get("/me", response_model=UserClaims) async def get_me( current_user: dict = Depends(get_current_user), ) -> UserClaims: """Return the current authenticated user's claims.""" return UserClaims(**current_user)