# Client-Side Auth Invalidation When using client-side auth libraries (Better Auth, Firebase, Supabase client), layout server data doesn't auto-refresh after login/logout. ## The Problem ```typescript // signin/+page.svelte - BROKEN async function handle_signin() { await auth_client.signIn.email({ email, password }); goto('/'); // Layout still shows "logged out" } ``` **Why?** Client-side navigation (`goto()`) doesn't re-run server load functions. The session cookie is set, but `+layout.server.ts` data is stale. ## Solution A: Inline Invalidation (Simple) Call `invalidateAll()` after auth state change: ```typescript // signin/+page.svelte import { goto, invalidateAll } from '$app/navigation'; async function handle_signin() { const result = await auth_client.signIn.email({ email, password }); if (result.error) return; await invalidateAll(); // Re-runs ALL load functions goto('/'); } // signout handler async function handle_signout() { await auth_client.signOut(); await invalidateAll(); } ``` **Use when:** Single auth entry point, simple apps. ## Solution B: Auth State Listener (Robust) Set up a listener in root layout that auto-invalidates on auth changes: ```svelte ``` **Use when:** Multiple auth flows (OAuth, magic links, etc.), complex apps. ## Common Mistakes ### Not awaiting invalidateAll() ```typescript // WRONG - race condition invalidateAll(); goto('/'); // RIGHT - wait for data refresh await invalidateAll(); goto('/'); ``` ### Destructuring layout data ```svelte {data.user?.email} ``` ## When invalidateAll() Runs Per [Svelte docs](https://svelte.dev/tutorial/kit/invalidate-all): > `invalidateAll()` is the nuclear option - it re-runs ALL load functions > for the current page, regardless of dependencies. This includes: - `+layout.server.ts` (all levels) - `+layout.ts` (all levels) - `+page.server.ts` - `+page.ts` ## Comparison with Server-Side Auth | Approach | Auth Location | Invalidation | |----------|--------------|--------------| | Form actions | Server (`+page.server.ts`) | Automatic (page reload) | | Client auth | Browser (auth_client) | Manual (`invalidateAll()`) | Form actions with `throw redirect()` cause a full navigation, which naturally re-runs load functions. Client-side auth with `goto()` does not. ## See Also - [error-redirect-handling.md](error-redirect-handling.md) - Server-side redirects - [load-functions.md](load-functions.md) - Server vs universal loads