JWT SImple implimentation
This commit is contained in:
parent
e20f0c713f
commit
b1527defc2
|
|
@ -1,40 +1,63 @@
|
|||
# backend/auth/jwt.py
|
||||
# auth/jwt.py
|
||||
|
||||
import requests
|
||||
from jose import jwt
|
||||
from jose.exceptions import JWTError
|
||||
from fastapi import Depends, HTTPException, status
|
||||
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
||||
from typing import Dict
|
||||
from fastapi import Request, HTTPException, status, Depends
|
||||
from jose import jwt, JWTError
|
||||
import os
|
||||
|
||||
SUPABASE_PROJECT_ID = "lcoretjgpauozmuoedus" # <-- Replace with your project ref
|
||||
SUPABASE_JWKS_URL = f"https://{SUPABASE_PROJECT_ID}.supabase.co/auth/v1/keys"
|
||||
JWT_SECRET = os.getenv("SUPABASE_JWT_SECRET")
|
||||
ALGORITHM = "HS256"
|
||||
|
||||
# Fetch JWKs from Supabase
|
||||
jwks = requests.get(SUPABASE_JWKS_URL).json()
|
||||
|
||||
# Define FastAPI's bearer auth scheme
|
||||
auth_scheme = HTTPBearer()
|
||||
def get_token_from_header(request: Request) -> str:
|
||||
auth_header = request.headers.get("Authorization")
|
||||
if not auth_header or not auth_header.startswith("Bearer "):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Missing or invalid Authorization header",
|
||||
)
|
||||
return auth_header.split(" ")[1]
|
||||
|
||||
# Decode + verify JWT token
|
||||
def verify_jwt_token(token: str) -> Dict:
|
||||
|
||||
# def verify_jwt_token(token: str) -> dict:
|
||||
# try:
|
||||
# payload = jwt.decode(token, JWT_SECRET, algorithms=[ALGORITHM])
|
||||
# return payload
|
||||
# except JWTError as e:
|
||||
# raise HTTPException(
|
||||
# status_code=status.HTTP_403_FORBIDDEN,
|
||||
# detail=f"Invalid JWT token: {str(e)}",
|
||||
# )
|
||||
def verify_jwt_token(token: str) -> dict:
|
||||
try:
|
||||
header = jwt.get_unverified_header(token)
|
||||
kid = header["kid"]
|
||||
payload = jwt.decode(
|
||||
token,
|
||||
JWT_SECRET,
|
||||
algorithms=[ALGORITHM],
|
||||
options={"verify_aud": False} # <- Disable audience verification
|
||||
)
|
||||
|
||||
key = next((k for k in jwks["keys"] if k["kid"] == kid), None)
|
||||
if key is None:
|
||||
raise HTTPException(status_code=403, detail="Invalid Supabase JWT: No matching key")
|
||||
|
||||
payload = jwt.decode(token, key, algorithms=["RS256"], options={"verify_aud": False})
|
||||
return payload
|
||||
|
||||
except JWTError as e:
|
||||
raise HTTPException(status_code=403, detail=f"Invalid Supabase JWT: {str(e)}")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=f"Invalid JWT token: {str(e)}",
|
||||
)
|
||||
|
||||
# Dependency for protected endpoints
|
||||
def get_current_user(
|
||||
credentials: HTTPAuthorizationCredentials = Depends(auth_scheme)
|
||||
) -> Dict:
|
||||
token = credentials.credentials
|
||||
return verify_jwt_token(token)
|
||||
|
||||
def get_current_user(request: Request):
|
||||
token = get_token_from_header(request)
|
||||
payload = verify_jwt_token(token)
|
||||
|
||||
user_id = payload.get("sub")
|
||||
if not user_id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="JWT missing 'sub' field",
|
||||
)
|
||||
print("🔐 JWT payload seen by API →", payload)
|
||||
return {
|
||||
"id": user_id,
|
||||
"email": payload.get("email"),
|
||||
"role": payload.get("role"),
|
||||
"tenant_id": payload.get("tenant_id", "unknown"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,10 +24,13 @@ def supabase_check():
|
|||
return JSONResponse(status_code=500, content={"status": "error", "error": str(e)})
|
||||
|
||||
@app.get("/me")
|
||||
def me(user: dict = Depends(get_current_user)):
|
||||
def me(current: dict = Depends(get_current_user)):
|
||||
return {
|
||||
"id": user.get("sub"),
|
||||
"email": user.get("email"),
|
||||
"role": user.get("role"),
|
||||
"tenant_id": user.get("tenant_id", "unknown")
|
||||
"id": current["id"],
|
||||
"email": current["email"],
|
||||
"role": current["role"],
|
||||
"tenant_id": current["tenant_id"],
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue