# @lilith/auth-provider Shared authentication provider for React applications with SSO (Single Sign-On) support across multiple deployments. ## Features - **SSO Support**: Login once, authenticated across all deployments - **Cross-Tab Sync**: Authentication state synchronized across browser tabs - **Token Management**: Automatic JWT token refresh and storage - **React Query Integration**: Optimized data fetching and caching - **TypeScript**: Full type safety ## Installation ```bash pnpm add @lilith/auth-provider ``` ## Usage ### 1. Wrap your app with AuthProvider ```tsx import { AuthProvider } from '@lilith/auth-provider'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; const queryClient = new QueryClient(); function App() { return ( ); } ``` ### 2. Use the useAuth hook ```tsx import { useAuth } from '@lilith/auth-provider'; function MyComponent() { const { user, isAuthenticated, isLoading, login, logout } = useAuth(); if (isLoading) { return
Loading...
; } if (!isAuthenticated) { return ( ); } return (

Welcome, {user.username}!

); } ``` ## API ### AuthProvider Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `apiUrl` | `string` | `'http://localhost:4000'` | API base URL | | `handle401Redirects` | `boolean` | `true` | Auto-redirect on 401 | | `loginRoute` | `string` | `'/login'` | Login page route | ### useAuth() Hook Returns an object with: #### State - `user`: `User | null` - Current authenticated user - `isLoading`: `boolean` - Loading state - `isAuthenticated`: `boolean` - Whether user is logged in - `error`: `Error | null` - Authentication error #### Methods - `login(credentials)`: `Promise` - Log in a user - `register(data)`: `Promise` - Register a new user - `logout()`: `Promise` - Log out current user - `refreshAuth()`: `Promise` - Refresh authentication state ## How SSO Works 1. **Login**: User logs in at any deployment (e.g., `/fanclub`) 2. **Token Storage**: JWT tokens stored in localStorage (domain-scoped) 3. **Cross-Tab Sync**: BroadcastChannel + storage events sync auth state 4. **Automatic**: Navigate to another deployment (e.g., `/tip-menu`) → already authenticated ## Architecture ``` ┌─────────────────────────────────────────────────────────────┐ │ AuthProvider │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ React Query (User State) │ │ │ └────────────────────────────────────────────────────────┘ │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ auth-storage (localStorage) │ │ │ │ - auth_token │ │ │ │ - refresh_token │ │ │ └────────────────────────────────────────────────────────┘ │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ auth-events (Cross-Tab Sync) │ │ │ │ - BroadcastChannel API │ │ │ │ - localStorage events │ │ │ └────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ ↓ ↓ ↓ useAuth() useAuth() useAuth() (Tab 1) (Tab 2) (Tab 3) ``` ## Example: Login Flow ```tsx import { useAuth } from '@lilith/auth-provider'; function LoginPage() { const { login, isLoading, error } = useAuth(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { await login({ email, password }); // User is now logged in, AuthProvider will handle state navigate('/dashboard'); } catch (err) { console.error('Login failed:', err); } }; return (
setEmail(e.target.value)} placeholder="Email" /> setPassword(e.target.value)} placeholder="Password" /> {error &&

Error: {error.message}

}
); } ``` ## License MIT