from __future__ import annotations from dataclasses import dataclass from fastapi import HTTPException, Request from huggingface_hub import parse_huggingface_oauth from app.core.config import Settings @dataclass(frozen=True, slots=True) class UserContext: id: str username: str display_name: str | None avatar_url: str | None authenticated: bool def get_optional_user(request: Request) -> UserContext | None: if "session" not in request.scope: return None try: oauth_info = parse_huggingface_oauth(request) except AssertionError: return None if oauth_info is None: return None user_info = oauth_info.user_info username = user_info.preferred_username or user_info.sub or "hf-user" display_name = user_info.name or username return UserContext( id=user_info.sub or username, username=username, display_name=display_name, avatar_url=user_info.picture, authenticated=True, ) def require_user(request: Request, settings: Settings) -> UserContext: user = get_optional_user(request) if user is not None: return user if settings.require_auth: raise HTTPException(status_code=401, detail="Sign in with Hugging Face to use this service.") return UserContext( id="anonymous", username="anonymous", display_name="Anonymous", avatar_url=None, authenticated=False, )