Integrations
Sveltekit

SvelteKit

Aponia.js provides a SvelteKit library for convenience.

Basic Usage

src/hooks.server.ts
 
import { Auth } from '@aponia.js/core'
import { sveltekit } from '@aponia.js/sveltekit'
 
const auth = new Auth()
 
const authHandle = sveltekit(auth)
 
export const handle = sveltekit(auth)

Full Usage

Install the packages.

npm install @aponia.js/core @aponia.js/sveltekit

Initialize a session plugin.

src/lib/server/auth/session.ts
import { JwtSessionPlugin } from '@aponia.js/core/plugins/session/jwt'
 
export const jwtSession = new JwtSessionPlugin()

Create providers.

src/lib/server/auth/google.ts
import { OIDCProvider } from '@aponia.js/core/plugins/providers/oidc'
import { GOOGLE_ID, GOOGLE_SECRET } from '$env/static/private'
 
export const google = new OIDCProvider({
  id: 'google',
  clientId: GOOGLE_ID,
  clientSecret: GOOGLE_SECRET,
  issuer: 'https://accounts.google.com',
  endpoints: {
    authorization: {
      params: {
        client_id: GOOGLE_ID,
        response_type: 'code',
        scope: 'openid profile email',
      },
    },
  },
})

Initialize Database (for Adapter).

src/lib/server/db.ts
import { PrismaClient } from '@prisma/client'
 
export const prisma = new PrismaClient()

Create an adapter.

src/lib/server/auth/adapter.ts
import { AdapterPlugin, type Adapter } from '@aponia.js/core/adapter'
import { prisma } from '$lib/server/db'
 
const rawAdapter: Adapter = {
  findAccount: async (_request, response) => {
    return await prisma.account.findFirst({
      where: {
        providerId: response.providerId,
        providerAccountId: response.providerAccountId,
      },
    })
  },
  getUserFromAccount: async (account, _request, _response) => {
    return await prisma.user.findFirst({
      where: {
        id: account.userId,
      },
    })
  },
  createSession: async (user, _account, _request, _response) => {
    return await prisma.session.create({
      userId: user.id,
      expires: Date.now() + 1000 * 60 * 24,
    })
  },
  createUser: async (_request, response) => {
    return await prisma.user.create({
      name: response.account.name,
      avatar: response.account.picture ?? response.account['image'],
    })
  },
  findUserAccounts: async (user, _request, _response) => {
    return await prisma.account.findMany({
      where: {
        userId: user.id,
      },
    })
  },
  createAccount: async (user, _request, response) => {
    return await prisma.account.create({
      providerId: response.providerId,
      providerAccountId: response.providerAccountId,
      userId: user.id,
    })
  },
}
 
export const adapter = new AdapterPlugin(rawAdapter)

Create an Auth instance with the session, adapter, and providers.

src/lib/server/auth/index.ts
import { Auth } from '@aponia.js/core'
import { jwtSession } from './session'
import { google } from './google'
import { adapter } from './adapter'
 
export const auth = new Auth({
  plugins: [jwtSession, google, adapter]
})

Define Global Types.

src/app.d.ts
declare global {
  namespace Aponia {
    interface Session extends {
      id: string
      expires: number
    }
  }
 
  namespace App {
    interface Locals {
      getUser: () => Promise<Aponia.Session | undefined>
    }
 
    interface PageData {
      session?: Aponia.Session
    }
  }
}

Create SvelteKit hooks.

src/hooks.server.ts
import type { Handle } from '@sveltejs/kit'
import { sequence } from '@sveltejs/kit/hooks'
import { sveltekit } from '@aponia.js/sveltekit'
import { auth } from '$lib/server/auth'
import { jwtSession } from '$lib/server/auth/session'
import { prisma } from '$lib/server/db'
 
const authHandle = sveltekit(auth)
 
const sessionHandle: Handle = async ({ event, resolve }) => {
  // Cached session, if already attempted to get.
  let session: Aponia.Session | false
 
  event.locals.getSession = async () => {
    if (session === false) return undefined
 
    const cookieSession = await jwtSession.getSession(event.cookies)
 
    const isValid = cookieSession.expires > Date.now()
 
    if (!isValid) {
      session = false
      return undefined
    }
 
    // Verify that the session in the cookie actually exists in the database.
 
    const dbSession = await prisma.findUnique({
      where: {
        id: cookieSession.id
      }
    })
 
    if (dbSession == null) {
      session = false
      return undefined
    }
 
    session = dbSession
    return session
  }
}
 
export const handle = sequence(authHandle, sessionHandle)

Testing

If all the steps were done correctly, then try visiting /auth/login/google!