Route Protection
Protect SvelteKit routes using auth sessions in server load functions and hooks.
Route Protection
Protecting a single route
ts
// src/routes/dashboard/+page.server.ts
import { auth } from '$auth/server';
import { redirect } from '@sveltejs/kit';
export async function load({ request }) {
const session = await auth.api.getSession({ headers: request.headers });
if (!session) redirect(302, '/login');
return { user: session.user };
}Protecting a group of routes
Use a layout server file for a route group:
ts
// src/routes/(app)/+layout.server.ts
import { auth } from '$auth/server';
import { redirect } from '@sveltejs/kit';
export async function load({ request }) {
const session = await auth.api.getSession({ headers: request.headers });
if (!session) redirect(302, '/login');
return { user: session.user };
}All routes under src/routes/(app)/ are now protected without repeating the check.
Role-based protection
ts
export async function load({ request }) {
const session = await auth.api.getSession({ headers: request.headers });
if (!session) redirect(302, '/login');
if (session.user.role !== 'admin') redirect(302, '/403');
return { user: session.user };
}Global protection in hooks
For apps where most routes are protected, use hooks.server.ts:
ts
// src/hooks.server.ts
import { auth } from '$auth/server';
import { sequence } from '@sveltejs/kit/hooks';
import { redirect, type Handle } from '@sveltejs/kit';
const publicPaths = ['/', '/login', '/register', '/api/auth'];
const protect: Handle = async ({ event, resolve }) => {
const isPublic = publicPaths.some(p => event.url.pathname.startsWith(p));
if (!isPublic) {
const session = await auth.api.getSession({ headers: event.request.headers });
if (!session) redirect(302, '/login');
event.locals.user = session.user;
}
return resolve(event);
};
export const handle = sequence(auth.handler, protect);Accessing user in components
Pass user data down from the layout load:
svelte
<!-- src/routes/(app)/+layout.svelte -->
<script lang="ts">
import { page } from '$app/stores';
const user = $derived($page.data.user);
</script>
<nav>
<span>{user.name}</span>
<form method="POST" action="/api/auth/sign-out">
<button type="submit">Sign out</button>
</form>
</nav>
{@render children()}