Files
Sveltey/src/hooks.server.ts
Luke Hagar b00c4a2da6 Overhaul
2025-05-27 17:09:58 -05:00

87 lines
2.4 KiB
TypeScript

import { createServerClient } from '@supabase/ssr';
import { type Handle, redirect } from '@sveltejs/kit';
import { sequence } from '@sveltejs/kit/hooks';
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public';
const supabase: Handle = async ({ event, resolve }) => {
/**
* Creates a Supabase client specific to this server request.
*
* The Supabase client is configured to:
* 1. Use cookies for session persistence
* 2. Automatically refresh expired tokens
* 3. Handle server-side authentication
*/
event.locals.supabase = createServerClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, {
cookies: {
getAll() {
return event.cookies.getAll();
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) => {
event.cookies.set(name, value, { ...options, path: '/' });
});
}
}
});
/**
* Unlike `supabase.auth.getSession()`, which returns the session _without_
* validating the JWT, this function also calls `getUser()` to validate the
* JWT before returning the session.
*/
event.locals.safeGetSession = async () => {
const {
data: { session }
} = await event.locals.supabase.auth.getSession();
if (!session) {
return { session: null, user: null };
}
const {
data: { user },
error
} = await event.locals.supabase.auth.getUser();
if (error) {
// JWT validation has failed
return { session: null, user: null };
}
return { session, user };
};
return resolve(event, {
filterSerializedResponseHeaders(name) {
/**
* Supabase libraries use the `content-range` and `x-supabase-api-version`
* headers, so we need to tell SvelteKit to pass it through.
*/
return name === 'content-range' || name === 'x-supabase-api-version';
}
});
};
const authGuard: Handle = async ({ event, resolve }) => {
const { session, user } = await event.locals.safeGetSession();
event.locals.session = session;
event.locals.user = user;
// Protect routes that require authentication
if (event.url.pathname.startsWith('/app')) {
if (!session) {
throw redirect(303, '/auth/login');
}
}
// Redirect authenticated users away from auth pages
if (event.url.pathname !== "/auth/logout" && event.url.pathname.startsWith('/auth' )) {
if (session) {
throw redirect(303, '/app/dashboard');
}
}
return resolve(event);
};
export const handle: Handle = sequence(supabase, authGuard);