Spaces:
No application file
No application file
| 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 | |
| } | |