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 fastapi import Request, HTTPException, status, Depends
|
||||||
from jose import jwt
|
from jose import jwt, JWTError
|
||||||
from jose.exceptions import JWTError
|
import os
|
||||||
from fastapi import Depends, HTTPException, status
|
|
||||||
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
|
||||||
from typing import Dict
|
|
||||||
|
|
||||||
SUPABASE_PROJECT_ID = "lcoretjgpauozmuoedus" # <-- Replace with your project ref
|
JWT_SECRET = os.getenv("SUPABASE_JWT_SECRET")
|
||||||
SUPABASE_JWKS_URL = f"https://{SUPABASE_PROJECT_ID}.supabase.co/auth/v1/keys"
|
ALGORITHM = "HS256"
|
||||||
|
|
||||||
# Fetch JWKs from Supabase
|
|
||||||
jwks = requests.get(SUPABASE_JWKS_URL).json()
|
|
||||||
|
|
||||||
# Define FastAPI's bearer auth scheme
|
def get_token_from_header(request: Request) -> str:
|
||||||
auth_scheme = HTTPBearer()
|
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:
|
try:
|
||||||
header = jwt.get_unverified_header(token)
|
payload = jwt.decode(
|
||||||
kid = header["kid"]
|
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
|
return payload
|
||||||
|
|
||||||
except JWTError as e:
|
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(
|
def get_current_user(request: Request):
|
||||||
credentials: HTTPAuthorizationCredentials = Depends(auth_scheme)
|
token = get_token_from_header(request)
|
||||||
) -> Dict:
|
payload = verify_jwt_token(token)
|
||||||
token = credentials.credentials
|
|
||||||
return 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)})
|
return JSONResponse(status_code=500, content={"status": "error", "error": str(e)})
|
||||||
|
|
||||||
@app.get("/me")
|
@app.get("/me")
|
||||||
def me(user: dict = Depends(get_current_user)):
|
def me(current: dict = Depends(get_current_user)):
|
||||||
return {
|
return {
|
||||||
"id": user.get("sub"),
|
"id": current["id"],
|
||||||
"email": user.get("email"),
|
"email": current["email"],
|
||||||
"role": user.get("role"),
|
"role": current["role"],
|
||||||
"tenant_id": user.get("tenant_id", "unknown")
|
"tenant_id": current["tenant_id"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue