I am logged in!
+{/if} +``` + +## Client-side data fetching with RLS + +For [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) to work properly when fetching data client-side, you need to make sure to import the `{ supabaseClient }` from `$lib/db` and only run your query once the session is defined client-side in `$page.data`: + +```html + + +{#if $page.data.session} +client-side data fetching with RLS
+{JSON.stringify(loadedData, null, 2)}
+{/if}
+```
+
+## Server-side data fetching with RLS
+
+```html title=src/routes/profile/+page.svelte
+
+
+{JSON.stringify(tableData, null, 2)}
+{JSON.stringify(user, null, 2)}
+```
+
+For [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) to work in a server environment, you need to use the `getSupabase` helper to check if the user is authenticated. The helper requires the `event` and returns `session` and `supabaseClient`:
+
+```ts title=src/routes/profile/+page.ts
+import type { PageLoad } from './$types';
+import { getSupabase } from '@supabase/auth-helpers-sveltekit';
+import { redirect } from '@sveltejs/kit';
+
+export const load: PageLoad = async (event) => {
+ const { session, supabaseClient } = await getSupabase(event);
+ if (!session) {
+ throw redirect(303, '/');
+ }
+ const { data: tableData } = await supabaseClient.from('test').select('*');
+
+ return {
+ user: session.user,
+ tableData
+ };
+};
+```
+
+## Protecting API routes
+
+Wrap an API Route to check that the user has a valid session. If they're not logged in the session is `null`.
+
+```ts title=src/routes/api/protected-route/+server.ts
+import type { RequestHandler } from './$types';
+import { getSupabase } from '@supabase/auth-helpers-sveltekit';
+import { json, redirect } from '@sveltejs/kit';
+
+export const GET: RequestHandler = async (event) => {
+ const { session, supabaseClient } = await getSupabase(event);
+ if (!session) {
+ throw redirect(303, '/');
+ }
+ const { data } = await supabaseClient.from('test').select('*');
+
+ return json({ data });
+};
+```
+
+If you visit `/api/protected-route` without a valid session cookie, you will get a 303 response.
+
+## Protecting Actions
+
+Wrap an Action to check that the user has a valid session. If they're not logged in the session is `null`.
+
+```ts title=src/routes/posts/+page.server.ts
+import type { Actions } from './$types';
+import { getSupabase } from '@supabase/auth-helpers-sveltekit';
+import { error, invalid } from '@sveltejs/kit';
+
+export const actions: Actions = {
+ createPost: async (event) => {
+ const { request } = event;
+ const { session, supabaseClient } = await getSupabase(event);
+ if (!session) {
+ // the user is not signed in
+ throw error(403, { message: 'Unauthorized' });
+ }
+ // we are save, let the user create the post
+ const formData = await request.formData();
+ const content = formData.get('content');
+
+ const { error: createPostError, data: newPost } = await supabaseClient
+ .from('posts')
+ .insert({ content });
+
+ if (createPostError) {
+ return invalid(500, {
+ supabaseErrorMessage: createPostError.message
+ });
+ }
+ return {
+ newPost
+ };
+ }
+};
+```
+
+If you try to submit a form with the action `?/createPost` without a valid session cookie, you will get a 403 error response.
+
+## Saving and deleting the session
+
+```ts
+import type { Actions } from './$types';
+import { invalid, redirect } from '@sveltejs/kit';
+import { getSupabase } from '@supabase/auth-helpers-sveltekit';
+
+export const actions: Actions = {
+ signin: async (event) => {
+ const { request, cookies, url } = event;
+ const { session, supabaseClient } = await getSupabase(event);
+ const formData = await request.formData();
+
+ const email = formData.get('email') as string;
+ const password = formData.get('password') as string;
+
+ const { error } = await supabaseClient.auth.signInWithPassword({
+ email,
+ password
+ });
+
+ if (error) {
+ if (error instanceof AuthApiError && error.status === 400) {
+ return invalid(400, {
+ error: 'Invalid credentials.',
+ values: {
+ email
+ }
+ });
+ }
+ return invalid(500, {
+ error: 'Server error. Try again later.',
+ values: {
+ email
+ }
+ });
+ }
+
+ throw redirect(303, '/dashboard');
+ },
+
+ signout: async (event) => {
+ const { supabaseClient } = await getSupabase(event);
+ await supabaseClient.auth.signOut();
+ throw redirect(303, '/');
+ }
+};
+```
+
+## Protecting multiple routes
+
+To avoid writing the same auth logic in every single route you can use the handle hook to
+protect multiple routes at once.
+
+```ts title=src/hooks.server.ts
+import type { RequestHandler } from './$types';
+import { getSupabase } from '@supabase/auth-helpers-sveltekit';
+import { redirect, error } from '@sveltejs/kit';
+
+export const handle: Handle = async ({ event, resolve }) => {
+ // protect requests to all routes that start with /protected-routes
+ if (event.url.pathname.startsWith('/protected-routes')) {
+ const { session, supabaseClient } = await getSupabase(event);
+
+ if (!session) {
+ throw redirect(303, '/');
+ }
+ }
+
+ // protect POST requests to all routes that start with /protected-posts
+ if (
+ event.url.pathname.startsWith('/protected-posts') &&
+ event.request.method === 'POST'
+ ) {
+ const { session, supabaseClient } = await getSupabase(event);
+
+ if (!session) {
+ throw error(303, '/');
+ }
+ }
+
+ return resolve(event);
+};
+```
+
+## Migrate from 0.7.x to 0.8 {#migration}
+
+### Set up the Supabase client {#migration-set-up-supabase-client}
+
+server-side fetched data with RLS:
+{JSON.stringify(tableData, null, 2)}
+user:
+{JSON.stringify(user, null, 2)}
```
-### Basic setup
+```ts title=src/routes/protected-route/+page.ts
+import { withAuth } from '@supabase/auth-helpers-sveltekit'
+import { redirect } from '@sveltejs/kit'
+import type { PageLoad } from './$types'
-You can now determine if a user is authenticated on the client-side by checking that the `user` object in `$page.data.session` is defined.
-
-```html title=src/routes/+page.svelte
-
-
-{#if !$page.data.session.user}
-I am logged in!
-{/if} -``` - -## Client-side data fetching with RLS - -For [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) to work properly when fetching data client-side, you need to make sure to import the `{ supabaseClient }` from `$lib/db` and only run your query once the user is defined client-side in `$page.data.session`: - -```html - - -{#if $page.data.session.user} -client-side data fetching with RLS
-{JSON.stringify(loadedData, null, 2)}
-{/if}
+ const { data: tableData } = await getSupabaseClient().from('test').select('*')
+ return { tableData, user: session.user }
+})
```
-## Server-side data fetching with RLS
+{JSON.stringify(user, null, 2)}
```
-For [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) to work in a server environment, you need to use the `withAuth` helper to check if the user is authenticated. The helper extends the event with `session` and `getSupabaseClient()`:
-
-```ts title=src/routes/profile/+page.ts
+```ts title=src/routes/protected-route/+page.ts
+// src/routes/profile/+page.ts
import type { PageLoad } from './$types';
-import { withAuth } from '@supabase/auth-helpers-sveltekit';
+import { getSupabase } from '@supabase/auth-helpers-sveltekit';
import { redirect } from '@sveltejs/kit';
-interface TestTable {
- id: string;
- created_at: string;
-}
-
-export const load: PageLoad = withAuth(async ({ getSupabaseClient, session }) => {
- if (!session.user) {
+export const load: PageLoad = async (event) => {
+ const { session, supabaseClient } = await getSupabase(event);
+ if (!session) {
throw redirect(303, '/');
}
- const { data: tableData } = await getSupabaseClient()
- .from