SvelteKit Auth - Let's Decide What To Use
| Published: January 07, 2024
| Updated: March 02, 2024
The options for auth when building SvelteKit apps is lacking to say the least.
SvelteKit is a fantastic meta-framework which has just about every feature you could ever want to create awesome web applications. But the major uncertainty in the SvelteKit ecosystem is how to best approach auth.
The official docs touch on auth from a high-level and how it relates to core processes like load functions, however they leave auth squarely in the hands of the developer - you.
Given SvelteKit is a relatively new meta-framework, there’s still no clear answer for how to best handle auth for the majority of apps. This is evidenced by the fact that it’s the main question constantly being asked by the good people of r/svelte on Reddit.
So this guide will run through the options, and offer advice when selecting auth libraries, and more specifically, when you should choose certain solutions over others.
Routes you can take
- Use a self-hosted library to help you create and manage your own auth (recommended for most use cases),
- Use hosted auth to process and manage all auth for you (recommended for scalability and setup simplicity), or
- Create an auth system from scratch and maintain all auth processes yourself (not recommended)
We’ll go through these options in order, listing the pros and cons of each, and the options you have within each of the categories.
Using Self-Hosted Libraries For Auth In SvelteKit
For every new project I start, I usually begin by installing an open-source auth library and integrating it into SvelteKit as the first thing I do.
Choosing a self-hosted auth library just means you have control over the user experience and data flow when it comes to authentication and authorization in your app.
If you have sufficient knowledge of back-end development, and are happy to spend a bit of time setting it up, the benefits are three-fold:
- Your customer data stays within a closed system,
- You have the flexibility to extend and modify how you like, and
- It’s free!
With those benefits, you also have some downsides:
- You usually have to spend more time integrating the auth package into your app,
- Scalable infrastructure is something you’ll need to be concerned with as your user base grows, and
- You will be required to handle auth issues yourself
The 3 most commonly used auth solutions for SvelteKit are:
- Lucia (involved setup but extendable and easy to maintain) - (my pick)
- Auth.js (simple setup, harder to extend & maintain) and
- Supabase Auth (harder to setup, but extendable and harder to maintain), and
- Firebase Auth (Easy to setup, hard to extend and abnormal to use)
Lucia with SvelteKit
Lucia seems to the most ubiquitous and favorable answer when asking the internet about auth in SvelteKit. If you browse the endless posts about SvelteKit auth, you’ll notice most people are suggesting Lucia.
I can vouch for Lucia too - once it’s up and running, it gets out of the way and there’s very little magic to it.
With a quickstart guide for SvelteKit, setting up should take no longer than an hour. There’s also several starter templates on GitHub (like this one) with Lucia ready to go, given its recent popularity.
Lucia has support for most ORM’s and Query Builders too, so it’s more than likely Lucia will slide right into your favorite stack! And there’s a huge list of OAuth providers it serves too.
A note before quickly starting with Lucia
Whilst Lucia is my favorite way to handle auth in SvelteKit, there is something to be note before you rush to add it to a project.
By their own admission, Lucia requires you have a reasonable knowledge of backend development, and a willingness to understand some of the inner-workings of SvelteKit before adopting it.
If you’re hoping to just dip your toe into SvelteKit land to see if you like it, Lucia most definitely could ruin the experience and send you back to safety… Like it did to me. 😆
However, if you’re committed to developing with SvelteKit, it’s a great exercise in leveling up your expertise of the framework; and auth in general. After grappling with my first integration of Lucia, I came away knowing a lot more than when I started, and it’s helped me in other aspects of my development workflow.
What I like about Lucia
Once I got my head around what’s happening between Lucia and Sveltekit, it was intuitive and everything just works how you’d expect.
It’s also a less opinionated approach compared to most other auth libraries. Lucia gives you the tools to implement your own system, whilst taking care of the finicky details and providing nice helper functions to perform common tasks.
In my experience with other popular auth libraries, I can easily get them up and running, but at the moment of any complication, you really have to dig deep to get to the bottom of it.
With Lucia however, much of the mechanics are exposed and it’s flexible enough to resolve problems easily. The community and creator (pilcrowOnPaper) are also very active, so quirky things are always discussed on GitHub and required library changes are resolved promptly.
With Lucia, you’re frontloading the complexity to the early scaffolding of the app, and then it gets out of your way when you want to program the business logic.
So if you’re a beginner with minimal knowledge of backend development, you’re up for a challenge! But for everyone else, I highly recommend Lucia. 🏆
Auth.js with SvelteKit
Starting as NextAuth, the library built its popularity as one of the leading Auth solutions for Next JS. In 2022, the team decided to become more framework-agnostic, moving to a core library with extensions to serve additional frameworks like SvelteKit.
The Auth.js library (@auth/core
) is currently experimental, but it’s fairly well battle-tested and it gets about 50,000 - 100,000 weekly installs on npm.
This library (in the form of next-auth
) was my main slice when I used NextJS. Whilst I had a few nightmarish moments making OAuth providers work, it was still abstracted enough to be an easy setup.
The API and guide for Auth.js is certainly easy to understand compared to Lucia. But the abstractions are highly opinionated, and if you wish to extend or modify some of the pieces, it can be a pain.
As mentioned, it’s still experimental, but it’s probably the best library to use for auth if you’re looking to build with SvelteKit a for the first time, or if you’re not comfortable with backend development.
If that’s the case, you might even be better off with a hosted auth solution, which we discuss later in the article.
Supabase Auth with SvelteKit
This is only relevant if you’re inclined to use Supabase for your database, which I love by the way. But I can’t think of a circumstance where I would recommend using their auth library over the alternatives mentioned above.
I suppose it integrates well with the @supabase/supabase-js
library, but that’s additional vendor lock-in that you don’t need when you have other (arguably better) ways to access your Supabase DB (e.g. Prisma, Drizzle etc.).
The guide to setting up Auth with Supabase using the supabase/ssr
library and other Supabase-SvelteKit helper functions is more complex than any of the other solutions in this section. And if you want to use typescript, you also have to install and use the Supabase CLI to generate the types.
Huntabyte has made a video tutorial going through the SvelteKit/Supabase auth integration, so if you’re considering add it - it might be worth watching this first:
Having tried this, I didn’t like it, despite the high quality guide and the thorough docs Supabase makes for their offerings - the API’s and helper functions feel unnecessarily foreign.
I appreciate the hard work the Supabase team puts into creating these libraries to be the ‘one-stop-shop’ for developers, but this option isn’t quite there in my opinion, even if you are tightly integrated with Supabase.
Firebase Auth With SvelteKite
I think Firebase is a great product and it creates a positive feedback loop instantly for new developers.
Abstracting away webhooks and being able to subscribe to real-time data with a simple function call is mind-blowing 🤯.
The database is NoSQL so it isn’t pedantic.
And the auth just made sense - it was client-side and you don’t have to do much. And you even have a generous free tier.
But.
I think as soon as you get comfortable building apps with Firebase, you need to get out. It is the motherload of opinionated development, and the vendor lock-in is palpable.
If you do want to adopt Firebase auth however, you’re going to be using some pretty unusual methods to handle protected routes and get user details. You’ll mostly be using Svelte writable stores to access user data.
After not using Firebase for the last 18 months, going back to it for this article has triggered me. Nothing feels real and I don’t feel safe.
Jeff from Fireship however, is a Firebase enthusiast. A Firebase connoisseur if you will… So he’s made a decent video explaining how to set up auth in a firebase app with SvelteKit.
So, if you already know how to develop production apps, I’d say don’t bother with this. The workflow will remove you from reality and there are better options.
Hosted Auth Solutions for SvelteKit
Hosted auth solutions were built to take the processing and maintenance of auth off the developers hands, and into the hands of a company who charges you (if you exceed their high free-tier).
Why use Hosted Auth?
Here are a few pro’s and con’s for picking a hosted auth solutions:
Pro’s of Hosted Auth
- Top-tier security - these companies do 1 thing only and they do it for lots of different apps - the tech is proven and specialized to handle auth exclusively
- Highly scalable - if you’re worried about handling auth for millions of users, this might be a good idea
- They are easy-peasy to set up - you can usually get auth up and running in your app within 15 minutes.
Con’s of Hosted Auth
- User privacy - you’ll be offloading your user’s details/data to these companies,
- Once you exceed the free tier, it can get very expensive!
- Single point of attack - if your auth provider is compromised, all of your users data and passwords are for the taking, as is your sign-in portal.
Generally speaking, hosted auth is good for 2 types of apps:
- Quickly popping up a small app or MVP,
- Huge companies that require the best solution for scalability, e.g. OpenAI used hosted auth (Auth0) for their sign-in process when they had ChatGPT, the fastest growing app of all time.
Providers for Hosted Auth in SvelteKit
So let’s look at the leading options to take when including hosted auth into your SvelteKit app:
Auth0 with SvelteKit
Auth0 is a service which is widely-used in the enterprise space and it’s one of the best solutions for getting auth up and running quickly. They’re popular due to their plug-and-play developer experience, where you get an API key and then use their pre-built components with stylings included to handle auth for you.
Whilst you can integrate Auth0 into your project using some vanilla Auth0 packages, there is no official Svelte/SvelteKit SDK.
In my opinion, this removes most of the initial benefits of using Auth0 in the first place. Sure, you’ll get hosted and managed auth, but the setup is going to be more difficult, and you don’t get the pre-built components that other meta-frameworks like NextJS get.
So to include Auth0 into your SvelteKit app, your options are to:
- Follow aguide from their blog for a Svelte single page app (SPA), or
- Use an unofficial Auth0 client for SvelteKit
If I had to pick, I’d rather use the unofficial library for SvelteKit.
The SPA example is not flexible and doesn’t make use of the backend features in SvelteKit. And you probably want to create a multi-page application. So, in those cases you’re better off using the unofficial library.
The benefit of the unofficial library is that it uses SvelteKit’s core features, and the setup process isn’t as involved as setting up something like Lucia or Auth.js. Whilst you still don’t get the nice looking pre-built components, you have access to use some helper functions in a headless manner.
Overall, I wouldn’t use Auth0 when building a SvelteKit app. If they built an official SvelteKit SDK to the level of their NextJS offering, I might change my mind. But for now, I’d pass on this, because there is a better alternative when selecting to use hosted auth called Clerk.
Clerk with SvelteKit
Clerk is an Auth solution which has gained a lot of popularity throughout the last year. With all the sponsorships and endorsements they’ve been getting from influencer devs, it’s hard to miss Clerk.
Firstly, it’s a paid product with a free tier of up to 10,000 monthly active user - an improvement over Auth0.
Their docs are beast mode (simple), but mamma-mia, there’s also no official SvelteKit SDK! 😭
So, much like the more popular (and less favorable) competitor, ’Auth0’ - you’ll have to rely on and unofficial library like this to integrate it with SvelteKit.
This library however, does include pre-built components, making it more accessible than the Auth0 alternative.
In fact, this library also has an option to install a headless version (clerk-sveltekit/headless
) for a smaller bundle size, which exposes the API’s, but without the pre-built components.
The setup is dead simple, and the management is intuitive and clean.
So if auth is hellish to you and you’d rather not think about auth at all, I’d recommend Clerk above anything in this article.
The intuitive API’s and high quality pre-built components are a strong selling point. Combined with a generous free tier, Clerk is hard to pass on.
Creating your own auth system from scratch
Now that we’ve talked about the abstractions for auth In SvelteKit, let’s get into going bare-bones.
You can create your own auth system, however I’d almost always recommend against it.
It’s difficult, and getting your auth system right is arguably the most mission-critical part of your application. And any bugs can lead to terribly bad consequences for your business and your users.
If you pair that with the reality that there are lofty incentives for hackers to break your auth system, it’s important you get this right!
In a closed-source system where no one battle-tests your code, you could be unknowingly introducing vulnerabilities into your code when developing creating an auth system.
With that in mind, let’s mention some of the things to keep in mind when developing your auth system from scratch in Sveltekit. 😋
SvelteKit fetch
and cookies
If you want to develop your own system, you’re probably already familiar with how to handle cookies and authorization within client-server requests. So we’ll only talk about Sveltekit-specific methods.
Firstly, in SvelteKit fetch
calls automatically inherit the cookie
and authorization
headers for page requests.
This means that in your +page.server.ts
and +layout.server.ts
files, you can access cookies
in your load
and action
functions, like this:
export async function load(event) {
const sessionId = event.cookies.get('sessionId');
if (getSessionLevel(sessionId) === 'admin') {
event.cookies.set('analytics', getAdminAnalyticsString('admin'), {
path: '/'
});
}
return {
user: await db.getUser(sessionId)
};
}
Given that the user only holds access to the sessionId
in their cookies, they pass this to the server, where you’ll create a utility function db.getUser(sessionId)
to ping the database for the user details matching the sessionId
, which would have to be set upon a successful login.
As of SvelteKit v2, The options
parameter of cookies.set
is also now required. SO you’ll need to enter the path
of the cookies to prevent misplaced cookie scope. To apply to your whole domain, enter path: '/'
and you’ll be hunky-dory.
It’s also important to note that if you set credentials: 'included'
in a fetch request, other cookies will not be passed.
SvelteKit Hooks for injecting Auth Properties
Another useful function that SvelteKit has enabled to easily build in auth is server hooks. This is middleware that you get to put between every incoming server request, and load
or action
functions. The benefit is that you get to modify what gets exposed and passed through to these functions.
If you want to implement them, you must first create a file src/hooks.server.js
.
Server hooks are typically used in auth systems to modify the locals
property of the request, for example:
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
event.locals.user = await getUser(event.cookies.get('sessionId'));
const response = await resolve(event);
return response;
};
So then in our load
function, we now get access to locals.user
, which will have the return value for the getUser
utility function:
export async function load(event) {
const user = event.locals.user
return {user}
}
So long as you’re running a fairly straightforward app without subdomains or other whacky complexity, knowing these SvelteKit-specific features should be enough to get you by in creating your auth system from scratch.
In Summary
Regardless of what you choose for your auth, always think of the common man using your application.
If you’re building a proper application in SvelteKit for your business where clients will use auth features in the app, I’d generally recommend Lucia as a one-size-fits-all statement. It’s extendable enough to tailor to your needs, whilst also being abstracted enough to not have constantly think about when developing the business logic of the app.
If you’re dealing with many app users and you need to scale fast, I’d push you more towards Clerk.
If you don’t even want to think about auth, and you’d rather it just be done so you can start working on the fun parts, then I’d also still recommend Clerk.
However, when opting into Clerk over self-hosted auth like Lucia, you trade-off privacy and affordability (self-hosted) for convenience and scalability (hosted).
If you’re a dare-devil that wants the challenge, or you don’t trust code from these libraries, try rolling your own auth from scratch. SvelteKit admittedly makes this easier than most meta-frameworks, but it’s a process that will make you a better developer in the end.