This is an example project showcasing how to integrate SvelteKit with AuthJS and Zitadel for authentication.
You can follow the Next.js tutorial provided by Zitadel for the initial setup. Be sure to set the redirect URI to [origin]/auth/callback/zitadel in your Zitadel configuration.
To run the project, follow these steps:
- Copy the provided .env.example file to .env and fill in all the required fields.
- Open your terminal and run the following commands:
npm install
npm run dev
The project will be accessible on port 5173.
SvelteKit provides various methods for route protection. You can find detailed information on these methods in the @auth/sveltekit documentation. In this project, I've chosen the layout-based protection method hoping that this sveltekit issue is soon fix, but please note that you can adjust the approach based on your requirements.
This method is currently recommended by the AuthJS creator on a per-component basis. It helps avoid race conditions between +layout.server.ts
and +page.server.ts
.
Example implementation:
import { redirect } from "@sveltejs/kit";
import type { PageServerLoad } from "./$types";
export const load: PageServerLoad = async (event) => {
const session = await event.locals.getSession();
if (!session?.user) throw redirect(303, "/auth/signin");
return {};
};
This approach involves a slight risk of encountering the issue linked earlier. However, it offers advantages in terms of layout management. In this project, protected routes are placed in the (auth) directory.
+layout.server.ts
example:
import type { LayoutServerLoad } from "./$types";
export const load: LayoutServerLoad = async (event) => {
return {
session: await event.locals.getSession(),
};
};
+page.server.ts
example:
import { redirect } from "@sveltejs/kit";
import type { PageServerLoad } from "./$types";
export const load: PageServerLoad = async (event) => {
const { session } = await event.parent();
if (!session?.user) {
throw redirect(303, /auth/signin);
}
return {};
};
This method is described here. It offers flexibility, but please note that SvelteKit does not always call it. Details on when it's called can be found here
In the project, there's a route called auth
that plays a crucial role. This route is necessary because SvelteKit's server cannot directly redirect the user to Zitadel's login page; instead, it must route them through /auth/signin
.
However, to avoid this behavior, the SvelteKit server will redirect the user to the /auth
page, which will trigger AuthJS's authentication function for signing in through Zitadel.
To streamline this process and allow users to return to their previous page after login, we've added a redirect search parameter to these requests. You can see this behavior in the following files:
/src/routes/(auth)/protected/+page.server.ts
/src/routes/auth/+page.svelte
By implementing this approach, we aim to provide a smoother user experience for your authentication flow.
- In Zitadel, create the role "Admin."
- Assign the "Admin" role to a user within your project.
- To enable authorization in the project, ensure that you fill in the variable
ZITADEL_RESOURCE_ID
in the environment file. - Logout from the user if you were connected before editing the authorizations.
To test Authorization I made the page Admin. If everything is correct you should see that the user has the "Admin" authorization.
- To access additional data from the user's profile, set the callback
jwt
andsignin
in the file/src/hooks.server.ts
. - If you need to add custom data to the session and keep intellisense, modify the file
/src/types/auth.d.ts
.
To get more information about this visit the page Authorization.
Before you proceed with the instructions, ensure that you have set up the required metadata in Zitadel. For detailed information on setting up metadata in Zitadel, please refer to the Zitadel claims documentation.
Before you can request user information, make sure you have completed the following steps:
- As for the roles you have to set the
ZITADEL_RESOURCE_ID
in .env file - In this project it is already set but remember to add
urn:zitadel:iam:user:metadata
as a param scope. This scope is required to access user metadata. - In your profile callback function, you will receive user metadata as an object with key-value pairs. It's important to note that the values are encoded in base64, so you must decode them before reading their contents.
While the previous methods demonstrate how to obtain user information from a token, you can also use an alternative approach requesting the userinfo
from the Zitadel endpoint. Details on how I implemented it can be found in the +layout.server.ts
file.
To view the adapter implementation, switch to the 'adapter' branch.## Why use it?
The adapter is a powerful tool that simplifies user registration and management. If you want to automate the process of saving and registering users, the adapter is the easiest way to achieve this.
In the hooks.server.ts
file, you can set the session strategy. There are two main options available:
- Database Strategy: This strategy does not use a JWT token. Instead, all user data is stored in the profile callback. While this approach means you lose the ability to request user information using an access token, you can access user data in the database. If you wish to store permissions and metadata, you will need to modify the models accordingly.
- JWT Strategy: This strategy follows a workflow similar to the one used previously. In this project, we focus on the JWT strategy as it aligns with the Zitadel tutorial.
I hope this project helps people integrate their SvelteKit projects with Zitadel!