Example App
Overview
The example-sveltekit project is a complete, working demonstration of @authrim/sveltekit. Built with SvelteKit 2 and Svelte 5, it showcases all major authentication flows — Passkey, Email Code, Social Login — along with server-side session management, protected routes, and the UI component library.
Source code: github.com/authrim/example-sveltekit
Project Structure
example-sveltekit/├── src/│ ├── app.d.ts # TypeScript global types│ ├── app.html # HTML template│ ├── hooks.server.ts # Server auth handler│ ├── lib/│ │ ├── auth.ts # Authrim client singleton│ │ └── config.ts # Environment config│ └── routes/│ ├── +layout.svelte # Root layout (AuthProvider)│ ├── +layout.server.ts # Server-side auth data│ ├── +page.svelte # Home page│ ├── login/│ │ └── +page.svelte # Login page│ ├── signup/│ │ └── +page.svelte # Sign-up page│ ├── callback/│ │ └── +page.svelte # OAuth callback handler│ └── account/│ ├── +page.svelte # Account settings (protected)│ └── +page.server.ts # Auth guard├── .env.example # Environment variable template├── svelte.config.js # SvelteKit config (Cloudflare adapter)├── vite.config.ts # Vite config└── wrangler.toml # Cloudflare Pages deploymentConfiguration
Environment Variables
Copy .env.example and fill in your values:
PUBLIC_AUTHRIM_ISSUER=https://your-tenant.authrim.comPUBLIC_AUTHRIM_CLIENT_ID=your-client-idAdmin Panel Setup
Register the following in your Authrim client settings:
| Setting | Value |
|---|---|
| Allowed Redirect URIs | http://localhost:5173/callback |
| Allowed Origins | http://localhost:5173 |
Key Files Walkthrough
src/lib/auth.ts — Client Singleton
The auth client is initialized once and reused across the app:
import { createAuthrim, type AuthrimClient } from '@authrim/sveltekit';import { getAuthConfig } from './config.js';
let authClient: AuthrimClient | null = null;
export async function getAuth(): Promise<AuthrimClient> { if (authClient) return authClient;
const config = getAuthConfig(); authClient = await createAuthrim({ issuer: config.issuer, clientId: config.clientId, });
return authClient;}
export function clearAuth(): void { if (authClient) { authClient.destroy(); authClient = null; }}src/hooks.server.ts — Server Auth Handler
Sets up server-side session management via the SvelteKit handle hook:
import { createAuthHandle } from '@authrim/sveltekit/server';import { env } from '$env/dynamic/public';
export const handle = createAuthHandle({ issuer: env.PUBLIC_AUTHRIM_ISSUER || '', clientId: env.PUBLIC_AUTHRIM_CLIENT_ID || '', callbackPaths: ['/callback'],});src/routes/+layout.server.ts — Auth Data for SSR
Makes auth data available to all pages:
import { createAuthLoad } from '@authrim/sveltekit/server';
export const load = createAuthLoad();src/routes/+layout.svelte — Root Layout
Initializes the auth client on the client side and wraps all pages with AuthProvider:
<script lang="ts"> import { onMount } from 'svelte'; import { AuthProvider } from '@authrim/sveltekit/components'; import type { AuthrimClient } from '@authrim/sveltekit';
let { data, children } = $props();
let auth: AuthrimClient | null = $state(null); let isInitializing = $state(true);
onMount(async () => { try { const { getAuth } = await import('$lib/auth.js'); auth = await getAuth(); } catch (e) { console.error('[Authrim] Failed to initialize auth:', e); } finally { isInitializing = false; } });</script>
{#if isInitializing} <p>Loading...</p>{:else if auth} <AuthProvider {auth} initialSession={data.auth?.session ?? null} initialUser={data.auth?.user ?? null} > {@render children()} </AuthProvider>{/if}Key points:
- The client is imported dynamically inside
onMountto avoid SSR issues AuthProviderreceives SSR data (initialSession,initialUser) to prevent hydration mismatch- All child routes can use
getAuthContext()to access the auth client
Page-by-Page Walkthrough
Home Page — src/routes/+page.svelte
The home page reads auth stores to display the current state:
const { session, user, isAuthenticated, loadingState } = auth.stores;- Authenticated — Shows user avatar, name, email, session ID, session expiration, and links to account settings
- Not authenticated — Shows a welcome card with sign-in and sign-up buttons
- Features listed — Passkey, Email Code, Social Login, Session Management, Passkey Management, Server-side Validation
Login Page — src/routes/login/+page.svelte
Offers three authentication methods:
Passkey (with Conditional UI)
onMount(async () => { const isAvailable = await auth.passkey.isConditionalUIAvailable(); if (isAvailable) { auth.passkey.login({ conditional: true }).then((result) => { if (result.data) goto(redirectTo); }); }});On load, the page starts Conditional UI — the browser’s autofill shows available passkeys. Users can also click the explicit “Sign in with Passkey” button.
Email Code
A two-step flow using EmailCodeForm:
// Step 1: Send codeconst result = await auth.emailCode.send(email, { action: 'login' });if (!result.error) emailStep = 'code';
// Step 2: Verify codeconst result = await auth.emailCode.verify(email, code);if (!result.error) goto(redirectTo);Social Login
const result = await auth.social.loginWithPopup(provider, { redirectTo });Supports Google, GitHub, and Apple. Each opens a popup window for authentication.
Sign-Up Page — src/routes/signup/+page.svelte
Multi-method sign-up with Passkey and Email Code:
// Passkey sign-upconst result = await auth.passkey.signUp({ name: name.trim() });
// Email Code sign-upconst result = await auth.emailCode.send(email, { action: 'signup', name: name.trim(),});Social sign-up reuses the same auth.social.loginWithPopup() flow.
Callback Page — src/routes/callback/+page.svelte
Handles OAuth/social login callbacks:
onMount(async () => { if (auth.social.hasCallbackParams()) { const result = await auth.social.handleCallback(); if (result.error) { error = result.error.message; } else { goto(result.data?.redirectTo || '/'); } }});Account Settings — src/routes/account/
A protected route using requireAuth():
import { requireAuth } from '@authrim/sveltekit/server';
export const load = requireAuth({ loginUrl: '/login', redirectParam: 'redirectTo',});Unauthenticated users are redirected to /login?redirectTo=/account.
The page displays:
- User profile (avatar, name, email)
- Passkey management (register, list, delete) using
PasskeyListandPasskeyRegisterButton - Session management (list, revoke) using
SessionList - Sign-out button
User Flow
flowchart LR
home["/
(Home)"]
login["/login
(Login)"]
signup["/signup
(Sign Up)"]
callback["/callback
(Callback)"]
account["/account
(Account)"]
home -->|"Not signed in"| login
home -->|"Not signed in"| signup
login -->|"Passkey / Email Code"| home
login -->|"Social Login"| callback --> home
signup -->|"Passkey / Email Code"| home
home -->|"Account Settings"| account
account -->|"Sign Out"| home
UI Components Used
The example app uses components from @authrim/sveltekit/ui:
| Component | Used in | Purpose |
|---|---|---|
Card | Login, Signup, Home | Container layout |
Button | All pages | Actions |
Input | Signup | Name input |
EmailCodeForm | Login, Signup | Email + OTP two-step form |
SocialLoginButtons | Login, Signup | Provider buttons |
PasskeyConditionalInput | Login | Autofill-based passkey selection |
OTPInput | Signup | 6-digit code input |
ResendCodeButton | Signup | Resend with countdown |
PasskeyList | Account | Registered passkeys |
PasskeyRegisterButton | Account | Add new passkey |
SessionList | Account | Active sessions |
AuthError | All pages | Error display |
Spinner | Home, Callback | Loading indicator |
Running Locally
git clone https://github.com/authrim/example-sveltekit.gitcd example-sveltekitpnpm installcp .env.example .env# Edit .env with your Authrim tenant URL and client IDpnpm devOpen http://localhost:5173 in your browser.
Deploying to Cloudflare Pages
The app is pre-configured for Cloudflare Pages:
pnpm buildnpx wrangler pages deploy .svelte-kit/cloudflareSet environment variables in the Cloudflare dashboard:
| Variable | Value |
|---|---|
PUBLIC_AUTHRIM_ISSUER | https://your-tenant.authrim.com |
PUBLIC_AUTHRIM_CLIENT_ID | your-client-id |
Update your Authrim client settings to include the production URL in Allowed Redirect URIs and Allowed Origins.
Next Steps
- Installation — Set up
@authrim/sveltekitin your own project - Server-Side Integration — Hooks, session management, auth guards
- Authentication — Passkey, Email Code, Social Login API
- UI Library — Full component catalog