Svault is an authentication, authorization, and user management library for Svelte/SvelteKit applications. Svault supports both native username/password authentication as well as OAuth.
- Svault is an open-source developer library that simplifies the authentication process in SvelteKit projects.
- Svault is flexible and lightweight, and allows the developer to decide which authentication types they would like to deploy in their application.
- With native username/password authentication, implementing registration and login functionality have never been easier. Cookies and sessions are automatically created and deleted upon logout or expiration.
- Svault also supports OAuth with a number of providers. Currently, it offers easy setup with Google, Github, and Discord, with more providers to come.
- Currently, Svault's database adapter connects to the developer's PostgreSQL database, with additional database functionality in the works.
This demo simulates implementing authentication functionality into an already existing SvelteKit app. First demonstrating log in component scaffolding without Svault authentication logic. Then moving on to implementing Svault, following documentation specs for the hooks server file. Developers will need to first set up their own log in components (buttons, input forms, etc.) following the Svault documentation for the correct endpoints/actions (this step is not pictured in the demo).
- Navigate to your SvelteKit project directory in the command line.
- Run:
npm install svault
-
When registering your application for OAuth set your callback url to match this format
/oauth/[provider]/validate
. -
In the
src
directory of your project, create ahooks.server.ts
file and paste the following code:
// Import if you would like to use Oauth login (necessary for all Oauth)
import { SvaultOauth } from 'svault';
// Import if you would like to use Github Oauth
import { github } from 'svault';
import { GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET } from '$env/static/private';
// Import if you would like to use Google Oauth
import { google } from 'svault';
import { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET } from '$env/static/private';
// Google callback urls have to match the callback url you setup in your development app so paste it here to pass into the Oauth function
const googleCallback = 'http://localhost:5173/oauth/google/validate';
// Import if you would like to use Discord Oauth
import { discord } from 'svault';
import { DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET } from "$env/static/private";
// Discord callback urls have to match the callback url you setup in your development app so paste it here to pass into the Oauth function
const discordCallback = 'http://localhost:5173/oauth/discord/validate';
// Set redirect path to your desired endpoint upon user login
const redirectPath = '/(yourPathHere)'; //ex. 'const redirectPath = '/redirectPage'
// Place the Oauth providers here
const providers = [
github(GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, redirectPath),
google(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, redirectPath, googleCallback),
discord(DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET, redirectPath, discordCallback)
];
// Svault Oauth handler
export const handle = SvaultOauth({ providers });
- Create an
.env
file at the root level of your project and define your client ID and secret as variables. Example:
// Paste if using Discord Oauth
DISCORD_CLIENT_ID = YOURIDHERE
DISCORD_CLIENT_SECRET = YOURSECRETHERE
// Paste if using Github Oauth
GITHUB_CLIENT_ID = YOURIDHERE
GITHUB_CLIENT_SECRET = YOURSECRETHERE
// Paste if using Google Oauth
GOOGLE_CLIENT_ID = YOURIDHERE
GOOGLE_CLIENT_SECRET = YOURSECRETHERE
-
In your
+page.svelte
file that has your login page:- Create a button or component for each provider you want to use, that will route to an endpoint of
/oauth/[provider-name-here]/auth
- Make sure to include an anchor tag within the button and/or component.
- Create a button or component for each provider you want to use, that will route to an endpoint of
// Example +page.svelte file for github authentication
<button>
<a href="/oauth/github/auth">Github</a>
</button>
<button>
<a href="/oauth/google/auth">Google</a>
</button>
<button>
<a href="/oauth/discord/auth">Discord</a>
</button>
- And you're good to go!
Note: OAuth providers are not set up to store any data in a database in this current iteration of Svault.
- In your
src
directory, create ahooks.server.ts
file
// Import if you would like to utilize native user registration and login
import { SvaultNative } from 'svault';
// Set redirect path to your desired endpoint upon user login
const redirectPath = '/[yourPathHere]'; //ex. 'const redirectPath = '/homepage'
// Svault native handler
export const handle = SvaultNative(redirectPath);
- Create a PostgreSQL table with the following columns:
CREATE TABLE [YOURTABLENAME] (
username VARCHAR NOT NULL,
password VARCHAR NOT NULL
)
- In your
routes
directory, create a route calledlogin
. In your login+page.svelte
, create form elements for taking in username and password inputs. Create buttons for login and register.- Ensure the endpoints are set to
registerValidate
andloginValidate
- Create a separate button that is set to
logout
endpoint
- Ensure the endpoints are set to
// Example routes/login/+page.svelte
<form method="post">
<input
type="text"
placeholder="Username"
name="username"
required
/>
<input
type="password"
placeholder="Password"
name="password"
required
/>
<button type="submit" formaction="?/registerValidate">
Register
</button>
<button type="submit" formaction="?/loginValidate">
Login
</button>
</form>
// To implement logout functionality, create a button or anchor tag in your page.svelte that redirects to '/logout'
<button>
<a href="/logout">Logout</a>
</button>
- In your
.env
file (create if you haven't done so) that takes in your database URI and user table name
// Paste if using native authentication with a PostgreSQL database
PG_URI = YOURDATABASEURI
TABLE_NAME = YOURTABLENAME
//MAX_AGE will determine the expiration time of the user's session
MAX_AGE = Date.now() + {someNumberHere} * {someNumberHere}
// ex. Date.now() + 1000 * 60 * 60 --> session will last for 1 hour
- After submitting the form, the user will be redirected to the endpoint of your choice.
-
Upon registering, the user will be added to the database with the username and a secure hashed password.
-
On login, the user will be authenticated through your database.
- A browser cookie will be created as well as a session in local memory storage called "svault-auth".
- The session will have an expiration time determined in your
.env
file. - Sessions will automatically be cleaned and deleted upon expiration.
-
On logout, the user will be redirected to the home page, the cookie will be deleted from the browser, and the session will be deleted from local memory store.
-
- And you're good to go!
- To implement native authentication and OAuth, you can use SvelteKit's Sequence helper function.
- In your existing
hooks.server.ts
file, add the following:
import { sequence } from '@sveltejs/kit/hooks';
/*
NOTE: CANNOT HAVE 2 HANDLE FUNCTIONS!
export const handle = SvaultNative(redirectPath);
export const handle = SvaultOauth({ providers });
*/
// Rename functions to their corresponding type of authentication
export const native = SvaultNative(redirectPath);
export const oauth = SvaultOauth({ providers });
// Use sveltekit sequence method to run both hooks in sequence
export const handle = sequence(oauth, native);
- Svault automatically sends back authentication information to the frontend via the
event.locals
object. This allows you to display any necessary information you would like, client-side.- If you would like to display the user’s username on the page, simply load
event.locals.username
in your+layout.server.ts
, and then call it on your+page.svelte
. - If you would like to display an appropriate error message upon incorrect login, the error will be returned back to the client side on the
event.locals.failure
object.
- If you would like to display the user’s username on the page, simply load
- See example below:
// In +layout.server.ts
import type { LayoutServerLoad } from '/$types';
export const load = (async ({ locals }) => {
const { username, failure } = locals;
return await { username, failure };
}) satisfies LayoutServerLoad;
// In +page.svelte
<!-- displays username upon successful login -->
{#if data.username}
<a
href="/logout"
data-sveltekit-reload
>
Hello {data.username}, Log out
</a>
{:else}
<!-- displays error message if login is unsuccessful -->
{#if data.failure}
<div>
{data.failure}
</div>
{/if}
Svault is an amazing project with many areas for iteration. Here are some of the ideas to add and improve our features:
- Implement long term storage for OAuth users in the database
- Add more OAuth providers! (Facebook, Reddit, Twitter...)
- Change session cache to Redis rather than in-memory store
- Create a My Profile page that displays after a user has been authenticated
- Add additional DB adapters- MySQL, MongoDB, etc.
- Add access authorization and roles to different users
- Complete frontend sessions logic in browser
- Create testing suites
- Add UI components for login, making it a one-stop-shop
- Refactor the TypeScript code and define correct typings/interfaces
- Fork and clone this repository.
- Create a new branch on your local repository, giving it a meaningful name, such as one that details what feature is being developed.
- Commit and push your work to your own forked repository.
- Submit a Pull Request from your forked branch, to the dev branch of the Svault repository.
- Your Pull Request will then be reviewed, and then merged if approved!
Franki Biswas Github | LinkedIn
Tristan Bott Github | LinkedIn
Michael Buenrostro Github | LinkedIn
Michelle Conroy Github | LinkedIn
Inspired by Lucia and Auth.js, Svault expands the authentication tools available to Svelte/SvelteKit developers.
Svault is developed under the MIT license.