import os from fastapi import Depends, HTTPException, status from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from jose import jwt, JWTError security = HTTPBearer() def get_jwt_secret() -> str: """Get JWT secret from environment variable.""" secret = os.getenv("JWT_SECRET") if not secret: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="JWT_SECRET not configured" ) return secret def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)) -> dict: """ Verify Bearer token signature. Returns the decoded token payload if valid. Raises HTTPException if invalid. """ token = credentials.credentials jwt_secret = get_jwt_secret() try: # Decode and verify the JWT token payload = jwt.decode( token, jwt_secret, algorithms=["HS256"], options={"verify_aud": False} # Clerk tokens may not have standard audience ) return payload except JWTError as e: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=f"Invalid token: {str(e)}", headers={"WWW-Authenticate": "Bearer"}, ) def get_current_user(token_payload: dict = Depends(verify_token)) -> dict: """ Extract user information from verified token. """ user_id = token_payload.get("sub") if not user_id: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token: missing user ID", headers={"WWW-Authenticate": "Bearer"}, ) return { "user_id": user_id, "email": token_payload.get("email"), "claims": token_payload }