modcomms/backend/app/dependencies/auth.py
michael 04527d65db Add MSAL debug logging to frontend and backend
- Frontend: Set MSAL log level to Info, add [MSAL] prefix
- Frontend: Add [MSAL Auth] logs for token acquisition
- Frontend: Add [MSAL Login] logs for login popup flow
- Backend: Add [MSAL Backend] logs for token verification
- Backend: Add [MSAL Backend] logs for auth dependency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 13:11:30 -06:00

74 lines
2.7 KiB
Python
Executable file

"""
FastAPI authentication dependencies.
Provides dependency functions for securing REST endpoints with Azure AD token verification.
"""
import logging
from typing import Optional
from fastapi import Header, HTTPException, status
from app.config import settings
from app.services.auth_service import verify_access_token
logger = logging.getLogger(__name__)
async def get_current_user(authorization: Optional[str] = Header(None)) -> dict:
"""
FastAPI dependency to verify the access token and return user claims.
Use as a dependency on protected endpoints:
@app.get("/protected")
async def protected_route(user: dict = Depends(get_current_user)):
return {"message": f"Hello {user.get('name')}"}
Args:
authorization: The Authorization header value (Bearer <token>)
Returns:
The token claims dict containing user information
Raises:
HTTPException: 401 if token is missing or invalid
"""
logger.info("[MSAL Backend] get_current_user dependency called")
# If auth is disabled, return mock user immediately
if settings.DISABLE_AUTH:
logger.info("[MSAL Backend] Auth disabled - returning mock user")
return {"sub": "dev-user", "name": "Development User", "preferred_username": "dev@localhost"}
if not authorization:
logger.warning("[MSAL Backend] Missing authorization header")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Missing authorization header",
headers={"WWW-Authenticate": "Bearer"},
)
logger.info(f"[MSAL Backend] Authorization header present, length: {len(authorization)}")
# Extract token from "Bearer <token>" format
parts = authorization.split()
if len(parts) != 2 or parts[0].lower() != "bearer":
logger.warning(f"[MSAL Backend] Invalid auth header format: {parts[0] if parts else 'empty'}")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authorization header format. Expected: Bearer <token>",
headers={"WWW-Authenticate": "Bearer"},
)
token = parts[1]
logger.info("[MSAL Backend] Extracted Bearer token, calling verify_access_token...")
claims = await verify_access_token(token)
if not claims:
logger.warning("[MSAL Backend] Token verification failed - returning 401")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or expired token",
headers={"WWW-Authenticate": "Bearer"},
)
logger.info(f"[MSAL Backend] Authentication successful for: {claims.get('name', 'unknown')}")
return claims