Olympus Docs
IntegrateSPA & mobile

SvelteKit integration

Authenticate a SvelteKit app against Olympus

SvelteKit's server-side hooks make Olympus integration clean.

Setup

bun add oauth4webapi

Hook for session check

src/hooks.server.ts:

import type { Handle } from "@sveltejs/kit";

export const handle: Handle = async ({ event, resolve }) => {
  const session = event.cookies.get("session");
  if (session) {
    try {
      event.locals.user = JSON.parse(session);
    } catch {}
  }
  return resolve(event);
};

Login server endpoint

src/routes/api/auth/login/+server.ts:

import { redirect } from "@sveltejs/kit";
import * as oauth from "oauth4webapi";

export const GET = async ({ cookies }) => {
  const issuer = new URL(process.env.OLYMPUS_ISSUER!);
  const as = await oauth.processDiscoveryResponse(issuer, await oauth.discoveryRequest(issuer));

  const verifier = oauth.generateRandomCodeVerifier();
  const challenge = await oauth.calculatePKCECodeChallenge(verifier);
  const state = oauth.generateRandomState();

  cookies.set("pkce_verifier", verifier, { path: "/", httpOnly: true, secure: true, sameSite: "lax" });
  cookies.set("pkce_state", state, { path: "/", httpOnly: true, secure: true, sameSite: "lax" });

  const url = new URL(as.authorization_endpoint!);
  url.search = new URLSearchParams({
    client_id: process.env.OLYMPUS_CLIENT_ID!,
    response_type: "code",
    scope: "openid profile email",
    redirect_uri: process.env.OLYMPUS_REDIRECT_URI!,
    code_challenge: challenge,
    code_challenge_method: "S256",
    state,
  }).toString();

  throw redirect(302, url.toString());
};

Page with auth check

src/routes/+page.svelte:

<script lang="ts">
  export let data;
</script>

{#if data.user}
  <p>Welcome, {data.user.email}</p>
{:else}
  <a href="/api/auth/login">Log in</a>
{/if}

src/routes/+page.server.ts:

export const load = async ({ locals }) => {
  return { user: locals.user };
};

On this page