Stores & Events
Overview
@authrim/sveltekit uses two complementary mechanisms for state management:
- Svelte Stores — Reactive
Readablestores for UI binding - Events — Typed event emitter for side effects and custom logic
Events are the source of truth. Stores are automatically updated (projected) from events — you never write to stores directly.
Stores
Access stores via auth.stores:
<script lang="ts"> import { getAuthContext } from '@authrim/sveltekit';
const auth = getAuthContext(); const { session, user, isAuthenticated, loadingState, error } = auth.stores;</script>
{#if $isAuthenticated} <p>Hello, {$user?.displayName}</p>{:else} <p>Not signed in</p>{/if}Store Reference
| Store | Type | Description |
|---|---|---|
session | Readable<Session | null> | Current session object |
user | Readable<User | null> | Current user object |
isAuthenticated | Readable<boolean> | Derived from session !== null |
loadingState | Readable<AuthLoadingState> | Current loading state |
error | Readable<AuthError | null> | Last authentication error |
AuthLoadingState
type AuthLoadingState = | 'idle' // Stable — no operation in progress | 'initializing' // Initial session check | 'authenticating' // Login/signup in progress | 'refreshing' // Session refresh in progress | 'signing_out'; // Sign out in progress'idle' is the resting state. After any operation completes (success or error), the state returns to 'idle'.
Loading State Example
<script lang="ts"> import { getAuthContext } from '@authrim/sveltekit';
const auth = getAuthContext(); const { loadingState, error } = auth.stores;</script>
{#if $loadingState === 'authenticating'} <div class="overlay">Signing in...</div>{:else if $loadingState === 'signing_out'} <div class="overlay">Signing out...</div>{/if}
{#if $error} <div class="alert" role="alert"> <p>{$error.message}</p> <code>{$error.code}</code> </div>{/if}Store Error Type
interface AuthError { code: string; // Error code (e.g., 'AR003001') message: string; // Human-readable message details?: unknown; // Additional metadata}Events
Subscribe to auth events via auth.on(). Returns an unsubscribe function.
const unsubscribe = auth.on('auth:login', (payload) => { console.log('Logged in:', payload.user.displayName); console.log('Method:', payload.method); // 'passkey' | 'emailCode' | 'social'});
// Cleanupunsubscribe();Event Reference
| Event | Payload | Triggered When |
|---|---|---|
auth:login | { session, user, method } | User successfully logs in |
auth:logout | { redirectUri? } | User signs out |
auth:error | { error: AuthError } | Authentication error occurs |
session:changed | { session, user } | Session or user data changes |
session:expired | { reason } | Session becomes invalid |
token:refreshed | { session } | Token successfully refreshed |
Event Payload Types
interface AuthEventPayloads { 'auth:login': { session: Session; user: User; method: 'passkey' | 'emailCode' | 'social'; }; 'auth:logout': { redirectUri?: string }; 'auth:error': { error: AuthError }; 'session:changed': { session: Session | null; user: User | null }; 'session:expired': { reason: 'timeout' | 'revoked' | 'logout' }; 'token:refreshed': { session: Session };}Event Usage in Components
<script lang="ts"> import { onMount, onDestroy } from 'svelte'; import { getAuthContext } from '@authrim/sveltekit'; import { goto } from '$app/navigation';
const auth = getAuthContext();
let unsubscribes: (() => void)[] = [];
onMount(() => { unsubscribes.push( auth.on('auth:login', () => { goto('/dashboard'); }), auth.on('session:expired', ({ reason }) => { if (reason === 'revoked') { goto('/login?reason=session-revoked'); } }), ); });
onDestroy(() => { unsubscribes.forEach(fn => fn()); });</script>Event → Store Projection
Events automatically update stores. You don’t need to manually sync them:
| Event | Store Updates |
|---|---|
auth:login | session ← payload.session, user ← payload.user, loadingState ← 'idle', error ← null |
auth:logout | session ← null, user ← null, loadingState ← 'idle', error ← null |
auth:error | error ← payload.error, loadingState ← 'idle' |
session:changed | session ← payload.session, user ← payload.user |
SSR Synchronization
When using AuthProvider with SSR data, the initial session is synced synchronously (before first render) to avoid hydration mismatch:
sequenceDiagram
participant Server as Server (hooks)
participant Layout as +layout.svelte
participant Provider as AuthProvider
participant Stores as Svelte Stores
Server->>Layout: SSR auth data
Layout->>Provider: initialSession, initialUser
Provider->>Stores: _syncFromSSR() (synchronous)
Note over Stores: session & user set
before first render
Provider->>Provider: onMount: revalidate in background
This ensures $isAuthenticated is correct on the first render — no flash of unauthenticated content.
Next Steps
- Components — AuthProvider and other components
- Authentication — Using auth methods with stores
- Configuration — Advanced store configuration