0.2.1 • Published 1 year ago

svauth v0.2.1

Weekly downloads
-
License
ISC
Repository
github
Last release
1 year ago

Table of Contents

Overview

svauth is a complete open source authentication solution for SvelteKit applications.

Designed from the ground up to support SvelteKit and serverless.

Heavily inspired by NextAuth.js.

Written for Svelte Hack 2023.

This is a monorepo containing the following packages / projects:

  1. The primary svauth package
  2. A development test application

Get Started

Install svauth

npm install svauth
yarn add svauth
pnpm add svauth

Add Svauth Handler

// hooks.server.ts
import Svauth from 'svauth';
import { Google } from 'svauth/providers';
import { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET } from '$env/static/private';

export const handle = Svauth({
	providers: [
		Google({
			clientId: GOOGLE_CLIENT_ID,
			clientSecret: GOOGLE_CLIENT_SECRET
		})
	]
});

(Optional) Get Session During Load

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

export const load = (async (event) => {
	return {
		session: await event.locals.getSession()
	};
}) satisfies PageServerLoad;

Import Session

<script lang="ts">
	// routes/+page.svelte
	import { session, signIn, signOut } from 'svauth/client';
</script>

{#if $session}
	<button on:click={() => signOut()}> Sign out </button>
	<p>Logged in as {$session.user.email}</p>
{:else}
	<button on:click={() => signIn('google')}> Sign in with Google </button>
	<p>Not signed in</p>
{/if}

Features

  • OAuth Providers - Seamless integration with Google, Discord, and GitHub.
  • Serverless - Designed to work with serverless environments.
  • Session Management - Built-in session management for server and client-side rendering.
  • TypeScript - Written in TypeScript and includes type definitions.
  • Security - Designed to be secure by default and encourage best practices for safeguarding user data.
  • Customizable Components - Pre-built, customizable components like the SignInWithGoogleButton for a smoother user authentication experience.

Security

  • CSRF Protection - SvelteKit's built-in CSRF protection is used to prevent CSRF attacks.
  • JWT Encryption - When JSON Web Tokens are enabled, they are encrypted by default (JWE) with A256GCM.
  • Client Independence - Doesn't rely on client-side JavaScript.
  • Secure Cookie Management - Signed, prefixed, server-only cookies.
  • OWASP Compliance - Attempts to implement the latest guidance published by Open Web Application Security Project.

Please contact me directly, stephenshkeda@gmail.com, to report serious issues that might impact the security of sites using svauth.

Environment Variables

NameDescription
SVAUTH_SECRETThe secret used to encrypt the session.
SVAUTH_URLThe URL of the application.
PUBLIC_SVAUTH_PREFIXThe prefix used for the svauth routes.

For production environments, if SVAUTH_URL is not set, VERCEL_URL will be used. For development environments, SVAUTH_URL defaults to localhost:5173.

PUBLIC_SVAUTH_PREFIX is optional and defaults to /auth.

Server API

Svauth

The Svauth function is used to create the Svauth handler.

Parameters

NameTypeDescription
optionsSvauthOptionsThe options object.

SvauthOptions

NameTypeDefaultDescription
providersProvider[]An array of providers.
adapterAdapterThe adapter to link svauth with a database.
expiresnumber | string30dThe expiration time of the session. When number is passed that is used as a value in seconds, when string is passed it is resolved to a time span and added to the current timestamp.

Example

// hooks.server.ts
import Svauth from 'svauth';

export const handle = Svauth({
	providers: [
		Google({
			clientId: GOOGLE_CLIENT_ID,
			clientSecret: GOOGLE_CLIENT_SECRET
		})
	],
	expires: '14d'
});

event.locals

The event.locals object contains the following properties:

NameTypeDescription
getSession()asyncReturns the current session.

Example

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

export const load = (async (event) => {
	return {
		session: await event.locals.getSession()
	};
}) satisfies PageServerLoad;

Client API

session

The session store is the easiest way to obtain information on current session.

session returns 4 possible values:

  • Session - The user's current session.
  • null - The credentials are wrong or the session has expired.
  • undefined - There is no session.
  • false - The session is loading.

Note: If you are obtaining the session during load, session will not return false.

Example

<script lang="ts">
	import { session } from 'svauth/client';
</script>

{#if $session}
	<p>Logged in as {$session.user.email}</p>
{:else}
	<p>Not signed in</p>
{/if}

Session Object

The Session object is returned by the session store.

Properties

NameTypeDescription
UserUserThe user object.
expiresDateThe expiration time of the session.
issuedAtDateThe time the session was issued.

User Object

The User object is found inside the Session object.

Properties

NameTypeDescription
idstringThe user's ID.
emailstringThe user's email.
namestringThe user's name.
imagestringA link to the user's image

signIn

The signIn function is used to sign in a user.

Parameters

NameTypeDefaultDescription
providerstringThe provider to sign in with.
redirectstringCurrent user's locationThe URL to redirect the user to after signing out.

Example

<script lang="ts">
	import { signIn } from 'svauth/client';
</script>

<button on:click={() => signIn('google')}> Sign in with Google </button>

signOut

The signOut function is used to sign out a user.

Parameters

NameTypeDefaultDescription
redirectstringCurrent user's locationThe URL to redirect the user to after signing out.

Example

<script lang="ts">
	import { signOut } from 'svauth/client';
</script>

<button on:click={() => signOut()}> Sign out </button>

Providers

Currently, svauth has support for three OAuth providers:

In the future, I plan to add support for more providers.

Google

Documentation

https://developers.google.com/identity/protocols/oauth2 https://developers.google.com/identity/openid-connect/openid-connect

Configuration

https://console.developers.google.com/apis/credentials

The "Authorized redirect URIs" used when creating the credentials must include your full domain and end in the callback path.

For example:

Example

// hooks.server.ts
import Svauth from 'svauth';
import { Google } from 'svauth/providers';
import { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET } from '$env/static/private';

export const handle = Svauth({
	providers: [
		Google({
			clientId: GOOGLE_CLIENT_ID,
			clientSecret: GOOGLE_CLIENT_SECRET
		})
	]
});

Discord

Documentation

https://discord.com/developers/docs/topics/oauth2

Configuration

https://discord.com/developers/applications

The "Redirects" used when creating the credentials must include your full domain and end in the callback path.

For example:

Example

// hooks.server.ts
import Svauth from 'svauth';
import { Discord } from 'svauth/providers';
import { DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET } from '$env/static/private';

export const handle = Svauth({
	providers: [
		Discord({
			clientId: DISCORD_CLIENT_ID,
			clientSecret: DISCORD_CLIENT_SECRET
		})
	]
});

GitHub

Documentation

https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps

Configuration

https://github.com/settings/developers

The "Authorization callback URL" used when creating the credentials must include your full domain and end in the callback path.

For example:

Example

// hooks.server.ts
import Svauth from 'svauth';
import { GitHub } from 'svauth/providers';
import { GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET } from '$env/static/private';

export const handle = Svauth({
	providers: [
		GitHub({
			clientId: GITHUB_CLIENT_ID,
			clientSecret: GITHUB_CLIENT_SECRET
		})
	]
});

Adapters

Prisma

Documentation

https://www.prisma.io/

Example

// routes/hooks.server.ts
import Svauth from 'svauth';
import { Google } from 'svauth/providers';
import { Prisma } from 'svauth/adapters';
import prisma from './server/prisma';
import { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET } from '$env/static/private';

export const handle = Svauth({
	providers: [
		Google({
			clientId: GOOGLE_CLIENT_ID,
			clientSecret: GOOGLE_CLIENT_SECRET
		})
	],
	adapter: Prisma(prisma)
});

Schema

// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider     = "mysql"
  url          = env("DATABASE_URL")
  relationMode = "prisma"
}

model Account {
  id                String @id @default(cuid())
  userId            String
  provider          String
  providerAccountId String
  user              User   @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
  @@index([userId])
}

model Session {
  id       String   @id @default(cuid())
  userId   String
  issuedAt DateTime @default(now())
  expires  DateTime
  user     User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId])
}

