Spaces:
Running
Running
| // HuggingFace OAuth authentication utilities (Server-side flow for Docker Spaces) | |
| const STORAGE_KEY = 'hf_oauth_token'; | |
| const USER_INFO_KEY = 'hf_user_info'; | |
| const DEV_MODE_KEY = 'hf_dev_mode'; | |
| const API_BASE = '/api'; | |
| // Check if we're in development mode (localhost) | |
| const isDevelopment = typeof window !== 'undefined' && | |
| (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'); | |
| export interface OAuthUserInfo { | |
| id?: string; | |
| sub?: string; | |
| name: string; | |
| preferred_username?: string; | |
| preferredUsername?: string; | |
| picture?: string; | |
| avatarUrl?: string; | |
| } | |
| export interface OAuthResult { | |
| accessToken: string; | |
| accessTokenExpiresAt: Date; | |
| userInfo: OAuthUserInfo; | |
| } | |
| /** | |
| * Initialize OAuth and check if user is logged in | |
| * Returns OAuth result if user is already logged in | |
| */ | |
| export async function initializeOAuth(): Promise<OAuthResult | null> { | |
| try { | |
| // In development mode, check for dev mode login first | |
| if (isDevelopment && isDevModeEnabled()) { | |
| const storedToken = getStoredToken(); | |
| const storedUserInfo = getStoredUserInfo(); | |
| if (storedToken && storedUserInfo) { | |
| return { | |
| accessToken: storedToken, | |
| accessTokenExpiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000), | |
| userInfo: storedUserInfo, | |
| }; | |
| } | |
| return null; | |
| } | |
| // Check if we're handling an OAuth callback (session parameter in URL) | |
| const urlParams = new URLSearchParams(window.location.search); | |
| const sessionToken = urlParams.get('session'); | |
| if (sessionToken) { | |
| // Fetch session data from backend | |
| try { | |
| const response = await fetch(`${API_BASE}/auth/session?session=${sessionToken}`); | |
| if (response.ok) { | |
| const data = await response.json(); | |
| // Normalize user info | |
| const userInfo: OAuthUserInfo = { | |
| id: data.user_info.sub || data.user_info.id, | |
| name: data.user_info.name, | |
| preferredUsername: data.user_info.preferred_username || data.user_info.preferredUsername, | |
| avatarUrl: data.user_info.picture || data.user_info.avatarUrl, | |
| }; | |
| const oauthResult: OAuthResult = { | |
| accessToken: data.access_token, | |
| accessTokenExpiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000), | |
| userInfo, | |
| }; | |
| // Store the OAuth result | |
| storeOAuthData(oauthResult); | |
| // Clean up URL | |
| window.history.replaceState({}, document.title, window.location.pathname); | |
| return oauthResult; | |
| } | |
| } catch (error) { | |
| console.error('Failed to fetch session:', error); | |
| } | |
| } | |
| // Check if we have stored credentials | |
| const storedToken = getStoredToken(); | |
| const storedUserInfo = getStoredUserInfo(); | |
| if (storedToken && storedUserInfo) { | |
| return { | |
| accessToken: storedToken, | |
| accessTokenExpiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000), | |
| userInfo: storedUserInfo, | |
| }; | |
| } | |
| return null; | |
| } catch (error) { | |
| console.error('OAuth initialization error:', error); | |
| return null; | |
| } | |
| } | |
| /** | |
| * Redirect to HuggingFace OAuth login page (via backend) | |
| */ | |
| export async function loginWithHuggingFace(): Promise<void> { | |
| try { | |
| // Call backend to get OAuth URL | |
| const response = await fetch(`${API_BASE}/auth/login`); | |
| if (!response.ok) { | |
| throw new Error('Failed to get login URL'); | |
| } | |
| const data = await response.json(); | |
| // Redirect to the OAuth authorization URL | |
| window.location.href = data.login_url; | |
| } catch (error) { | |
| console.error('Failed to initiate OAuth login:', error); | |
| throw new Error('Failed to start login process'); | |
| } | |
| } | |
| /** | |
| * Logout and clear stored credentials | |
| */ | |
| export function logout(): void { | |
| if (typeof window !== 'undefined') { | |
| localStorage.removeItem(STORAGE_KEY); | |
| localStorage.removeItem(USER_INFO_KEY); | |
| localStorage.removeItem(DEV_MODE_KEY); | |
| } | |
| } | |
| /** | |
| * Store OAuth data in localStorage | |
| */ | |
| function storeOAuthData(result: OAuthResult): void { | |
| if (typeof window !== 'undefined') { | |
| localStorage.setItem(STORAGE_KEY, result.accessToken); | |
| localStorage.setItem(USER_INFO_KEY, JSON.stringify(result.userInfo)); | |
| } | |
| } | |
| /** | |
| * Get stored access token | |
| */ | |
| export function getStoredToken(): string | null { | |
| if (typeof window !== 'undefined') { | |
| return localStorage.getItem(STORAGE_KEY); | |
| } | |
| return null; | |
| } | |
| /** | |
| * Get stored user info | |
| */ | |
| export function getStoredUserInfo(): OAuthUserInfo | null { | |
| if (typeof window !== 'undefined') { | |
| const userInfoStr = localStorage.getItem(USER_INFO_KEY); | |
| if (userInfoStr) { | |
| try { | |
| return JSON.parse(userInfoStr); | |
| } catch { | |
| return null; | |
| } | |
| } | |
| } | |
| return null; | |
| } | |
| /** | |
| * Check if user is authenticated | |
| */ | |
| export function isAuthenticated(): boolean { | |
| return getStoredToken() !== null; | |
| } | |
| /** | |
| * Development mode login (mock authentication) | |
| */ | |
| export function loginDevMode(username: string): OAuthResult { | |
| const mockToken = `dev_token_${username}_${Date.now()}`; | |
| const mockUserInfo: OAuthUserInfo = { | |
| id: `dev_${Date.now()}`, | |
| name: username, | |
| preferredUsername: username.toLowerCase().replace(/\s+/g, '_'), | |
| avatarUrl: `https://ui-avatars.com/api/?name=${encodeURIComponent(username)}&background=random&size=128`, | |
| }; | |
| const result: OAuthResult = { | |
| accessToken: mockToken, | |
| accessTokenExpiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000), | |
| userInfo: mockUserInfo, | |
| }; | |
| // Store the mock data | |
| storeOAuthData(result); | |
| // Mark as dev mode | |
| if (typeof window !== 'undefined') { | |
| localStorage.setItem(DEV_MODE_KEY, 'true'); | |
| } | |
| return result; | |
| } | |
| /** | |
| * Check if dev mode is enabled | |
| */ | |
| export function isDevModeEnabled(): boolean { | |
| if (typeof window !== 'undefined') { | |
| return localStorage.getItem(DEV_MODE_KEY) === 'true'; | |
| } | |
| return false; | |
| } | |
| /** | |
| * Check if we're in development environment | |
| */ | |
| export function isDevelopmentMode(): boolean { | |
| return isDevelopment; | |
| } | |