Spaces:
Running
Running
| from dataclasses import dataclass | |
| from typing import Any, Dict | |
| import requests | |
| from app.config.settings import settings | |
| class AuthSession: | |
| user: Dict[str, Any] | |
| access_token: str | |
| refresh_token: str | |
| class SignUpResult: | |
| user: Dict[str, Any] | |
| session: AuthSession | None | |
| confirmation_required: bool | |
| class SupabaseAuthClient: | |
| """Small Supabase Auth REST client for Streamlit.""" | |
| def __init__(self, url: str = None, anon_key: str = None): | |
| self.url = (url or settings.SUPABASE_URL).rstrip("/") | |
| self.anon_key = anon_key or settings.SUPABASE_ANON_KEY | |
| if not self.url or not self.anon_key: | |
| raise ValueError("SUPABASE_URL and SUPABASE_ANON_KEY are required for authentication.") | |
| self.auth_url = f"{self.url}/auth/v1" | |
| def sign_up(self, email: str, password: str, redirect_to: str = "") -> SignUpResult: | |
| params = {"redirect_to": redirect_to} if redirect_to else None | |
| response = requests.post( | |
| f"{self.auth_url}/signup", | |
| headers=self._headers(), | |
| params=params, | |
| json={"email": email, "password": password}, | |
| timeout=20, | |
| ) | |
| data = self._handle_response(response) | |
| user = data.get("user") | |
| access_token = data.get("access_token") | |
| if access_token: | |
| return SignUpResult( | |
| user=user, | |
| session=self._session_from_response(data), | |
| confirmation_required=False, | |
| ) | |
| if user: | |
| return SignUpResult(user=user, session=None, confirmation_required=True) | |
| raise RuntimeError("Supabase did not return a user. Check your Auth settings.") | |
| def sign_in(self, email: str, password: str) -> AuthSession: | |
| response = requests.post( | |
| f"{self.auth_url}/token?grant_type=password", | |
| headers=self._headers(), | |
| json={"email": email, "password": password}, | |
| timeout=20, | |
| ) | |
| data = self._handle_response(response) | |
| return self._session_from_response(data) | |
| def get_user(self, access_token: str) -> Dict[str, Any]: | |
| response = requests.get( | |
| f"{self.auth_url}/user", | |
| headers=self._headers(access_token), | |
| timeout=20, | |
| ) | |
| return self._handle_response(response) | |
| def refresh(self, refresh_token: str) -> AuthSession: | |
| response = requests.post( | |
| f"{self.auth_url}/token?grant_type=refresh_token", | |
| headers=self._headers(), | |
| json={"refresh_token": refresh_token}, | |
| timeout=20, | |
| ) | |
| data = self._handle_response(response) | |
| return self._session_from_response(data) | |
| def sign_out(self, access_token: str) -> None: | |
| response = requests.post( | |
| f"{self.auth_url}/logout", | |
| headers=self._headers(access_token), | |
| timeout=20, | |
| ) | |
| self._handle_response(response) | |
| def _headers(self, access_token: str = None) -> Dict[str, str]: | |
| return { | |
| "apikey": self.anon_key, | |
| "Authorization": f"Bearer {access_token or self.anon_key}", | |
| "Content-Type": "application/json", | |
| } | |
| def _session_from_response(self, data: Dict[str, Any]) -> AuthSession: | |
| user = data.get("user") | |
| access_token = data.get("access_token") | |
| refresh_token = data.get("refresh_token") | |
| if not user: | |
| raise RuntimeError("Supabase did not return a user. Check whether email confirmation is required.") | |
| if not access_token: | |
| raise RuntimeError("Supabase did not return an access token.") | |
| return AuthSession( | |
| user=user, | |
| access_token=access_token, | |
| refresh_token=refresh_token or "", | |
| ) | |
| def _handle_response(self, response: requests.Response) -> Dict[str, Any]: | |
| if response.ok: | |
| return response.json() if response.content else {} | |
| try: | |
| data = response.json() | |
| message = data.get("msg") or data.get("message") or data.get("error_description") or data.get("error") | |
| except Exception: | |
| message = response.text | |
| raise RuntimeError(message or f"Supabase auth request failed with status {response.status_code}") | |
| def get_auth_client() -> SupabaseAuthClient: | |
| return SupabaseAuthClient() | |