Docs

SvelteKit Integration

Before you start, make sure you have a Better Auth instance configured. If you haven't done that yet, check out the installation.

Mount the handler

We need to mount the handler to SvelteKit server hook.

hooks.server.ts
import { auth } from "$lib/auth";
import { svelteKitHandler } from "better-auth/svelte-kit";
 
export async function handle({ event, resolve }) {
	return svelteKitHandler({ event, resolve, auth });
}

Create a client

Create a client instance. You can name the file anything you want. Here we are creating client.ts file inside the lib/ directory.

auth-client.ts
import { createAuthClient } from "better-auth/svelte" // make sure to import from better-auth/svelte
 
export const authClient = createAuthClient({
    // you can pass client configuration here
})

Once you have created the client, you can use it to sign up, sign in, and perform other actions. Some of the actions are reactive. The client use nano-store to store the state and reflect changes when there is a change like a user signing in or out affecting the session state.

Example usage

<script lang="ts">
  import { authClient } from "$lib/client";
  const session = authClient.useSession();
</script>
    <div>
      {#if $session.data}
        <div>
          <p>
            {$session?.data?.user.name}
          </p>
          <button
            on:click={async () => {
              await authClient.signOut();
            }}
          >
            Sign Out
          </button>
        </div>
      {:else}
        <button
          on:click={async () => {
            await authClient.signIn.social({
              provider: "github",
            });
          }}
        >
          Continue with github
        </button>
      {/if}
    </div>

Example: Getting User session and role in a layout

+layout.server.ts
import type { LayoutServerLoad } from './$types';
import { error, redirect } from '@sveltejs/kit';
import { auth } from '$lib/auth';
 
 
export const load: LayoutServerLoad = async ({ request }) => {
    const session = await auth.api.getSession({
          headers: request.headers
    });
    if (!session) {
        console.log('Admin : No session');
        throw redirect(302, '/login');
    }
    if (session.user.role !== 'admin') {
        console.log('Admin : Not admin');
        throw error(403, 'Forbidden');
    }
}; 

Example: Storing session on locals and protecting a route with layout

We first get the session and set it to event.locals

hooks.server.ts
import type { Handle } from '@sveltejs/kit';
import { auth } from '$lib/auth-client';
 
export const handle: Handle = async ({ event, resolve }) => {
  // Get the session  
  const session = await auth.api.getSession({
    headers: event.request.headers
  });
  // Set session and user to locals 
  event.locals.session = session?.data?.session;
  event.locals.user = session?.data?.user;
 
  const response = await resolve(event);
  return response;
};  

Then on the +layout.server.ts of the protected routes

+layout.server.ts
import type { LayoutServerLoad } from './$types';
import { error, redirect } from '@sveltejs/kit';
 
export const load: LayoutServerLoad = async ({ locals }) => {
    const session = locals.session;
    const user = locals.user;
 
    if (!session) {
        console.log('Admin : No session');
        throw redirect(302, '/login');
    }
    if (user?.role !== 'admin') {
        console.log('Admin : Not admin');
        throw error(403, 'Forbidden');
    }
}; 

if you do this , make sure to also set the types on your app.d.ts

app.d.ts
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
 
declare global {
	namespace App {
		interface Locals {
			session: Session | undefined;
			user: User | undefined;
		}
		// interface Error {}
		// interface Locals {}
		// interface PageData {}
		// interface Platform {}
	}
}
 
export { };

On this page