"""FastAPI dependency injection for authentication and common services.""" from typing import Optional from fastapi import Depends, HTTPException, status from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from sqlalchemy.orm import Session from backend.core.database import get_db from backend.models.user import User from backend.services.auth_service import AuthService from jose import JWTError, jwt import logging logger = logging.getLogger(__name__) # Security scheme for JWT tokens security = HTTPBearer() def get_auth_service() -> AuthService: """Get AuthService instance.""" return AuthService() async def get_current_user( credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(get_db), auth_service: AuthService = Depends(get_auth_service) ) -> User: """ Validate JWT token and return current user. Args: credentials: HTTP Bearer token from request header db: Database session auth_service: Authentication service instance Returns: User: Current authenticated user Raises: HTTPException: 401 if token is invalid or user not found """ credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) try: token = credentials.credentials if not token: raise credentials_exception # Decode and validate token payload = auth_service.decode_access_token(token) if payload is None: raise credentials_exception user_id: str = payload.get("sub") if user_id is None: raise credentials_exception # Get user from database user = db.query(User).filter(User.id == user_id).first() if user is None: raise credentials_exception return user except JWTError as jwt_error: if "expired" in str(jwt_error).lower(): logger.warning("JWT token expired") raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Token expired", headers={"WWW-Authenticate": "Bearer"}, ) logger.warning(f"Invalid JWT token: {jwt_error}") raise credentials_exception except Exception as e: logger.error(f"Error validating user token: {e}") raise credentials_exception async def get_current_user_optional( credentials: Optional[HTTPAuthorizationCredentials] = Depends(HTTPBearer(auto_error=False)), db: Session = Depends(get_db), auth_service: AuthService = Depends(get_auth_service) ) -> Optional[User]: """ Optionally validate JWT token and return current user. Returns None if no token provided or token is invalid. Args: credentials: Optional HTTP Bearer token from request header db: Database session auth_service: Authentication service instance Returns: Optional[User]: Current authenticated user or None """ if not credentials: return None try: token = credentials.credentials if not token: return None # Decode and validate token payload = auth_service.decode_access_token(token) if payload is None: return None user_id: str = payload.get("sub") if user_id is None: return None # Get user from database user = db.query(User).filter(User.id == user_id).first() return user except Exception as e: logger.debug(f"Optional auth validation failed: {e}") return None