No description
  • TypeScript 72.5%
  • Svelte 22%
  • JavaScript 3.8%
  • HTML 1.7%
Find a file
2025-11-02 18:19:33 +00:00
assets first commit 2025-10-22 16:43:16 +01:00
e2e first commit 2025-10-22 16:43:16 +01:00
src first commit 2025-10-22 16:43:16 +01:00
static first commit 2025-10-22 16:43:16 +01:00
.env.example first commit 2025-10-22 16:43:16 +01:00
.gitignore first commit 2025-10-22 16:43:16 +01:00
.npmrc first commit 2025-10-22 16:43:16 +01:00
.prettierignore first commit 2025-10-22 16:43:16 +01:00
.prettierrc first commit 2025-10-22 16:43:16 +01:00
drizzle.config.ts first commit 2025-10-22 16:43:16 +01:00
local.db first commit 2025-10-22 16:43:16 +01:00
local.db.bak first commit 2025-10-22 16:43:16 +01:00
package-lock.json first commit 2025-10-22 16:43:16 +01:00
package.json first commit 2025-10-22 16:43:16 +01:00
playwright.config.ts first commit 2025-10-22 16:43:16 +01:00
README.md first commit 2025-10-22 16:43:16 +01:00
svelte.config.js first commit 2025-10-22 16:43:16 +01:00
tsconfig.json Update tsconfig.json 2025-11-02 18:19:33 +00:00
vite.config.ts first commit 2025-10-22 16:43:16 +01:00
vitest-setup-client.ts first commit 2025-10-22 16:43:16 +01:00

SvelteKit Access Control Introduction

Enda Lee 2025

PDF version

Introduction

Setting up using the built in Lucia Auth access control

Creating a new application

1. Setup a Sveltekit app in webapps/lab-6a

Enter the following command to start the setup process. . refers to the current directory.

npx sv create .

As before you will be prompted to selection options for the new application.

This is the same as in lab 1 except for the options where you should include drizzle and lucia

SvelteKit Options

Also make sure to include the lucia demo.

Lucia Demo include

2. Trying the access control demo

1. Start the application as usual, you should see a prompt to update the database schema.

This will add two tables, user and session to the SQLite database.

Run first time

2. Proceed and start the application

Started

3. Open http://localhost:5173/demo in your browser

You will see the very basic demo page with a link to the login form - open it:

demo page

4. Register an account (don't forget the password)

After registration you should see a confirmation. In addition to the message you should see that a cookie was set in the browser.

Post registration

That's the demo, behind the scences is more interesting...

3. How it works

Although this is a very simple example, the authentication process is the same as for a more complex application.

1. Request for page intercepted by hooks.server.ts (see comments)

This check happens on every request to the application so that checking occurs before a route/ page is loaded.

// /hooks.server.ts
import type { Handle } from '@sveltejs/kit';

// import lucia auth functions 
import * as auth from '$lib/server/auth';

const handleAuth: Handle = async ({ event, resolve }) => {

	// 1. Try to get the session cookie from the browser request
	const sessionToken = event.cookies.get(auth.sessionCookieName);

	// 2. if no session cookie, clear the user and sesssion objects
	if (!sessionToken) {
		event.locals.user = null;
		event.locals.session = null;
		return resolve(event);
	}

	// 3. validate the session and retrieve the (logeed in) user
	const { session, user } = await auth.validateSessionToken(sessionToken);

	// 4. Set or delete the cookie
	if (session) {
		auth.setSessionTokenCookie(event, sessionToken, session.expiresAt);
	} else {
		auth.deleteSessionTokenCookie(event);
	}

	// 5. store user and session in state
	event.locals.user = user;
	event.locals.session = session;
	return resolve(event);
};

export const handle: Handle = handleAuth;

2. continue to load routes/demo/lucia

+page.server.ts will load first on server-side - read coments for details

// routes/demo/lucia/+page.server.ts
import * as auth from '$lib/server/auth';
import { fail, redirect } from '@sveltejs/kit';
import { getRequestEvent } from '$app/server';
import type { Actions, PageServerLoad } from './$types';


//	Login required for this route
//	Check if user in locals object and return (to +page.svelte for this route)
export const load: PageServerLoad = async () => {
	const user = requireLogin();
	return { user };
};

// Form action to handle a request for logout
export const actions: Actions = {
	logout: async (event) => {
		// check if session exists
		if (!event.locals.session) {
			return fail(401);
		}

		// clear the session
		await auth.invalidateSession(event.locals.session.id);
		auth.deleteSessionTokenCookie(event);

		// redirect to the login page
		return redirect(302, '/demo/lucia/login');
	}
};

// This function gets locals object if set (by server hooks)
function requireLogin() {
	const { locals } = getRequestEvent();

	// if no user redirect to login page
	if (!locals.user) {
		return redirect(302, '/demo/lucia/login');
	}

	// return user
	return locals.user;
}

+page.svelte loaded - read coments for details

<script lang='ts'>
	// Use Svelte form enhacements for submission
	import { enhance } from '$app/forms';
	import type { PageServerData } from './$types';

	// Get the server data from the page load function
	let { data }: { data: PageServerData } = $props();
</script>

<!-- Display user details about the logged in user-->
<h1>Hi, {data.user.username}!</h1>
<p>Your user ID is {data.user.id}.</p>

<!-- The logout form - sends a post request handled by the logout action in +page.server.ts-->
<form method='post' action='?/logout' use:enhance>
	<button>Sign out</button>
</form>

4. The auth functions - src/lib/server/auth.ts

As part of lucia auth, auth.ts was added to the app. This script contains 'boilerplate' functions to handle session creation, validation, crypto, etc. The function names are self explanatary.

Exercises

Part 1

  1. Add some routes/ pages to app:
    • Some of these will be public, e.g about, contact, login, register.
    • Other will require login, e.g. user-profile
  2. Add a nav bar for your new pages in +layout.svelte and use Bootstrap styling.
  3. Following the demo example, and authentication checking on the routes which require login.
  4. Use Bootstrap to improve the login/ registration UI.

Part 2

Require authentication to access the /location route in Lab 6

  • Use code from part 1 in your solution.
  • The database already includes the required user and session tables with 3 sample users: alice, bob, and test all of which use the password Password
  • Add a login link to the nav menu which should change to show logout after a successful login (see: https://svelte.dev/tutorial/svelte/else-if-blocks)

Enda Lee 2025