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:
npx sv create --no-install --template minimal --types ts --no-add-ons svelte-example
cd svelte-example
npx sv add eslint --no-install --cwd .
npx sv add prettier --no-install --cwd .
npm install
npm run dev -- --open
The commands above set up SvelteKit with the following:
Now our application is available at http://localhost:5173/
npm install -D @picocss/pico --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/(protected)/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=demo1234
# Find your key here: https://userfront.com/test/dashboard/api-keys
USERFRONT_API_KEY=uf_test_admin_demo1234_7100ea25c6f...
# Find your key here: https://userfront.com/test/dashboard/jwt
PUBLIC_USERFRONT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyvNQgi44otiNbxy2qT5R
...
...
...
NwV4FeTgNvd5FO2Yye7LigkCAwEAAQ==
-----END PUBLIC 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 (Sign Up)</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/(protected)/dashboard/+page.svelte
file with the following:
<!-- src/routes/(protected)/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 onclick={() => 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.
Add the file src/routes/(protected)/dashboard/+page.server.ts
to protect the /dashboard
route.
Each protected route needs a +page.server file like this:
// src/routes/(protected)/dashboard/+page.server.ts
import { RequireLogin } from 'userfront-svelte/sveltekit';
// Protected route. Redirect if not logged in. Show error when insufficient roles.
export const load = async () => {
const { user, roles } = new RequireLogin();
console.log(user);
console.log(roles);
};
RequireLogin
is a special helper class. When authorization conditions are not met, the user is either redirected to the login page or shown an error.
The class provides several methods that restrict which users are allowed. These methods may be chained together:
export const load = async () => {
new RequireLogin().andAdmin().andAnyRoles(['author', 'contributor']).andAllRoles(['viewer', 'owner'])
};
The RequireLogin
class may also be extended with your own methods to implement custom guard conditions.
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.