model User {
  id       String    @id @default(cuid())
  name     String
  email    String    @unique
  picture  String
  accounts Account[]
  sessions Session[]
}

Components

SignInWithGoogleButton

The SignInWithGoogleButton component is a simple button that will sign the user in with Google.

Documentation

https://developers.google.com/identity/gsi/web/guides/overview

Configuration

https://console.developers.google.com/apis/credentials

The "Authorized JavaScript origins" used when creating the credentials must include your HTTP origins.

For example:

Props

NameTypeDefaultDescription
oneTapbooleanfalseWhether to use Google One Tap sign in.
typestandard | iconstandardThe button type.button.
themeoutline | filled_blue | filled_blackoutlineThe button theme.
sizelarge | medium | smalllargeThe button size.
textsignin_with | signup_with | continue_with | signinsignin_withThe button text.
shaperectangular | pill | circle | squarerectangularThe button shape.
logo_alignmentleft | centerleftThe Google logo alignment.
widthnumberThe button width, in pixels.
localestringThe button language.

Example

<script lang="ts">
	// routes/+page.svelte
	import { SignInWithGoogleButton } from 'svauth/components';
</script>

<SignInWithGoogleButton />

License

ISC

Portions of this page are reproduced from work created and shared by Google and used according to terms described in the Creative Commons 4.0 Attribution License.