Samad14's picture
Add sequencing pipeline (FASTQ -> QC -> alignment -> variant calling -> report)
da793ed verified
Raw
History Blame Contribute Delete
2.55 kB
import base64
import hashlib
import json
import logging
from fastapi import Depends, HTTPException, Request
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
logger = logging.getLogger(__name__)
security = HTTPBearer(auto_error=False)
async def get_user_id(
credentials: HTTPAuthorizationCredentials | None = Depends(security),
) -> str | None:
"""Extract Supabase user_id from the Bearer JWT, or None for anonymous users."""
if credentials is None:
return None
try:
parts = credentials.credentials.split(".")
if len(parts) != 3:
return None
payload = parts[1]
padding = 4 - len(payload) % 4
if padding != 4:
payload += "=" * padding
decoded = base64.urlsafe_b64decode(payload)
claims = json.loads(decoded)
return claims.get("sub")
except Exception:
logger.debug("Failed to decode JWT", exc_info=True)
return None
async def require_user_id(
credentials: HTTPAuthorizationCredentials | None = Depends(security),
) -> str:
"""Like get_user_id but raises 401 if no valid JWT is present."""
uid = await get_user_id(credentials)
if not uid:
raise HTTPException(status_code=401, detail="Authentication required")
return uid
async def get_user_id_from_api_key(request: Request) -> str | None:
"""Authenticate via X-API-Key header. Returns user_id or None."""
api_key = request.headers.get("X-API-Key")
if not api_key:
return None
key_hash = hashlib.sha256(api_key.encode()).hexdigest()
try:
from app.services.supabase import get_supabase
supabase = get_supabase()
result = supabase.table("api_keys").select("user_id").eq("key_hash", key_hash).execute()
if result.data:
uid = result.data[0]["user_id"]
supabase.table("api_keys").update({"last_used_at": "now()"}).eq("key_hash", key_hash).execute()
return uid
except Exception:
pass
return None
async def require_user_or_api_key(
credentials: HTTPAuthorizationCredentials | None = Depends(security),
request: Request = None,
) -> str:
"""Accepts either a Bearer JWT or X-API-Key header."""
uid = await get_user_id(credentials)
if uid:
return uid
uid = await get_user_id_from_api_key(request)
if uid:
return uid
raise HTTPException(status_code=401, detail="Authentication required")