Svelte port of Userfront examples based on:
https://userfront-svelte-leftium.vercel.app
https://github.com/Leftium/userfront-svelte
In this example, we will add authentication and access control to a SvelteKit application.
The userfront-svelte
package does work with plain Svelte, but we will use SvelteKit for setup and routing.
At a high level, Svelte’s responsibility in authentication is to:
npm create svelte@latest my-app
cd my-app
npm install
npm run dev -- --open
Select the options as you go. In this example, we set up SvelteKit with the following:
Now our application is available at http://localhost:5173/
This example uses Pico CSS for nice-looking default semantic styles.
npm install @picocss/pico@next --save
We’ll set up a simple app with routing. This is all we need to start adding authentication.
Route | Description |
---|---|
/ |
Home page |
/login |
Login page |
/reset |
Password reset page |
/dashboard |
User dashboard, for logged in users only |
Add src/routes/+layout.svelte
with the following to add a simple navigation menu:
<!-- src/routes/+layout.svelte -->
<script lang="ts">
import '@picocss/pico';
</script>
<main class="container">
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/login">Login</a></li>
<li><a href="/reset">Reset</a></li>
<li><a href="/dashboard">Dashboard</a></li>
</ul>
</nav>
<slot />
</main>
<style>
main {
max-width: 600px;
}
nav {
justify-content: center;
}
:global(h1) {
text-align: center;
}
</style>
Then add placeholders for each route:
<!-- src/routes/+page -->
<h1>Home</h1>
<!-- src/routes/login/+page -->
<h1>Login</h1>
<!-- src/routes/reset/+page -->
<h1>Reset</h1>
<!-- src/routes/dashboard/+page -->
<h1>Dashboard</h1>
With our routes in place, we are ready to add authentication.
Add the file env.locals
to the root of your project folder and fill in your account details.
They will be used in the next steps.
SvelteKit provides access to environment variables so we can avoid hard-coding them:
# /env.locals
# Find your account (global tenant) id here: https://userfront.com/test/dashboard/settings
PUBLIC_USERFRONT_ACCOUNT_ID=
# Find your key here (use base64 version): https://userfront.com/test/dashboard/jwt
PUBLIC_USERFRONT_PUBLIC_KEY_BASE64=
# Find your key here: https://userfront.com/test/dashboard/api-keys
USERFRONT_API_KEY=
We’ll start by adding a signup form to the home page.
Install the required packages with:
npm install -D @userfront/toolkit userfront-svelte --save
We will use Userfront tools on multiple pages, so we can initialize it once in the +layout.svelte
file.
<!-- src/routes/+layout.svelte --!>
<script lang="ts">
import '@picocss/pico';
import { PUBLIC_USERFRONT_ACCOUNT_ID } from '$env/static/public';
import Userfront from '@userfront/toolkit/web-components';
Userfront.init(PUBLIC_USERFRONT_ACCOUNT_ID);
</script>
<main class="container">
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/login">Login</a></li>
<li><a href="/reset">Reset</a></li>
<li><a href="/dashboard">Dashboard</a></li>
</ul>
</nav>
<slot />
</main>
<style>
main {
max-width: 600px;
}
nav {
justify-content: center;
}
:global(h1) {
text-align: center;
}
</style>
Now we can add the signup form to the home page just by adding the appropriate web component in src/routes/+page.svelte
:
<!-- src/routes/+page.svelte -->
<h1>Home</h1>
<signup-form />
Now the home page has your signup form. Try signing up a user.
The form is in “Test mode” by default, which will create user records in a test environment you can view separately in your Userfront dashboard.
Continue by adding your login and password reset forms in the same way that you added your signup form:
<!-- src/routes/login/+page.svelte -->
<h1>Login</h1>
<login-form redirect-on-load-if-logged-in="true" />
<!-- src/routes/reset/+page.svelte -->
<h1>Reset</h1>
<password-reset-form />
At this point, your signup, login, and password reset should all be functional.
Your users can sign up, log in, and reset their password.
Whenever a user does log in, we want to show them some relevant information and also give them the ability to log out.
For the dashboard page, we can add information about the user by referencing the Userfront.user
object.
We can log the user out by calling Userfront.logout()
.
Replace the src/routes/dashboard/+page.svelte
file with the following:
<!-- src/routes/dashboard/+page.svelte -->
<script lang="ts">
import { PUBLIC_USERFRONT_ACCOUNT_ID } from '$env/static/public';
import Userfront from '@userfront/toolkit/web-components';
Userfront.init(PUBLIC_USERFRONT_ACCOUNT_ID);
const { user } = Userfront;
</script>
<h1>Dashboard</h1>
<article>
<header>
<h4>{user.name || user.email}</h4>
<button on:click={() => Userfront.logout()}>Log out</button>
</header>
<textarea readonly rows="6">Userfront.user = {JSON.stringify(user, null, 4)}</textarea>
</article>
<style>
article header {
display: flex;
justify-content: space-between;
align-items: baseline;
}
textarea {
white-space: pre;
overflow-wrap: normal;
overflow-x: hidden;
}
</style>
Usually, we don’t want users to be able to view the dashboard unless they are logged in. This is known as protecting a route.
Whenever a user is not logged in but tries to visit /dashboard
, we can redirect them to the login screen.
userfrontCookieToTokens()
and verifyToken()
are helper functions that parse/decode Userfront cookies on both the server and client.
Add the file src/hooks.server.ts
to pass auth info from the UserFront JWT to SvelteKit’s request event:
// src/hooks.server.ts
import {
PUBLIC_USERFRONT_ACCOUNT_ID,
PUBLIC_USERFRONT_PUBLIC_KEY_BASE64
} from '$env/static/public';
import { userfrontCookieToTokens, verifyToken } from 'userfront-svelte';
export async function handle({ event, resolve }) {
const cookie = event.request.headers.get('cookie');
const userfrontTokens = await userfrontCookieToTokens(cookie, PUBLIC_USERFRONT_ACCOUNT_ID);
event.locals.auth = await verifyToken(
PUBLIC_USERFRONT_PUBLIC_KEY_BASE64,
userfrontTokens?.accessToken
);
return resolve(event);
}
Then add the file src/routes/dashboard/+page.server.ts
to protect the /dashboard
route.
Each protected route needs a +page.server file like this:
// src/routes/dashboard/+page.server.ts
import { redirect } from '@sveltejs/kit';
// Protected route. Redirect if not logged in.
export const load = async ({ locals }) => {
if (!locals.auth) throw redirect(302, `/login`);
};
Userfront.tokens.accessToken
is a JWT access token that you can
use on your backend to protect your API endpoints.
The SvelteKit client can send the JWT access token as a
Bearer
token inside the Authorization
header. For example:
// Example of calling an endpoint with a JWT
const response = await fetch('/your-endpoint', {
method: 'GET',
headers: {
'content-type': 'application/json',
authorization: `Bearer ${Userfront.tokens.accessToken}`
},
});
To handle a request like this, the (SvelteKit) backend should read the JWT access token
from the Authorization
header and verify that it is valid using the JWT public key found
found in your Userfront dashboard.
Using this approach, any invalid or missing tokens are rejected by your server.
You can also reference the contents of the token later using the auth
object:
console.log(auth);
// =>
{
mode: 'test',
tenantId: 'demo1234',
userId: 1,
userUuid: 'ab53dbdc-bb1a-4d4d-9edf-683a6ca3f609',
isConfirmed: false,
authorization: {
demo1234: {
roles: ["admin"]
},
},
sessionId: '35d0bf4a-912c-4429-9886-cd65a4844a4f',
iat: 1614114057,
exp: 1616706057
}
With this information, you can perform further checks as desired,
or use the userId
or userUuid
to look up information related to the user.
For example, if you wanted to limit a route to admin users, you could check
against the authorization
object from the verified access token:
// Javascript example
const authorization = auth.authorization["demo1234"] || {};
if (authorization.roles.includes("admin")) {
// Allow access
} else {
// Deny access
}
/api/update-user
+server endpoint that reads and verifies the JWT access tokenFrom here, you can add social identity providers like Google, Facebook, and LinkedIn to your Svelte application, or business identity providers like Azure AD, Office365, and more.
To do this, create an application with the identity provider (e.g. Google), and then add those SSO credentials to the Userfront dashboard. The result is a modified sign on experience.
No additional code is needed to implement Single Sign On using this approach: you can add and remove providers without updating your forms or the way you handle JWT access tokens.