Skip to content

Page Templates

@authrim/sveltekit/ui/templates provides seven page templates — fully styled, responsive reference implementations that you can use directly or copy and customize.

import {
LoginTemplate,
SignUpTemplate,
AccountSettingsTemplate,
ConsentTemplate,
DeviceFlowTemplate,
CIBATemplate,
ReauthTemplate,
} from '@authrim/sveltekit/ui/templates';

All templates use the UI Library components and respect the --authrim-* CSS custom properties.

A full login page with passkey, email code, and social login options.

src/routes/login/+page.svelte
<script lang="ts">
import { LoginTemplate } from '@authrim/sveltekit/ui/templates';
import { getAuthContext } from '@authrim/sveltekit';
import { goto } from '$app/navigation';
const auth = getAuthContext();
let loading = $state(false);
let loadingProvider = $state<string | undefined>(undefined);
let error = $state('');
async function handlePasskeyLogin() {
loading = true;
error = '';
const { error: err } = await auth.passkey.login();
loading = false;
if (err) { error = err.message; return; }
goto('/');
}
async function handleSocialLogin(e: CustomEvent<{ provider: string }>) {
const provider = e.detail.provider;
loadingProvider = provider;
error = '';
const { error: err } = await auth.social.loginWithPopup(provider);
loadingProvider = undefined;
if (err) { error = err.message; return; }
goto('/');
}
</script>
<LoginTemplate
availableProviders={['google', 'github', 'apple']}
enablePasskey={true}
enableEmailCode={true}
{loading}
{loadingProvider}
{error}
title="Welcome back"
subtitle="Sign in to your account"
on:passkey-login={handlePasskeyLogin}
on:social-login={handleSocialLogin}
on:email-submit={(e) => sendCode(e.detail.email)}
on:code-submit={(e) => verifyCode(e.detail.code)}
on:code-resend={resendCode}
on:dismiss-error={() => { error = ''; }}
/>
PropTypeDefaultDescription
availableProvidersSocialProvider[][]Social providers to display
enablePasskeybooleantrueShow passkey login option
enableEmailCodebooleantrueShow email code option
loadingbooleanfalseGlobal loading state
loadingProviderSocialProvider | undefinedProvider currently loading
errorstring''Error message to display
titlestring'Welcome back'Page title
subtitlestring'Sign in to your account'Page subtitle
EventPayloadDescription
passkey-loginPasskey login requested
social-login{ provider }Social login requested
email-submit{ email }Email code send requested
code-submit{ code }Code verification requested
code-resendResend code requested
dismiss-errorError dismissed
MethodDescription
setEmailStep(step)Control email form step ('email' or 'code') from parent
  • Centered card (max-width: 420px) on a full-height gradient background
  • Sections separated by dividers: Passkey → Email Code → Social
  • Footer with “Don’t have an account? Sign up” link

Multi-method signup page with passkey and email code options.

<SignUpTemplate
availableProviders={['google', 'github']}
enablePasskey={true}
enableEmailCode={true}
{loading}
{error}
on:passkey-signup={(e) => signUpWithPasskey(e.detail)}
on:social-signup={(e) => socialSignup(e.detail.provider)}
on:email-submit={(e) => sendSignupCode(e.detail)}
on:code-submit={(e) => verifySignupCode(e.detail.code)}
on:dismiss-error={() => { error = ''; }}
/>
PropTypeDefaultDescription
availableProvidersSocialProvider[][]Social providers
enablePasskeybooleantrueShow passkey option
enableEmailCodebooleantrueShow email option
loadingbooleanfalseLoading state
errorstring''Error message
titlestring'Create account'Page title

passkey-signup, social-signup, email-submit, code-submit, code-resend, dismiss-error

Account management page with passkey list, session list, and profile info.

<AccountSettingsTemplate
passkeys={passkeyList}
sessions={sessionList}
currentSessionId={currentSessId}
on:passkey-register={handleAddPasskey}
on:passkey-delete={(e) => deletePasskey(e.detail.credentialId)}
on:session-revoke={(e) => revokeSession(e.detail.sessionId)}
on:account-link={(e) => linkAccount(e.detail.provider)}
on:account-unlink={(e) => unlinkAccount(e.detail.accountId)}
/>
PropTypeDescription
passkeysPasskeyItemDisplay[]Registered passkeys
sessionsSessionItemDisplay[]Active sessions
linkedAccountsLinkedAccountDisplay[]Linked social accounts
currentSessionIdstring | undefinedCurrent session ID
loadingbooleanGlobal loading state
passkeyLoadingbooleanPasskey section loading
deletingPasskeyIdstring | undefinedPasskey currently being deleted
revokingSessionIdstring | undefinedSession currently being revoked
unlinkingAccountIdstring | undefinedLinked account currently being unlinked
linkableProvidersSocialProvider[]Providers that can be linked
linkingProviderSocialProvider | undefinedProvider currently being linked

