Spaces:
No application file
No application file
| """ | |
| JWT verification middleware for FastAPI. | |
| Validates JWT tokens on all protected endpoints. | |
| """ | |
| from fastapi import Request | |
| from starlette.responses import JSONResponse | |
| from jose import JWTError, jwt | |
| from app.core.config import settings | |
| from typing import Callable | |
| async def verify_jwt_token(request: Request, call_next: Callable): | |
| # Skip CORS preflight requests | |
| if request.method == "OPTIONS": | |
| return await call_next(request) | |
| # Public endpoints that don't require authentication | |
| public_paths = [ | |
| "/api/auth/signup", | |
| "/api/auth/signin", | |
| "/docs", | |
| "/openapi.json", | |
| "/redoc", | |
| "/health", | |
| ] | |
| if request.url.path in public_paths: | |
| return await call_next(request) | |
| auth_header = request.headers.get("Authorization") | |
| if not auth_header: | |
| return JSONResponse( | |
| status_code=401, | |
| content={"detail": "Missing authentication token"}, | |
| ) | |
| if not auth_header.startswith("Bearer "): | |
| return JSONResponse( | |
| status_code=401, | |
| content={"detail": "Invalid authentication scheme"}, | |
| ) | |
| token = auth_header.replace("Bearer ", "") | |
| try: | |
| payload = jwt.decode( | |
| token, | |
| settings.JWT_SECRET, | |
| algorithms=[settings.JWT_ALGORITHM], | |
| ) | |
| user_id = payload.get("user_id") | |
| if not user_id: | |
| return JSONResponse( | |
| status_code=401, | |
| content={"detail": "Invalid token payload"}, | |
| ) | |
| request.state.user_id = user_id | |
| request.state.username = payload.get("username") | |
| except JWTError as e: | |
| return JSONResponse( | |
| status_code=401, | |
| content={"detail": f"Invalid or expired token: {str(e)}"}, | |
| ) | |
| return await call_next(request) | |