New SvelteKit course: fullstacksveltekit.com

Why Lucia might be the best authentication library for SvelteKit

I've spent quite some time researching and working with various authentication libraries and services for SvelteKit. Either as part of the work we do at our Svelte agency or for side projects I've worked on. All these experiences have brought me to Lucia, a SvelteKit authentication library I've been using for a while now. And I firmly believe that, at this moment, Lucia is the best one out there.

https://www.datocms-assets.com/129313/1712826187-lucia-best-auth-library-sveltekit.png

I've spent quite some time researching and working with various authentication libraries and services for SvelteKit. Either as part of the work we do at our Svelte agency  or for side projects I've worked on. I've tried many of them, from self-hosted to third-party services, and open-source libraries, and, I even  rolled my own auth  at some point.

All these experiences have brought me to Lucia, a SvelteKit authentication library I've been using for a while now.  And I firmly believe that, currently, Lucia is the best one out there.

But before I dive into Lucia's details, let's first talk about what makes a good authentication library.

What makes a good authentication library?

This is a non-exhaustive list of characteristics  I  look for when reaching for an authentication library. This doesn't mean that libraries/services that don't meet these criteria are bad, but I consider that they are not the best fit for my needs.

Criteria may vary depending on the types of projects you're building, the scale of your application, the legal and regulatory requirements that you have to account for, etc.

But I do feel like the following criteria are a good starting point for anyone looking to build a secure authentication system for their SvelteKit application.

Data Ownership

This is the first thing I check whenever I have to decide which authentication library to use. I want to make sure that the user's data is owned by me (meaning that I have full control over it). The last thing I'd want would be to have to make requests to a third-party service to get access to the user's data.

While this is made easy these days through SDKs, I still personally prefer full control and ownership of the data.

These criteria already rule out a lot of authentication services like Auth0, Okta, Clerk, etc.

Ease of integration and setup

I would rather not fight my authentication library to make it work. What needs to be done to get the user authenticated and authorized should be clear and easy to understand.

Flexibility and customization

While this might seem like a contradiction with the previous criteria, it's a good thing. The ability to customize the authentication process to fit your specific needs is a key factor in building a secure and user-friendly application.

Whether it's how and where (MySQL, SQLite, Postgres, serverless database, etc…) you want to store the user's data or custom logic you would like to add before or after the authentication process, this is a good criterion to check.

Great documentation

Without some good documentation, all the criteria above will be difficult to achieve. Excellent documentation will help you understand how to use the library, what it does, and how to customize it to your needs.

Open Source

This is a little subjective, but I think it's important to consider the open-source nature of the library. If it's open source, it means that the code is available for anyone to view, modify, and contribute to. This can be a good thing if you're looking to build a community around your project and get feedback from other developers.

Ecosystem and community

Uses cases change and vary over time and depending on the project you're building. Today you might be building an email and password authentication system with a SQLite database, but the next day, you might want to integrate OAuth 2.0 with Bitbucket or GitHub. Or you might want to use a different database, like Postgres or MongoDB.

It's essential that the authentication library you choose is well-maintained and has a strong community behind it. This will ensure that you have access to the latest features and bug fixes and that you can easily find help and support if you run into any issues.

Now what is Lucia?

Lucia  is an open-source authentication library for TypeScript applications. It gives you the utilities and tools you need to build a secure and user-friendly authentication system for your applications.

Lucia is built and primarily maintained by  Pilcrow  .

Lucia can be considered an agnostic authentication library for JavaScript, TypeScript, and Node.js applications. The documentation has guides for how to use it with  SvelteKit, Next.js, Astro, Nuxt, Express, and more  . But you get the primitives and building blocks to build your authentication system in any JavaScript framework.

It also offers the advantage of working on most JavaScript runtimes, including Node.js, Deno, Bun, and Cloudflare Workers.

Out of the box, Lucia has support for various ranges of databases and ORMs, like MySQL, Postgres, SQLite, MongoDB, Prisma, Drizzle ORM, and more.

Its primary authentication method focus is session-based, but it also has support for OAuth 2.0 with various providers.

How does it work?

There are, in my opinion, two main parts to how Lucia works:

  • Database adapters  : These are the database drivers that allow Lucia to connect to your database. Lucia uses these to create session cookies, invalidate sessions, and more. Before the  v3 release, adapters were also used to directly create and manage user accounts in the database. Now this process is totally separated from Lucia itself, and you have full control over it.

  • Session management  :  Lucia uses sessions  to keep track of the user's authentication state. Sessions are stored in the database, and their ID is stored in the cookies. These session IDs can then be used on every request to identify the user and authorize them to various parts of your application.

The ecosystem

