/** * Moxiegen Authentication Module * Handles Auth0 authentication, login/logout, and token management */ class MoxieAuth { constructor() { this.auth0Client = null; this.isAuthenticated = false; this.user = null; this.token = null; this.isInitialized = false; } /** * Initialize Auth0 client */ async init() { if (this.isInitialized) return; try { // Dynamically load Auth0 SPA SDK if not already loaded if (typeof auth0 === 'undefined') { await this.loadScript('https://cdn.auth0.com/js/auth0-spa-js/2.0/auth0-spa-js.production.js'); } // Create Auth0 client this.auth0Client = await auth0.createAuth0Client({ domain: CONFIG.auth0.domain, clientId: CONFIG.auth0.clientId, authorizationParams: { audience: CONFIG.auth0.audience, redirect_uri: CONFIG.auth0.redirectUri }, cacheLocation: 'localstorage', useRefreshTokens: true }); // Check if coming back from Auth0 redirect const query = window.location.search; if (query.includes('code=') && query.includes('state=')) { await this.auth0Client.handleRedirectCallback(); // Remove query params from URL window.history.replaceState({}, document.title, window.location.pathname); } // Check authentication status this.isAuthenticated = await this.auth0Client.isAuthenticated(); if (this.isAuthenticated) { this.user = await this.auth0Client.getUser(); this.token = await this.auth0Client.getTokenSilently(); } this.isInitialized = true; console.log('Auth0 initialized. Authenticated:', this.isAuthenticated); } catch (error) { console.error('Failed to initialize Auth0:', error); throw error; } } /** * Load external script */ loadScript(src) { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = src; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); } /** * Login - redirect to Auth0 */ async login(returnTo = null) { if (!this.auth0Client) { await this.init(); } await this.auth0Client.loginWithRedirect({ authorizationParams: { audience: CONFIG.auth0.audience, redirect_uri: returnTo || CONFIG.auth0.redirectUri } }); } /** * Logout */ async logout() { if (!this.auth0Client) { await this.init(); } // Clear local state this.isAuthenticated = false; this.user = null; this.token = null; // Logout from Auth0 await this.auth0Client.logout({ logoutParams: { returnTo: CONFIG.auth0.logoutUri } }); } /** * Get access token (silently refreshes if needed) */ async getToken() { if (!this.auth0Client) { await this.init(); } if (!this.isAuthenticated) { return null; } try { this.token = await this.auth0Client.getTokenSilently(); return this.token; } catch (error) { console.error('Failed to get token:', error); // Token might be expired, try to re-authenticate this.isAuthenticated = false; return null; } } /** * Get current user */ async getUser() { if (!this.auth0Client) { await this.init(); } return this.user; } /** * Check if user is authenticated */ async checkAuth() { if (!this.auth0Client) { await this.init(); } this.isAuthenticated = await this.auth0Client.isAuthenticated(); if (this.isAuthenticated) { this.user = await this.auth0Client.getUser(); this.token = await this.auth0Client.getTokenSilently(); } return this.isAuthenticated; } /** * Check if user has specific role */ hasRole(role) { if (!this.user) return false; const roles = this.user['https://moxiegen.client.guacamolebox.net/roles'] || []; return roles.includes(role); } } // Create singleton instance const moxieAuth = new MoxieAuth(); // Export for use in other modules window.moxieAuth = moxieAuth;