Integrating OAuth in Your SvelteKit App: Step-by-Step with AuthJS

Integrating OAuth in Your SvelteKit

Unlocking User Authentication in SvelteKit: OAuth Strategies with AuthJS

authjs
sveltekit
OAuth

Install required npm packages

Install the required npm package first

terminal or console
npm install @auth/core @auth/sveltekit

Read detail documentation on the authjs website


Populate .env variables

Make sure to populate .env

.env
GITHUB_ID=01eer344sdeecvff
GITHUB_SECRET=fdg451dreas5124713jhl85m152

Don't worry about sharing my github ID and SECRET, becasue these are just random number


Populate .env.local variables

Create another file named .env.local add the AUTH_SECRET environment variable

.env.local
AUTH_SECRET="This is an example"

AUTH_SECRET is a random string used by the library to encrypt tokens and email verification hashes, and it's mandatory to keep things secure!

Use the command below or https://generate-secret.vercel.app/32 to generate a random value for it.

console command
openssl rand -base64 32

Create server hook

hooks.server.js
import { SvelteKitAuth } from "@auth/sveltekit";
import GitHub from "@auth/core/providers/github";
import { GITHUB_ID, GITHUB_SECRET } from "$env/static/private";

// console.log(GITHUB_ID, " + ", GITHUB_SECRET);
// console.log(SvelteKitAuth);

export const { handle } = SvelteKitAuth({
  providers: [GitHub({ clientId: GITHUB_ID, clientSecret: GITHUB_SECRET })],
});

Populate +layout.server.js

+layout.server.js
export const load = async (event) => {
  console.log(event);
  return {
    session: await event.locals.auth(),
  };
};

Consuming the session via page store

We can use the $page.data.session variable from anywhere on your page

+page.svelte
<script>
  import { signIn, signOut } from '@auth/sveltekit/client'
  import { page } from '$app/stores'
</script>

{#if $page.data.session?.user}
  <p>Signed in as {$page.data.session.user.email}</p>
  <button on:click={signOut}>Sign out</button>
  <img src="https://cdn.pixabay.com/photo/2017/08/11/19/36/vw-2632486_1280.png" />
{:else}
  <p>Not signed in.</p>
  <button on:click={() => signIn('github')}>Sign in</button>
{/if}

Protecting API Routes

To protect API Routes (blocking unauthorized access to resources), we can use locals.auth() just like in the layouts file to know whether a session exists or not:

+page.server.js
import { error } from "@sveltejs/kit";

// This is the `load` function expected in a `+page.server.js` file.
export async function load({ locals }) {
  // Your authentication and logic here
  const session = await locals.auth?.();
  if (!session || !session.user) {
    error(401, "You must sign in to view movies.");
  }

  // Returning props for the page
  return {
    props: {
      movies: [
        { title: "Alien vs Predator", id: 1 },
        { title: "Reservoir Dogs", id: 2 },
      ],
    },
  };
}

The above way of protecting a route is repetitive, as we have to use the same code for every +page.server.js route


Non repeative way of incorporating OAuth

Here is the more composed way of achieving the same result using hooks.server.js

hooks.server.js
// src/hooks.server.js
import { sequence } from "@sveltejs/kit/hooks";
import { SvelteKitAuth } from "@auth/sveltekit";
import GitHub from "@auth/core/providers/github";
import { GITHUB_ID, GITHUB_SECRET } from "$env/static/private";

const svelteKitAuth = SvelteKitAuth({
  providers: [GitHub({ clientId: GITHUB_ID, clientSecret: GITHUB_SECRET })],
});

const customHandle = async ({ event, resolve }) => {
  // Skip auth for public routes.
  const publicRoutes = ["/", "/qcData"]; // Add your public routes here.
  if (!publicRoutes.includes(event.url.pathname)) {
    const session = await event.locals.auth?.();
    if (!session || !session.user) {
      // If not authenticated, throw an error or redirect the user.
      return new Response("You must sign in to view this page.", {
        status: 401,
      });
    }
  }

  // If the route is public or the user is authenticated, continue with the request.
  return resolve(event);
};

export const handle = sequence(svelteKitAuth.handle, customHandle);