One of the major improvements that was brought by Lucia v3 is the surrounding ecosystem. They are now separate packages that abstract various parts of the authentication process.  Arctic  provides OAuth 2.0 and OpenID Connect support for major providers like  Google  , Facebook,  GitHub  , etc…

Oslo  gives you several utilities for various authentication needs like creating, parsing, and validating JWT tokens, password hashing, cookies management, etc…

Moreover, there is also a very active  community on Discord  around the library.

Integrating Lucia for email and password authentication in SvelteKit

Now, let's briefly go through how to integrate Lucia for email and password authentication in SvelteKit.

We'll start by creating a new SvelteKit project (with TypeScript), and installing the necessary dependencies for Lucia to work.

To keep things simple, we will use SQLite as our database, and Drizzle ORM as our ORM to connect and make queries to the database.

pnpx create-svelte@latest lucia-email-password

code loading...

Before continuing, let's also add `oslo` as an optimized dependency in our Vite configuration.

code loading...

Database setup

Let's now set up our database connection with Drizzle ORM, and create a basic schema for the database.

code loading...

Make sure to add the SQLITE_DB_URL environment variable to your .env file. For me, it looks like this:

SQLITE_DB_URL=src/lib/server/db/sqlite.db

Furthermore, make sure to add the src/lib/server/db/sqlite.db file to your `.gitignore` file.

Now, let's create the database schema.

code loading...

This is quite a simple schema. We have a users table with the email and the hashed password, and a sessions table with the user ID and the session ID. We also make sure to add timestamps to the tables.

Furthermore, we can now create a basic model for creating a user, getting a user by email, etc…

code loading...

Before having our schema applied to the DB, we need to configure Drizzle (Kit) to run migrations. I won't go over the details of how to do that here, but you can find more information in the  Drizzle documentation  .

Once all that is done, you should be able to run  pnpm push:sqlite --config=src/lib/server/db/drizzle.config.ts  to directly schema changes to the database, or  pnpm drizzle-kit generate:sqlite --config=src/lib/server/db/drizzle.config.ts  to generate the schema files for you.

Authentication setup with Lucia

Now that we have our database set up, we can start integrating Lucia for email and password authentication.

First, let's create the configuration for Lucia. We'll use the  @lucia-auth/adapter-sqlite  adapter, which is a SQLite adapter for Lucia.

code loading...

This code tells Lucia how the tables in the database are named, and how to map the attributes to the user and session objects.

You want to make sure to also set up the types for  User  and  Session  in your SvelteKit  locals  types for proper type safety.

Before we're able to use Lucia to sign up and log in users, we also need to set up checking the session cookie, invalidating or updating the  locals  with the proper value for the user and the session. This is done in the  server handle hook of our SvelteKit application  .

Again, to keep this article short, I will not go over the details of how to do that, but the overview steps are:

  1. Get the session ID from the session cookie.

  2. If there is no session ID, set the  user  and  session  locals to  null  and continue with the request.

  3. If there is a session ID, with a valid and fresh session, create a new session cookie with the session ID.

  4. If there is no session, create a blank session cookie.

  5. Set the  user  and  session  locals to the user and session objects.

  6. Continue with the request.

From there, we can use the  user  and  session  locals to sign up and login users, and handle the authentication flow.

The signup flow looks like this:

  1. The user submits the signup form with their email and password.

  2. We do the necessary checks to make sure the email is valid, and the password meets the required criteria.

  3. We hash the password and create a new user in the database.

  4. We create a new session for the user and set the session ID in the session cookie.

  5. This will automatically set the  user  and  session  locals with the user and session objects (from the handle hook).

  6. We can now redirect the user to the home page.

The login flow looks like this:

  1. The user submits the login form with their email and password.

  2. We do the necessary checks to make sure the email is valid, and the password meets the required criteria.

  3. We verify the user's password by hashing it and comparing it to the hashed password in the database.

  4. If the password is valid, we create a new session for the user and set the session ID in the session cookie.

  5. This will automatically set the  user  and  session  locals with the user and session objects (from the handle hook).

  6. We can now redirect the user to the home page.

That's it! With Lucia, we can easily handle authentication in our SvelteKit application and protect our routes and pages with a session-based authentication system.

If you're looking for a more complete and detailed code example for email and password authentication with Lucia, you can check out  our recipe on that  . With a few steps, you can easily have a fully functional email and password authentication system in your SvelteKit application.

And there's more!

By purchasing the lifetime license for  Om Recipes   , you also get access to a wide range of recipes and tutorials on how to build various types of applications with SvelteKit and Lucia.

This includes email and password authentication with email verification, password reset, OAuth 2.0 with GitHub, Google, Twitter, Stripe integration, and much more.