passkey-register, passkey-delete, session-revoke, account-link, account-unlink

OAuth consent screen showing client info, requested scopes, and approve/deny buttons.

<script lang="ts">
import { ConsentTemplate } from '@authrim/sveltekit/ui/templates';
import { getAuthContext } from '@authrim/sveltekit';
import { page } from '$app/stores';
const auth = getAuthContext();
const challengeId = $page.url.searchParams.get('challenge');
let consentData = $state(null);
$effect(() => {
if (challengeId) {
auth.consent.getData(challengeId).then(data => {
consentData = data;
});
}
});
</script>
{#if consentData}
<ConsentTemplate
client={consentData.client}
scopes={consentData.scopes}
user={consentData.user}
organizations={consentData.organizations}
selectedOrgId={consentData.target_org_id}
roles={consentData.roles}
actingAs={consentData.acting_as}
showOrgSelector={consentData.features.org_selector_enabled}
showActingAs={consentData.features.acting_as_enabled}
showRoles={consentData.features.show_roles}
on:allow={(e) => auth.consent.submit(challengeId, {
approve: true,
selectedOrgId: e.detail.selectedOrgId,
actingAsUserId: e.detail.actingAsUserId,
})}
on:deny={() => auth.consent.submit(challengeId, { approve: false })}
/>
{/if}
PropTypeDescription
clientConsentClientInfo | nullRequesting client details
scopesConsentScopeInfo[]Requested scopes
userConsentUserInfo | nullCurrent user info
organizationsConsentOrgInfo[]Organizations available for the grant
selectedOrgIdstring | nullSelected organization ID
rolesstring[]Roles to display
actingAsConsentActingAsInfo | nullDelegated access context
loadingbooleanLoading state

allow, deny, switch-account, org-change, dismiss-error

Device authorization code entry screen (RFC 8628).

<script lang="ts">
import { DeviceFlowTemplate } from '@authrim/sveltekit/ui/templates';
import { getAuthContext } from '@authrim/sveltekit';
const auth = getAuthContext();
async function handleSubmit(e: CustomEvent<{ userCode: string }>) {
const result = await auth.deviceFlow.submit(e.detail.userCode, true);
// result.message contains the server confirmation.
}
</script>
<DeviceFlowTemplate
on:approve={handleSubmit}
on:deny={(e) => auth.deviceFlow.submit(e.detail.userCode, false)}
/>
PropTypeDescription
loadingbooleanLoading state
errorstringError message
successstringSuccess message
initialCodestringPre-filled user code
qrCodeUrlstringQR code image URL
verificationUrlstringVerification URL shown with the QR code

approve, deny, code-change, dismiss-error, dismiss-success

CIBA (Client Initiated Backchannel Authentication) approval screen.

<script lang="ts">
import { CIBATemplate } from '@authrim/sveltekit/ui/templates';
import { getAuthContext } from '@authrim/sveltekit';
const auth = getAuthContext();
let requests = $state([]);
$effect(() => {
auth.ciba.getData('[email protected]').then(data => {
requests = data;
});
});
</script>
<CIBATemplate
{requests}
on:approve={(e) => auth.ciba.approve(e.detail.authReqId, userId, sub)}
on:deny={(e) => auth.ciba.reject(e.detail.authReqId)}
on:refresh={loadRequests}
/>
PropTypeDescription
requestsCIBAPendingRequest[]Pending CIBA requests
loadingbooleanLoading state
errorstringError message
successstringSuccess message

approve with { authReqId }, deny with { authReqId }, refresh, dismiss-error, dismiss-success

Re-authentication prompt for sensitive operations.

PropTypeDescription
enablePasskeybooleanShow passkey option
enableEmailCodebooleanShow email code option
loadingbooleanLoading state
errorstringError message
titlestringPage title

passkey-login, email-submit, code-submit, dismiss-error

All templates use --authrim-* CSS custom properties. Override them to match your brand:

:root {
/* Primary brand color */
--authrim-color-primary: #0066cc;
--authrim-color-primary-hover: #0052a3;
--authrim-color-primary-active: #003d7a;
--authrim-color-primary-subtle: #e6f0ff;
--authrim-color-primary-text: #ffffff;
/* Background */
--authrim-color-bg: #ffffff;
--authrim-color-bg-subtle: #f8fafc;
/* Typography */
--authrim-font-sans: 'Inter', system-ui, sans-serif;
/* Border radius */
--authrim-radius-lg: 12px;
}

Templates occupy the full viewport height with a centered card layout and subtle gradient background.