diff --git a/documentation/docs/20-core-concepts/60-remote-functions.md b/documentation/docs/20-core-concepts/60-remote-functions.md index 0035c0c40221..1618bca0407d 100644 --- a/documentation/docs/20-core-concepts/60-remote-functions.md +++ b/documentation/docs/20-core-concepts/60-remote-functions.md @@ -1155,3 +1155,106 @@ Note that some properties of `RequestEvent` are different inside remote function ## Redirects Inside `query`, `form` and `prerender` functions it is possible to use the [`redirect(...)`](@sveltejs-kit#redirect) function. It is *not* possible inside `command` functions, as you should avoid redirecting here. (If you absolutely have to, you can return a `{ redirect: location }` object and deal with it in the client.) + +## Using Auth Guards + +You can protect routes by creating reusable authentication guard queries — when these queries are used in a component, the route becomes protected. + +This example sets an `authenticated` cookie, but in a real app you'd have proper checks and session management: + +```ts +/// file: src/routes/auth/auth.remote.ts +import * as v from 'valibot' +import { redirect } from '@sveltejs/kit' +import { form, getRequestEvent, query } from '$app/server' + +const loginSchema = v.object({ secret: v.string() }) + +export const login = form(loginSchema, ({ secret }) => { + const event = getRequestEvent() + + if (secret === 'svelte') { + event.cookies.set('authenticated', 'true', { path: '/' }) + redirect(303, '/auth/guarded') + } else { + return { error: 'You shall not pass!' } + } +}) +``` + +```svelte +/// file: src/routes/auth/+page.svelte + + +
+``` + +There are several ways to implement authentication guards with remote functions: + +```ts +/// file: src/routes/auth/auth.remote.ts +import { redirect } from '@sveltejs/kit' +import { getRequestEvent, query } from '$app/server' + +// 1. inline check +export const getSecretA = query(() => { + const event = getRequestEvent() + if (event.cookies.get('authenticated') !== 'true') { + redirect(307, '/auth') + } + return 'Secret text A' +}) + +// 2. reusable helper function +const requireAuth = query(() => { + const event = getRequestEvent() + if (event.cookies.get('authenticated') !== 'true') { + redirect(307, '/auth') + } +}) + +export const getSecretB = query(async () => { + await requireAuth() + return 'Secret text B' +}) + +// 3. higher-order function +const authQuery ={await getSecretA()}
+{await getSecretB()}
+{await getSecretC()}
+```