[!WARNING] This example has been moved into the authkit-sveltekit project and this repo has been archived.
The AuthKit library for SvelteKit provides convenient helpers for authentication and session management using WorkOS & AuthKit with SvelteKit.
Install the package with:
npm install @workos-inc/authkit-sveltekit
or
yarn add @workos-inc/authkit-sveltekit
Make sure the following values are present in your .env environment variables file. The client ID and API key can be found in the WorkOS dashboard, and the redirect URI can also be configured there.
WORKOS_CLIENT_ID="client_..." # retrieved from the WorkOS dashboard
WORKOS_API_KEY="sk_test_..." # retrieved from the WorkOS dashboard
WORKOS_COOKIE_PASSWORD="<your password>" # generate a secure password here
WORKOS_REDIRECT_URI="http://localhost:5173/callback" # configured in the WorkOS dashboard
WORKOS_COOKIE_PASSWORD is the private key used to encrypt the session cookie. It has to be at least 32 characters long. You can use the 1Password generator or the openssl library to generate a strong password via the command line:
openssl rand -base64 32
Certain environment variables are optional and can be used to debug or configure cookie settings.
| Environment Variable | Default Value | Description |
|---|---|---|
WORKOS_COOKIE_MAX_AGE |
34560000 (400 days) |
Maximum age of the cookie in seconds |
WORKOS_COOKIE_DOMAIN |
None | Domain for the cookie. When empty, the cookie is only valid for the current domain |
WORKOS_COOKIE_NAME |
'workos_session' |
Name of the session cookie |
WORKOS_COOKIE_SAMESITE |
'lax' |
SameSite attribute for cookies. Options: 'lax', 'strict', or 'none' |
Example usage:
WORKOS_COOKIE_MAX_AGE='600'
WORKOS_COOKIE_DOMAIN='example.com'
WORKOS_COOKIE_NAME='my-auth-cookie'
[!WARNING] Setting
WORKOS_COOKIE_SAMESITE='none'allows cookies to be sent in cross-origin contexts (like iframes), but reduces protection against CSRF attacks. This setting forces cookies to be secure (HTTPS only) and should only be used when absolutely necessary for your application architecture.
[!TIP]
WORKOS_COOKIE_DOMAINcan be used to share WorkOS sessions between apps/domains. Note: TheWORKOS_COOKIE_PASSWORDwould need to be the same across apps/domains. Not needed for most use cases.
Create or update your src/hooks.server.ts file:
import { createAuthKitHandle } from '@workos-inc/authkit-sveltekit';
export const handle = createAuthKitHandle();
For advanced configuration:
import { createAuthKitHandle } from '@workos-inc/authkit-sveltekit';
export const handle = createAuthKitHandle({
protectedPaths: ['/dashboard', '/admin'],
excludePaths: ['/login', '/logout', '/callback', '/public'],
loginPath: '/auth/signin'
});
Add the following to your src/app.d.ts file:
import type { AuthLocals } from '@workos-inc/authkit-sveltekit';
declare global {
namespace App {
interface Locals extends AuthLocals {}
// ... your other type definitions
}
}
export {};
Create src/routes/login/+server.ts:
export { GET } from '@workos-inc/authkit-sveltekit/login';
For custom configuration:
import { loginHandler } from '@workos-inc/authkit-sveltekit';
export const GET = loginHandler({
screenHint: 'sign-in' // or 'sign-up'
});
Create src/routes/logout/+server.ts:
export { POST } from '@workos-inc/authkit-sveltekit/logout';
Create src/routes/callback/+server.ts:
export { GET } from '@workos-inc/authkit-sveltekit/callback';
For custom success handling:
import { callbackHandler } from '@workos-inc/authkit-sveltekit';
export const GET = callbackHandler({
onSuccess: async (user, session) => {
// Custom logic after successful authentication
console.log(`User ${user.email} signed in`);
}
});
Use the authentication data that's automatically populated in locals:
<!-- src/routes/+page.svelte -->
<script>
import { page } from '$app/stores';
$: user = $page.data.user;
</script>
{#if user}
<h1>Welcome back, {user.firstName}!</h1>
<form method="POST" action="/logout">
<button type="submit">Sign Out</button>
</form>
{:else}
<a href="/login">Sign In</a>
{/if}
In your +layout.server.ts:
import type { LayoutServerLoad } from './$types';
export const load: LayoutServerLoad = async ({ locals }) => {
return {
user: locals.user
};
};
AuthKit SvelteKit provides ready-to-use Svelte components:
<script>
import { SignInButton, SignOutButton, UserProfile } from '@workos-inc/authkit-sveltekit/components';
import { page } from '$app/stores';
$: user = $page.data.user;
</script>
{#if user}
<UserProfile {user} />
<SignOutButton />
{:else}
<SignInButton screenHint="sign-up">Create Account</SignInButton>
{/if}
<!-- Custom sign-in button -->
<SignInButton screenHint="sign-up" class="btn btn-primary">
Create Your Account
</SignInButton>
<!-- User profile with custom template -->
<UserProfile {user} let:user>
<div class="profile">
<img src={user.profilePictureUrl} alt="Profile" />
<span>{user.firstName} {user.lastName}</span>
<small>{user.email}</small>
</div>
</UserProfile>
Use reactive stores for client-side authentication state:
<script>
import { authUser, isAuthenticated } from '@workos-inc/authkit-sveltekit/stores';
</script>
{#if $isAuthenticated}
<p>Welcome back, {$authUser.firstName}!</p>
{:else}
<p>Please sign in to continue.</p>
{/if}
Use requireAuth to protect page load functions:
// src/routes/dashboard/+page.server.ts
import { requireAuth } from '@workos-inc/authkit-sveltekit';
export const load = requireAuth(async ({ locals }) => {
// locals.user is guaranteed to exist and fully typed
return {
user: locals.user,
dashboardData: await fetchDashboardData(locals.user.id)
};
});
Protect API endpoints with withAuth:
// src/routes/api/user/+server.ts
import { json } from '@sveltejs/kit';
import { withAuth } from '@workos-inc/authkit-sveltekit';
export const GET = withAuth(async ({ locals }) => {
return json({
user: locals.user,
timestamp: new Date().toISOString()
});
});
// src/hooks.server.ts
import { createAuthKitHandle } from '@workos-inc/authkit-sveltekit';
export const handle = createAuthKitHandle({
protectedPaths: ['/dashboard', '/admin'],
excludePaths: ['/login', '/logout', '/callback', '/api/public'],
loginPath: '/auth/signin',
populateLocals: true
});
// src/hooks.server.ts
import { createAuthKitHandle, loadAuthKitEnv } from '@workos-inc/authkit-sveltekit';
const config = loadAuthKitEnv(); // Loads from WORKOS_* environment variables
export const handle = createAuthKitHandle({
...config,
protectedPaths: ['/dashboard']
});
Access organization data through locals:
// src/routes/dashboard/+page.server.ts
export const load = requireAuth(async ({ locals }) => {
const { user, organizationId, role, permissions } = locals;
return {
user,
organization: organizationId ? await getOrganization(organizationId) : null,
userRole: role,
userPermissions: permissions
};
});
Refresh user sessions to get the latest data:
<script>
import { invalidateAll } from '$app/navigation';
async function refreshSession() {
// Trigger a refresh of all load functions
await invalidateAll();
}
</script>
<button on:click={refreshSession}>Refresh Session</button>
Handle authentication errors gracefully:
// src/routes/api/protected/+server.ts
import { json, error } from '@sveltejs/kit';
import { withAuth } from '@workos-inc/authkit-sveltekit';
export const GET = withAuth(async ({ locals }) => {
try {
const data = await fetchSensitiveData(locals.user.id);
return json(data);
} catch (err) {
console.error('API error:', err);
throw error(500, 'Failed to fetch data');
}
});
Add environment variables to your Vercel deployment:
vercel env add WORKOS_CLIENT_ID
vercel env add WORKOS_API_KEY
vercel env add WORKOS_REDIRECT_URI
vercel env add WORKOS_COOKIE_PASSWORD
Add to your wrangler.toml:
[vars]
WORKOS_CLIENT_ID = "your_client_id"
WORKOS_REDIRECT_URI = "https://your-app.pages.dev/callback"
# Add secrets using wrangler
# npx wrangler secret put WORKOS_API_KEY
# npx wrangler secret put WORKOS_COOKIE_PASSWORD
Add environment variables in your Netlify dashboard or netlify.toml:
[build.environment]
WORKOS_CLIENT_ID = "your_client_id"
WORKOS_REDIRECT_URI = "https://your-app.netlify.app/callback"
# In your Dockerfile
ENV WORKOS_CLIENT_ID=your_client_id
ENV WORKOS_REDIRECT_URI=https://your-app.com/callback
For advanced use cases, you can access the underlying session manager:
import { getSessionManager } from '@workos-inc/authkit-sveltekit';
// In a server-side context
const sessionManager = getSessionManager();
const authResult = await sessionManager.withAuth(request);
Access the WorkOS client directly for advanced operations:
import { getWorkOS } from '@workos-inc/authkit-ssr';
const workos = getWorkOS();
const organizations = await workos.organizations.listOrganizations({
limit: 10
});
Implement custom session storage for special deployment needs:
import { createSvelteKitAuthKit, SvelteKitStorage } from '@workos-inc/authkit-sveltekit';
class CustomStorage extends SvelteKitStorage {
// Override storage methods for custom behavior
}
const sessionManager = createSvelteKitAuthKit({
storage: new CustomStorage(config)
});
// Re-exported from @workos-inc/node
export type { User, Impersonator } from '@workos-inc/node';
// Re-exported from @workos-inc/authkit-ssr
export type { AuthResult, Session } from '@workos-inc/authkit-ssr';
// SvelteKit-specific types
export interface AuthLocals {
user: User | null;
sessionId?: string;
organizationId?: string;
role?: string;
permissions?: string[];
impersonator?: Impersonator;
accessToken?: string;
}
| Function | Description |
|---|---|
createAuthKitHandle(options?) |
Creates SvelteKit handle function |
requireAuth(loadFn, loginPath?) |
Wraps load functions to require auth |
withAuth(handler) |
Wraps API handlers to require auth |
loadAuthKitEnv(prefix?) |
Loads config from environment variables |
| Component | Props | Description |
|---|---|---|
SignInButton |
screenHint?, returnPathname?, class? |
Pre-built sign-in button |
SignOutButton |
returnTo?, class? |
Pre-built sign-out button |
UserProfile |
user, children? |
User profile display |
| Store | Type | Description |
|---|---|---|
authUser |
Readable<User | null> |
Current user state |
isAuthenticated |
Readable<boolean> |
Authentication status |
userOrganizations |
Readable<Organization[]> |
User's organizations |
currentOrganization |
Readable<Organization | null> |
Current organization |
Check out our examples for different use cases:
If you're migrating from a manual WorkOS implementation:
createAuthKitHandle()AuthLocalsrequireAuth and withAuth| Old Pattern | New Pattern |
|---|---|
| Custom session management | createAuthKitHandle() |
| Manual login routes | export { GET } from '@workos-inc/authkit-sveltekit/login' |
| Custom auth checks | requireAuth(), withAuth() |
| Manual user state | $page.data.user, stores |
WORKOS_COOKIE_PASSWORD is 32+ charactersWORKOS_REDIRECT_URI matches your callback route exactly/callback/+server.ts) is properly configuredAuthLocals in your app.d.ts fileWORKOS_COOKIE_DOMAIN is correctly configured if setEnable debug logging to troubleshoot issues:
// src/hooks.server.ts
import { createAuthKitHandle } from '@workos-inc/authkit-sveltekit';
export const handle = createAuthKitHandle({
debug: true // Enable debug logs
});
We welcome contributions! Please see our Contributing Guide for details.
MIT © WorkOS