Community package that integrates Clerk with SvelteKit.
Important
This package requires Svelte 5 and uses runes
and snippets
under the hood. If you're using Svelte 4, please refer to clerk-sveltekit.
npm install svelte-clerk
PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxxxxxxx
CLERK_SECRET_KEY=sk_test_xxxxxxx
This handler will authenticate a token passed from the frontend and attaches the Auth
object to event.locals.auth
.
// hooks.server.ts
import { withClerkHandler } from 'svelte-clerk/server';
export const handle = withClerkHandler();
Inside your src/
directory, update the app.d.ts
file to ensure that the locals added by the Clerk handler are properly typed.
/// <reference types="svelte-clerk/env" />
declare global {
namespace App {...}
}
All Clerk runes and components must be children of the <ClerkProvider>
component, which provides active session and user context.
// src/+layout.server.ts
import { buildClerkProps } from 'svelte-clerk/server';
// To enable Clerk SSR support, add initial state props to the load function
export const load = ({ locals }) => {
return {
...buildClerkProps(locals.auth)
};
};
<script lang="ts">
import type { Snippet } from '@svelte';
import { ClerkProvider } from 'svelte-clerk';
import { PUBLIC_CLERK_PUBLISHABLE_KEY } from '$env/static/public';
const { children }: { children: Snippet } = $props();
</script>
<!-- ... -->
<ClerkProvider publishableKey={PUBLIC_CLERK_PUBLISHABLE_KEY}>
{@render children()}
</ClerkProvider>
To see all available props for each component, visit the Clerk UI Components docs.
<ClerkLoaded>
<ClerkLoading>
<Protect>
<SignedIn>
<SignedOut>
<SignIn>
<SignUp>
<UserButton>
<UserProfile>
<OrganizationProfile>
<OrganizationSwitcher>
<CreateOrganization>
<GoogleOneTap>
auth
- Auth object.user
- Authenticated user.organization
- Active Organization of the authenticated user.session
- Session of the authenticated user.clerk
-Clerk
object.
Example:
The following example demonstrates how to use the auth
rune to access the current auth state, like whether the user is signed in or not. It also demonstrates a basic example of how you could use the getToken()
method to retrieve a session token for fetching data from an external resource.
<script>
import { useClerkContext } from 'svelte-clerk';
// Do not destructure context or you'll lose reactivity!
const ctx = useClerkContext();
const userId = $derived(ctx.auth.userId);
const fetchDataFromExternalResource = async () => {
const token = await ctx.session.getToken();
const response = await fetch('https://api.example.com/data', {
headers: {
Authorization: `Bearer ${token}`
}
});
return response.json();
};
</script>
{#if userId === undefined}
<p>Loading...</p>
{:else if userId === null}
<p>Sign in to view this page</p>
{:else}
<div>...</div>
{/if}
Clerk offers Control Components that allow you to protect your pages. These components are used to control the visibility of your pages based on the user's authentication state.
<script>
import { SignedIn, SignedOut, UserButton, SignOutButton } from 'svelte-clerk';
</script>
<div>
<h1>Index Route</h1>
<SignedIn>
<p>You are signed in!</p>
<div>
<p>View your profile here 👇</p>
<UserButton />
</div>
<div>
<SignOutButton />
</div>
</SignedIn>
<SignedOut>
<p>You are signed out</p>
<div>
<a href="/sign-in">Go to Sign in</a>
</div>
<div>
<a href="/sign-up">Go to Sign up</a>
</div>
</SignedOut>
</div>
To protect your routes, you can use the load function to check for the userId
singleton. If it doesn't exist, redirect your user back to the sign-in page.
import { redirect } from '@sveltejs/kit';
import { clerkClient } from 'svelte-clerk/server';
export const load = ({ locals }) => {
const { userId } = locals.auth;
if (!userId) {
return redirect(307, '/sign-in');
}
const user = await clerkClient.users.getUser(userId);
return {
user: JSON.parse(JSON.stringify(user))
};
};
Note
If you're planning to add authorization logic within a +layout.server.ts
file, I recommend reading this blog post first.
MIT