Wocha Docs

SvelteKit quickstart

Add Wocha authentication to a SvelteKit app using @wocha/sveltekit with the BFF (Backend-for-Frontend) pattern.

Add Wocha authentication to a SvelteKit app using @wocha/sveltekit with the BFF (Backend-for-Frontend) pattern. Token exchange runs on the server; sessions are stored in encrypted httpOnly cookies.

Prerequisites

  • Node.js 18+
  • SvelteKit 2+ project
  • A Wocha project with a confidential OAuth application (Wocha Console)
  • Redirect URI registered: http://localhost:5173/auth/callback

What you'll build

A SvelteKit app with server-side OAuth routes, encrypted cookies, and client stores for sign-in state.

your-app.local

Welcome back

After sign-in

✓ Session stored securely

✓ User profile available in your app

✓ Organisation context ready for multi-tenant features

Installation

pnpm add @wocha/sveltekit
Or scaffold with the CLI
npx @wocha/cli init --framework sveltekit

Peer dependencies: @sveltejs/kit ^2.0, Svelte 4 or 5.

Environment variables

Create .env:

WOCHA_CLIENT_ID=your-client-id
WOCHA_CLIENT_SECRET=your-client-secret
WOCHA_ISSUER=https://your-tenant.auth.wocha.ai
 
# Optional
WOCHA_API_URL=https://your-tenant.api.wocha.ai

Auth route handler

Create src/routes/auth/[...wocha]/+server.ts:

import { createWochaHandler, wochaAuthConfigFromEnv } from "@wocha/sveltekit/server";
 
const config = wochaAuthConfigFromEnv() ?? {
  clientId: import.meta.env.WOCHA_CLIENT_ID,
  clientSecret: import.meta.env.WOCHA_CLIENT_SECRET,
  issuer: import.meta.env.WOCHA_ISSUER,
  apiUrl: import.meta.env.WOCHA_API_URL,
};
 
export const GET = createWochaHandler(config);
export const POST = createWochaHandler(config);

This exposes:

RoutePurpose
GET /auth/loginStart OAuth login
GET /auth/callbackOAuth callback — sets session cookie
GET /auth/logoutEnd session
GET /auth/sessionPublic session JSON for client stores
POST /auth/switch-orgSwitch active organisation

Route protection hook

Add to src/hooks.server.ts:

import { greetHandle } from "@wocha/sveltekit/server";
 
export const handle = greetHandle(undefined, {
  publicPaths: ["/", "/about"],
});

Unauthenticated requests to protected routes redirect to /auth/login?return_to=….

Client stores and components

Use stores in your Svelte pages:

<script lang="ts">
  import { session, user, org, signIn, signOut } from "@wocha/sveltekit/client";
</script>
 
{#if $user}
  <p>Signed in as {$user.email}</p>
  <p>Organisation: {$org.orgId ?? "—"}</p>
  <button on:click={() => signOut()}>Sign out</button>
{:else}
  <button on:click={() => signIn("/dashboard")}>Sign in</button>
{/if}

Conditional rendering with components:

<script lang="ts">
  import { Authenticated, Protect } from "@wocha/sveltekit/client/components";
</script>
 
<Authenticated>
  <Dashboard />
</Authenticated>
 
<Protect permission={{ resource: { type: "document", id: "doc-1" }, permission: "edit" }}>
  <EditForm />
</Protect>

Server-side session access

Use helpers in +page.server.ts:

import { getSession, requireSession } from "@wocha/sveltekit/server";
import type { PageServerLoad } from "./$types";
 
export const load: PageServerLoad = async (event) => {
  const session = await requireSession(event);
  return { email: session.user.email };
};

Testing the integration

  1. Start the dev server:

    npm run dev
  2. Visit http://localhost:5173 and click Sign in.

  3. Complete login on the hosted auth UI.

  4. Confirm you return with an active session — check $user in the browser or call GET /auth/session.

  5. Visit a protected route (not in publicPaths) while signed out — you should be redirected to /auth/login.

Next steps

On this page