"""Authentication router""" from fastapi import APIRouter, Depends, HTTPException, status, Request from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from typing import Optional from app.models.user import User, UserLogin, Token, TokenRefresh, UserCreate from app.models.auth_history import AuthAction from app.services.auth_service import AuthService from app.services.token_service import TokenService from app.utils.security import decode_token router = APIRouter(prefix="/auth", tags=["Authentication"]) oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login") async def get_current_user(token: str = Depends(oauth2_scheme)) -> User: """Get current authenticated user""" credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) payload = decode_token(token) if payload is None or payload.get("type") != "access": raise credentials_exception user = await AuthService.get_user_by_id(payload.get("sub")) if user is None: raise credentials_exception return user @router.post("/register", response_model=User) async def register(user_data: UserCreate, request: Request): """Register a new user""" try: user = await AuthService.create_user(user_data) # Log registration await AuthService.log_auth_action( user_id=str(user.id), action=AuthAction.REGISTER, ip_address=request.client.host, user_agent=request.headers.get("User-Agent") ) return user except ValueError as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=str(e) ) @router.post("/login", response_model=Token) async def login(request: Request, form_data: OAuth2PasswordRequestForm = Depends()): """Login with username/email and password""" user = await AuthService.authenticate_user(form_data.username, form_data.password) if not user: # Log failed login attempt await AuthService.log_auth_action( user_id="unknown", action=AuthAction.FAILED_LOGIN, ip_address=request.client.host, user_agent=request.headers.get("User-Agent"), result="failed", details={"username": form_data.username} ) raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username or password", headers={"WWW-Authenticate": "Bearer"}, ) # Create tokens tokens = await TokenService.create_tokens( str(user.id), { "username": user.username, "role": user.role, "email": user.email } ) # Log successful login await AuthService.log_auth_action( user_id=str(user.id), action=AuthAction.LOGIN, ip_address=request.client.host, user_agent=request.headers.get("User-Agent") ) return tokens @router.post("/refresh", response_model=Token) async def refresh_token(request: Request, token_data: TokenRefresh): """Refresh access token using refresh token""" user_id = await TokenService.verify_refresh_token(token_data.refresh_token) if not user_id: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid refresh token" ) # Get user user = await AuthService.get_user_by_id(user_id) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found" ) # Revoke old refresh token await TokenService.revoke_refresh_token(token_data.refresh_token) # Create new tokens tokens = await TokenService.create_tokens( str(user.id), { "username": user.username, "role": user.role, "email": user.email } ) # Log token refresh await AuthService.log_auth_action( user_id=str(user.id), action=AuthAction.TOKEN_REFRESH, ip_address=request.client.host, user_agent=request.headers.get("User-Agent") ) return tokens @router.post("/logout") async def logout(request: Request, current_user: User = Depends(get_current_user)): """Logout current user""" # Revoke all user tokens await TokenService.revoke_all_user_tokens(str(current_user.id)) # Log logout await AuthService.log_auth_action( user_id=str(current_user.id), action=AuthAction.LOGOUT, ip_address=request.client.host, user_agent=request.headers.get("User-Agent") ) return {"message": "Successfully logged out"} @router.get("/me", response_model=User) async def get_me(current_user: User = Depends(get_current_user)): """Get current user information""" return current_user