| # auth/clerk.py | |
| from jose import jwt | |
| import httpx | |
| from fastapi import HTTPException | |
| CLERK_ISSUER = "https://known-porpoise-86.clerk.accounts.dev" # e.g. https://enabling-terrapin-28.clerk.accounts.dev | |
| CLERK_AUDIENCE = "https://fair-work-contract.vercel.app/" # Your frontend origin | |
| async def verify_clerk_jwt(token: str) -> dict: | |
| try: | |
| async with httpx.AsyncClient() as client: | |
| jwks_url = f"{CLERK_ISSUER}/.well-known/jwks.json" | |
| resp = await client.get(jwks_url) | |
| jwks = resp.json()["keys"] | |
| unverified_header = jwt.get_unverified_header(token) | |
| kid = unverified_header.get("kid") | |
| key = next((k for k in jwks if k["kid"] == kid), None) | |
| if not key: | |
| raise HTTPException(status_code=401, detail="Public key not found") | |
| payload = jwt.decode( | |
| token, | |
| key, | |
| algorithms=["RS256"], | |
| audience=CLERK_AUDIENCE, | |
| issuer=CLERK_ISSUER | |
| ) | |
| return payload | |
| except Exception as e: | |
| raise HTTPException(status_code=401, detail=f"Invalid Clerk JWT: {str(e)}") | |