# ================================================================ # services/auth/app/api/auth.py - Updated with modular monitoring # ================================================================ """ Authentication API routes - Enhanced with proper metrics access """ from fastapi import APIRouter, Depends, HTTPException, status, Request from sqlalchemy.ext.asyncio import AsyncSession import structlog from app.core.database import get_db from app.schemas.auth import ( UserRegistration, UserLogin, TokenResponse, RefreshTokenRequest, UserResponse ) from app.services.auth_service import AuthService from app.core.security import security_manager from shared.monitoring.decorators import track_execution_time, count_calls logger = structlog.get_logger() router = APIRouter() def get_metrics_collector(request: Request): """Get metrics collector from app state""" return getattr(request.app.state, 'metrics_collector', None) @router.post("/register", response_model=UserResponse) @track_execution_time("registration_duration_seconds", "auth-service") async def register( user_data: UserRegistration, request: Request, db: AsyncSession = Depends(get_db) ): """Register a new user""" metrics = get_metrics_collector(request) try: result = await AuthService.register_user(user_data, db) # Record successful registration if metrics: metrics.increment_counter("registration_total", labels={"status": "success"}) logger.info(f"User registration successful: {user_data.email}") return result except HTTPException as e: # Record failed registration if metrics: metrics.increment_counter("registration_total", labels={"status": "failed"}) logger.warning(f"Registration failed for {user_data.email}: {e.detail}") raise except Exception as e: # Record error if metrics: metrics.increment_counter("registration_total", labels={"status": "error"}) logger.error(f"Registration error for {user_data.email}: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Registration failed" ) @router.post("/login", response_model=TokenResponse) @track_execution_time("login_duration_seconds", "auth-service") async def login( login_data: UserLogin, request: Request, db: AsyncSession = Depends(get_db) ): """User login""" metrics = get_metrics_collector(request) try: ip_address = request.client.host user_agent = request.headers.get("user-agent", "") result = await AuthService.login_user(login_data, db, ip_address, user_agent) # Record successful login if metrics: metrics.increment_counter("login_success_total") logger.info(f"Login successful for {login_data.email}") return result except HTTPException as e: # Record failed login if metrics: metrics.increment_counter("login_failure_total", labels={"reason": "auth_failed"}) logger.warning(f"Login failed for {login_data.email}: {e.detail}") raise except Exception as e: # Record login error if metrics: metrics.increment_counter("login_failure_total", labels={"reason": "error"}) logger.error(f"Login error for {login_data.email}: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Login failed" ) @router.post("/refresh", response_model=TokenResponse) @track_execution_time("token_refresh_duration_seconds", "auth-service") async def refresh_token( refresh_data: RefreshTokenRequest, request: Request, db: AsyncSession = Depends(get_db) ): """Refresh access token""" metrics = get_metrics_collector(request) try: result = await AuthService.refresh_token(refresh_data.refresh_token, db) # Record successful refresh if metrics: metrics.increment_counter("token_refresh_total", labels={"status": "success"}) return result except HTTPException as e: # Record failed refresh if metrics: metrics.increment_counter("token_refresh_total", labels={"status": "failed"}) raise except Exception as e: # Record refresh error if metrics: metrics.increment_counter("token_refresh_total", labels={"status": "error"}) logger.error(f"Token refresh error: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Token refresh failed" ) @router.post("/verify") async def verify_token( request: Request, db: AsyncSession = Depends(get_db) ): """Verify access token""" metrics = get_metrics_collector(request) try: auth_header = request.headers.get("Authorization") if not auth_header or not auth_header.startswith("Bearer "): if metrics: metrics.increment_counter("token_verify_total", labels={"status": "no_token"}) raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing or invalid authorization header" ) token = auth_header.split(" ")[1] payload = await AuthService.verify_token(token, db) # Record successful verification if metrics: metrics.increment_counter("token_verify_total", labels={"status": "success"}) return {"valid": True, "user_id": payload["sub"]} except HTTPException as e: # Record failed verification if metrics: metrics.increment_counter("token_verify_total", labels={"status": "failed"}) raise except Exception as e: # Record verification error if metrics: metrics.increment_counter("token_verify_total", labels={"status": "error"}) logger.error(f"Token verification error: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Token verification failed" ) @router.post("/logout") async def logout( request: Request, db: AsyncSession = Depends(get_db) ): """User logout""" metrics = get_metrics_collector(request) try: auth_header = request.headers.get("Authorization") if not auth_header or not auth_header.startswith("Bearer "): if metrics: metrics.increment_counter("logout_total", labels={"status": "no_token"}) raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing or invalid authorization header" ) token = auth_header.split(" ")[1] await AuthService.logout_user(token, db) # Record successful logout if metrics: metrics.increment_counter("logout_total", labels={"status": "success"}) return {"message": "Logged out successfully"} except HTTPException as e: # Record failed logout if metrics: metrics.increment_counter("logout_total", labels={"status": "failed"}) raise except Exception as e: # Record logout error if metrics: metrics.increment_counter("logout_total", labels={"status": "error"}) logger.error(f"Logout error: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Logout failed" )