Team Ai
Apppublic

ruby2210/todo-manager

sourceHugging Facemitupdated 9mo agoView on Hugging Face
0likes
middleware.py96 linesDownload Raw Back to auth
1from fastapi import Request, HTTPException, status2from fastapi.security.http import HTTPBearer, HTTPAuthorizationCredentials3from typing import Optional4from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint5from starlette.responses import Response6from src.auth.utils import verify_token7 8 9class AuthMiddleware(BaseHTTPMiddleware):10    """11    Global authentication middleware for all /api/ routes.12 13    This middleware automatically validates JWT tokens for all API routes14    and attaches user information to the request state.15    """16 17    def __init__(self, app, exempt_paths: Optional[list] = None):18        super().__init__(app)19        self.exempt_paths = exempt_paths or [20            "/health",21            "/docs",22            "/redoc",23            "/openapi.json",24            "/api/auth/login",25            "/api/auth/signup",26        ]27        self.security = HTTPBearer(28            auto_error=False29        )  # Don't auto-error, handle manually30 31    async def dispatch(32        self, request: Request, call_next: RequestResponseEndpoint33    ) -> Response:34        # Skip authentication for exempt paths35        if request.url.path in self.exempt_paths or request.url.path.startswith(36            "/api/docs"37        ):38            response = await call_next(request)39            return response40 41        # Skip authentication for non-API routes (for now, we'll protect all /api/ routes)42        if (43            not request.url.path.startswith("/api/")44            or request.url.path == "/api/health"45        ):46            response = await call_next(request)47            return response48 49        # Extract authorization header50        auth_header = request.headers.get("Authorization")51        if not auth_header:52            raise HTTPException(53                status_code=status.HTTP_401_UNAUTHORIZED,54                detail="Authorization header missing",55                headers={"WWW-Authenticate": "Bearer"},56            )57 58        # Verify token59        token = auth_header.replace("Bearer ", "")60        payload = verify_token(token)61 62        if not payload:63            raise HTTPException(64                status_code=status.HTTP_401_UNAUTHORIZED,65                detail="Invalid or expired token",66                headers={"WWW-Authenticate": "Bearer"},67            )68 69        # Add user info to request state for use in endpoints70        user_id = payload.get("sub") or payload.get("user_id")71        if user_id:72            request.state.user_id = user_id73        else:74            raise HTTPException(75                status_code=status.HTTP_401_UNAUTHORIZED,76                detail="User ID not found in token",77                headers={"WWW-Authenticate": "Bearer"},78            )79 80        response = await call_next(request)81        return response82 83 84# Alternative: A simpler approach using dependency injection at the router level85# This is often preferred in FastAPI applications86from fastapi import Depends87from src.api.deps import get_current_user88 89 90def get_auth_dependency():91    """92    Returns the authentication dependency for use in routes.93    This can be used to add authentication to specific routes or routers.94    """95    return Depends(get_current_user)96