Build SvelteKit authentication with Logto

Learn how to build a user authentication flow with SvelteKit by integrating Logto SDK.
Gao
GaoFounder
February 29, 20243 min read
Build SvelteKit authentication with Logto

Get started

Introduction

  • Logto is an open-source Auth0 alternative for building identity infrastructures. It supports various sign-in methods, including username, email, phone number, and popular social sign-ins like Google and GitHub.
  • SvelteKit is a framework for rapidly developing robust, performant web applications using Svelte.

In this tutorial, we will show you how to build a user authentication flow with SvelteKit by integrating Logto SDK. The tutorial uses TypeScript as the programming language.

Prerequisites

Before you begin, ensure you have the following:

  • A Logto account. If you don't have one, you can sign up for free.
  • A SvelteKit development environment and a project.

Create a Logto application

To get started, create a Logto application with the "Traditional web" type. Follow these steps to create a Logto application:

  1. Sign in to the Logto Console.
  2. In the left navigation bar, click on Applications.
  3. Click on Create application.
  4. In the opened page, find the "Traditional web" section and locate the "SvelteKit" card.
  5. Click on Start building, and input the name of your application.
  6. Click on Create.

Then you should see an interactive tutorial that guides you through the process of integrating Logto SDK with your SvelteKit application. The following content can be a reference for future use.

Integrate with Logto SDK

Installation

Install Logto SDK via your favorite package manager:

# or pnpm, yarn, etc.
npm i @logto/sveltekit

Add Logto hook

In your hooks.server.ts file, add the following code to inject the Logto hook into your server:

import { handleLogto } from '@logto/sveltekit';

export const handle = handleLogto(
  {
    endpoint: '<your-logto-endpoint>',
    appId: '<your-logto-app-id>',
    appSecret: '<your-logto-app-secret>',
  },
  {
    encryptionKey: '<a-random-string>',
  }
);

Since these information are sensitive, it's recommended to use environment variables:

import { handleLogto } from '@logto/sveltekit';
import { env } from '$env/dynamic/private';

export const handle = handleLogto(
  {
    endpoint: env.LOGTO_ENDPOINT,
    appId: env.LOGTO_APP_ID,
    appSecret: env.LOGTO_APP_SECRET,
  },
  {
    encryptionKey: env.LOGTO_COOKIE_ENCRYPTION_KEY,
  }
);

If you have multiple hooks, you can use the sequence() helper function to chain them:

import { sequence } from '@sveltejs/kit/hooks';

export const handle = sequence(handleLogto, handleOtherHook);

Now you can access the Logto client in the locals object. For TypeScript, you can add the type to app.d.ts:

import type { LogtoClient, UserInfoResponse } from '@logto/sveltekit';

declare global {
  namespace App {
    interface Locals {
      logtoClient: LogtoClient;
      user?: UserInfoResponse;
    }
  }
}

We'll discuss the user object later.

Implement sign-in and sign-out

In the following code snippets, we assume your app is running on http://localhost:3000/.

Configure redirect URIs

Switch to the application details page of Logto Console. Add a Redirect URI http://localhost:3000/callback.

Redirect URI is an OAuth 2.0 concept which implies the location should redirect after authentication.

Similarly, add http://localhost:3000/ to the "Post sign-out redirect URI" section.

Post Sign-out Redirect URI is an OAuth 2.0 concept which implies the location should redirect after signing out.

Then click "Save" to save the changes.

Back to your app, in the page where you want to implement sign-in and sign-out, define the following actions:

// +page.server.ts
import type { Actions } from './$types';

export const actions: Actions = {
  signIn: async ({ locals }) => {
    await locals.logtoClient.signIn('http://localhost:3000/callback');
  },
  signOut: async ({ locals }) => {
    await locals.logtoClient.signOut('http://localhost:3000/');
  },
};

Then use these actions in your Svelte component:

{/* +page.svelte */}
<form method="POST" action="?/{data.user ? 'signOut' : 'signIn'}">
  <button type="submit">Sign {data.user ? 'out' : 'in'}</button>
</form>

Display user information

To display the user's information, you can inject the locals.user object into the layout, thus making it available to all pages:

import type { LayoutServerLoad } from './$types';

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

In your Svelte component:

<script>
  /** @type {import('./$types').PageData} */
  export let data;
</script>

{#if data.user}
<ul>
  {#each Object.entries(data.user) as [key, value]}
  <li>{key}: {value}</li>
  {/each}
</ul>
{/if}

Checkpoint: Run the application

Now you can run the application and try to sign-in/sign-out with Logto:

  1. Open the application in your browser, you should see the "Sign in" button.
  2. Click the "Sign in" button, and you should be redirected to the Logto sign-in page.
  3. After you have signed in, you should be redirected back to the application, and you should see the user data and the "Sign out" button.
  4. Click the "Sign out" button, and you should be redirected to the Logto sign-out page, and then redirected back to the application with an unsigned-in state.

If you encounter any issues during the integration, please don't hesitate to join our Discord server to chat with the community and the Logto team!

Further readings