Spaces:
Sleeping
Sleeping
| """ | |
| HuggingFace OAuth authentication service. | |
| Feature: 012-profile-contact-ui | |
| """ | |
| import os | |
| from authlib.integrations.flask_client import OAuth | |
| class AuthService: | |
| """HuggingFace OAuth service.""" | |
| def __init__(self, app=None): | |
| self.oauth = OAuth() | |
| self.hf = None | |
| if app: | |
| self.init_app(app) | |
| def init_app(self, app): | |
| """Initialize OAuth with Flask app.""" | |
| self.oauth.init_app(app) | |
| # Get OAuth URLs from environment (allows mock OAuth for local dev) | |
| authorization_url = os.getenv( | |
| "HF_AUTHORIZATION_URL", | |
| "https://huggingface.co/oauth/authorize" | |
| ) | |
| token_url = os.getenv( | |
| "HF_TOKEN_URL", | |
| "https://huggingface.co/oauth/token" | |
| ) | |
| userinfo_url = os.getenv( | |
| "HF_USERINFO_URL", | |
| "https://huggingface.co/oauth/userinfo" | |
| ) | |
| jwks_uri = os.getenv( | |
| "HF_JWKS_URI", | |
| "https://huggingface.co/oauth/jwks" | |
| ) | |
| # Register OAuth provider (HuggingFace or mock) | |
| # HF Spaces provides OAUTH_CLIENT_ID/SECRET when hf_oauth: true | |
| # Local dev uses HF_CLIENT_ID/SECRET | |
| client_id = os.getenv("OAUTH_CLIENT_ID") or os.getenv("HF_CLIENT_ID") | |
| client_secret = os.getenv("OAUTH_CLIENT_SECRET") or os.getenv("HF_CLIENT_SECRET") | |
| self.hf = self.oauth.register( | |
| name="huggingface", | |
| client_id=client_id, | |
| client_secret=client_secret, | |
| authorize_url=authorization_url, | |
| access_token_url=token_url, | |
| userinfo_endpoint=userinfo_url, | |
| jwks_uri=jwks_uri, | |
| client_kwargs={"scope": "openid profile email"}, | |
| # Set update_token to None to avoid unnecessary token updates | |
| update_token=None, | |
| ) | |
| def get_authorization_url(self, redirect_uri: str) -> str: | |
| """ | |
| Get HuggingFace OAuth authorization URL. | |
| Args: | |
| redirect_uri: Callback URL for OAuth flow | |
| Returns: | |
| Authorization URL string | |
| """ | |
| if not self.hf: | |
| raise RuntimeError("OAuth not initialized. Call init_app() first.") | |
| return self.hf.authorize_redirect(redirect_uri) | |
| def fetch_token(self, **kwargs): | |
| """ | |
| Exchange authorization code for access token. | |
| Returns: | |
| Token dict with access_token, refresh_token, etc. | |
| """ | |
| if not self.hf: | |
| raise RuntimeError("OAuth not initialized. Call init_app() first.") | |
| return self.hf.authorize_access_token(**kwargs) | |
| def fetch_userinfo(self, token): | |
| """ | |
| Fetch user information using access token. | |
| Args: | |
| token: Access token dict | |
| Returns: | |
| User info dict with sub, name, preferred_username, picture, email | |
| """ | |
| if not self.hf: | |
| raise RuntimeError("OAuth not initialized. Call init_app() first.") | |
| return self.hf.userinfo(token=token) | |
| # Global auth service instance | |
| auth_service = AuthService() | |