# @lilith/sso-client Client library for integrating with lilith-platform SSO authentication service. ## Features - Session-based authentication with HTTP-only cookies - Popup-based login/register flows - Automatic session checking and refresh - React hooks for easy integration - TypeScript support with full type definitions - PostMessage communication for cross-origin auth ## Installation ```bash pnpm add @lilith/sso-client ``` ## Usage ### Vanilla JavaScript ```typescript import { SSOClient } from '@lilith/sso-client'; const sso = new SSOClient({ ssoUrl: 'https://sso.lilithapps.com', checkInterval: 300000, // Check session every 5 minutes onAuthChange: (authenticated, user) => { console.log('Auth state changed:', authenticated, user); }, onError: (error) => { console.error('SSO error:', error); }, }); // Start automatic session checking sso.startAutoCheck(); // Login async function login() { try { const user = await sso.login(); console.log('Logged in:', user); } catch (error) { console.error('Login failed:', error); } } // Register async function register() { try { const user = await sso.register(); console.log('Registered:', user); } catch (error) { console.error('Registration failed:', error); } } // Logout async function logout() { try { await sso.logout(); console.log('Logged out'); } catch (error) { console.error('Logout failed:', error); } } // Check current session async function checkAuth() { const response = await sso.checkSession(); if (response.authenticated) { console.log('User:', response.user); } else { console.log('Not authenticated'); } } // Make authenticated requests async function fetchData() { const response = await sso.authenticatedFetch('https://api.lilithapps.com/data'); const data = await response.json(); return data; } // Cleanup when done sso.destroy(); ``` ### React Hooks ```typescript import { useSSO } from '@lilith/sso-client/react'; function App() { const { authenticated, user, loading, error, login, register, logout, authenticatedFetch, } = useSSO({ ssoUrl: 'https://sso.lilithapps.com', }); if (loading) { return
Loading...
; } if (error) { return
Error: {error.message}
; } if (!authenticated) { return (

Please log in

); } return (

Welcome, {user?.username}!

); } ``` ### Custom Popup Options ```typescript // Customize popup window size and title await sso.login({ width: 600, height: 700, title: 'Login to lilith.platform', }); await sso.register({ width: 600, height: 800, title: 'Create Account', }); ``` ### Manual Session Management ```typescript // Validate current session const isValid = await sso.validateSession(); // Refresh session TTL const refreshed = await sso.refreshSession(); // Get current user const user = sso.getUser(); // Check authentication status const authenticated = sso.isAuthenticated(); ``` ## API Reference ### SSOClient #### Constructor ```typescript new SSOClient(config: SSOConfig) ``` **Config Options:** - `ssoUrl` (required): URL of the SSO service - `checkInterval` (optional): Session check interval in ms (default: 300000) - `popupWidth` (optional): Default popup width (default: 500) - `popupHeight` (optional): Default popup height (default: 600) - `onAuthChange` (optional): Callback when auth state changes - `onError` (optional): Callback for errors #### Methods **`login(options?: PopupOptions): Promise`** Opens login popup and returns authenticated user. **`register(options?: PopupOptions): Promise`** Opens register popup and returns new user. **`logout(): Promise`** Logs out the current user and clears session. **`checkSession(): Promise`** Checks current session status and updates internal state. **`validateSession(): Promise`** Validates session cookie without updating state. **`refreshSession(): Promise`** Refreshes session TTL. **`startAutoCheck(): void`** Starts automatic session checking at configured interval. **`stopAutoCheck(): void`** Stops automatic session checking. **`getUser(): User | null`** Returns current authenticated user. **`isAuthenticated(): boolean`** Returns current authentication status. **`authenticatedFetch(url: string, options?: RequestInit): Promise`** Makes fetch request with credentials included. **`destroy(): void`** Cleanup method - stops auto-check, removes listeners, closes popups. ### useSSO Hook ```typescript const { authenticated, user, loading, error, login, register, logout, checkSession, authenticatedFetch, } = useSSO(config); ``` Returns: - `authenticated`: Boolean indicating auth status - `user`: Current user object or null - `loading`: Boolean indicating loading state - `error`: Error object or null - `login`: Function to open login popup - `register`: Function to open register popup - `logout`: Function to logout - `checkSession`: Function to manually check session - `authenticatedFetch`: Function to make authenticated requests ## Types ```typescript interface User { id: string; email: string; username: string; role: string; createdAt: string; updatedAt: string; } interface SSOConfig { ssoUrl: string; checkInterval?: number; popupWidth?: number; popupHeight?: number; onAuthChange?: (authenticated: boolean, user: User | null) => void; onError?: (error: Error) => void; } interface AuthState { authenticated: boolean; user: User | null; loading: boolean; error: Error | null; } interface PopupOptions { width?: number; height?: number; title?: string; } ``` ## How It Works 1. **Popup-based authentication**: Login/register opens SSO service in popup window 2. **PostMessage communication**: Popup sends success/error messages to parent 3. **HTTP-only cookies**: Session token stored securely in cookie 4. **Automatic session checking**: Periodically validates session in background 5. **Credentials included**: All requests include session cookie automatically ## Security - Session tokens stored in HTTP-only cookies (not accessible via JavaScript) - Cookies are domain-scoped (`.lilithapps.com` in production) - HTTPS enforced in production (`secure` flag) - SameSite protection against CSRF - PostMessage origin validation ## Development ```bash # Install dependencies pnpm install # Build pnpm build # Watch mode pnpm dev # Clean pnpm clean ``` ## MFA (Two-Factor Authentication) The SSO client includes full MFA support with two methods: TOTP and Email (no third-party SMS services for privacy). ### Checking MFA Status ```typescript const status = await sso.getMfaStatus(); console.log('MFA enabled:', status.enabled); console.log('Available methods:', status.methods); ``` ### Setting Up TOTP (Authenticator App) ```typescript // 1. Get setup data (secret + QR code) const setup = await sso.setupTotp(); console.log('QR Code:', setup.qrCodeDataUrl); console.log('Secret:', setup.secret); // 2. Verify with code from authenticator app const result = await sso.verifyTotpSetup(setup.secret, '123456'); console.log('Recovery codes:', result.codes); ``` ### Setting Up Email MFA ```typescript await sso.enableEmailMfa(); // Uses the user's registered email ``` ### Login with MFA ```typescript const result = await sso.loginWithCredentials(email, password); if (result.mfaRequired) { // MFA is required const pending = sso.getMfaPendingSession(); console.log('Available methods:', pending.availableMethods); // For email, send code first await sso.sendMfaCode('email'); // Verify MFA code const challenge = await sso.verifyMfaChallenge('email', '123456'); if (challenge.success) { console.log('Logged in:', challenge.user); } } else { // Direct login (no MFA) console.log('Logged in:', result.user); } ``` ### Using Recovery Codes ```typescript const result = await sso.verifyRecoveryCode('ABCD-1234'); if (result.success) { console.log('Logged in with recovery code'); if (result.warning) { console.log('Warning:', result.warning); } } ``` ### Managing MFA ```typescript // Set preferred method await sso.setPreferredMfaMethod('totp'); // Disable a method await sso.disableMfaMethod('email', 'password123'); // Regenerate recovery codes const codes = await sso.regenerateRecoveryCodes('password123'); console.log('New codes:', codes.codes); ``` ### MFA Callback ```typescript const sso = new SSOClient({ ssoUrl: 'https://sso.lilithapps.com', onMfaRequired: (pending) => { // Redirect to MFA challenge UI console.log('MFA required:', pending.availableMethods); }, }); ``` ## License UNLICENSED