autonomy-labs / app /auth.py
ArunKr's picture
Upload folder using huggingface_hub
6a02a15 verified
from __future__ import annotations
import os
import time
from typing import Any
from fastapi import HTTPException, Request
_SUPABASE_TOKEN_CACHE: dict[str, tuple[float, dict[str, Any]]] = {}
async def verify_supabase_access_token(access_token: str) -> dict[str, Any]:
"""
Verifies a Supabase access token by calling Supabase Auth `GET /auth/v1/user`.
Uses a small in-memory TTL cache to avoid calling Supabase on every request.
"""
access_token = (access_token or "").strip()
if not access_token:
raise HTTPException(status_code=401, detail={"code": "missing_token", "message": "Missing access token"})
now = time.time()
cached = _SUPABASE_TOKEN_CACHE.get(access_token)
if cached and (now - cached[0]) < 30:
return cached[1]
supabase_url = os.environ.get("SUPABASE_URL")
supabase_key = os.environ.get("SUPABASE_KEY") or os.environ.get("SUPABASE_ANON_KEY")
if not supabase_url or not supabase_key:
raise HTTPException(
status_code=503,
detail={"code": "supabase_not_configured", "message": "Supabase is not configured"},
)
import httpx
headers = {"Authorization": f"Bearer {access_token}", "apikey": supabase_key}
url = f"{supabase_url.rstrip('/')}/auth/v1/user"
async with httpx.AsyncClient(timeout=10.0) as client:
resp = await client.get(url, headers=headers)
if resp.status_code != 200:
raise HTTPException(status_code=401, detail={"code": "invalid_session", "message": "Invalid or expired session"})
user = resp.json()
_SUPABASE_TOKEN_CACHE[access_token] = (now, user)
# Best-effort cache bound.
if len(_SUPABASE_TOKEN_CACHE) > 500:
for k in list(_SUPABASE_TOKEN_CACHE.keys())[:200]:
_SUPABASE_TOKEN_CACHE.pop(k, None)
return user
async def require_user_from_request(request: Request) -> dict[str, Any]:
auth = (request.headers.get("authorization") or "").strip()
if not auth.lower().startswith("bearer "):
raise HTTPException(
status_code=401,
detail={"code": "missing_bearer_token", "message": "Missing Authorization bearer token"},
)
token = auth.split(None, 1)[1].strip()
return await verify_supabase_access_token(token)