Add user management to a Next.js site with React server components, server actions, and AuthKit
The most tedious and difficult part of building a web app is authentication. But a new tool just entered the discussion that’s hoping to change that.
There are lots of options to get auth set up quickly, but they often aren’t built to handle the more complex, enterprise features that you hope to grow into over time. In the other direction, user management that’s powerful enough for a more mature company is usually so cumbersome and expensive to set up that it’s borderline foolish to start with it.
AuthKit caught my attention because its stated intention is to fit the needs of early-stage companies as well as more mature, complex use cases. They have a hosted UI for getting full-featured user management set up in a few lines of code, plus they have a full SDK for building custom user management flows and adding enterprise features like SSO. I love this, because it lines up with my views on progressive disclosure of complexity in software.
In this tutorial, you’ll use AuthKit to add user management to a Next.js project using the app directory, React server components, and server actions.
Enable authentication in your WorkOS dashboard
To enable authentication, head to dashboard.workos.com, then click the Authentication tab and make sure that at least one of the methods is enabled.
While you’re in here, also make sure to visit the Redirects tab and make sure http://localhost:3000/callback is added as a sign-in callback.
Get the project cloned and running
We’ll be starting from a modified version of the official AuthKit example app, which is built using the app directory in Next.js and Radix (the same UI library AuthKit uses to create the hosted UI). We’re not going to focus on the UI — instead, we’ll only be looking at the specific code that makes user login and session management work in the app.
To get started, clone the app:
Next, copy .env.local.example to .env.local and add the required environment variables:
Finally, start up local development to see the app.
Open http://localhost:3000 to see the running site.
Get the URL for signing in or signing up via AuthKit
Our first step is to get the URL that sends a user to AuthKit’s hosted sign in/sign up flow. To do that, make the following changes in src/auth.ts:
After initializing a new instance of the WorkOS Node SDK, this file also exports a new function called getAuthorizationUrl().
This function uses the user management API — WorkOS’s collection of features that make up AuthKit’s core functionality. The getAuthorizationUrl() method takes in the client ID and redirect URI (which were set via .env.local earlier) and the provider, which is set to 'authkit' to use the hosted UI.
Put this authorization URL to work by making the following changes in src/app/components/sign-in-button.tsx:
Save these changes, then click the “Sign In with AuthKit” button on the home page. You’ll be redirected to the hosted sign in/sign up flow
The user is authorizing the app, but there’s no handler in place to turn the authorization code into a user token. In the next step, we’ll implement the callback handler to exchange the code for a user token.
Create a callback handler for user logins
Exchange the code for user details by replacing the contents of src/app/callback/route.tsx with the following code:
To exchange the authorization code for user information, this code uses the authenticateWithCode() method.
Next, the user details are encoded into a JSON web token (JWT) using the jose package.
Once a token is created, the current URL is cloned, updated to point to the home page, and the code is deleted. This updated URL is where the user will be redirected after a successful authorization.
Finally, the token is added as an HTTP-only cookie before returning the response.
After saving, click the “Sign In with AuthKit” button again. You’ll end up back on the home page, which still needs changes to show a logged in user, but if you check the “application” tab in your devtools and look at cookies, you’ll see the token cookie is now present.
With the user token set, the next step is to read it and update the UI based on whether a user is logged in.
Add logic to verify and load a logged in user + log out
Now that a token is set when a user is logged in, add the logic to check and verify that token by making the following changes in src/auth.ts:
The verifyJwtToken() function uses the jose package to make sure the token was created using the secret key set in .env.local.
The getUser() function loads the token cookie, verifies it using verifyJwtToken(), then returns an object with the current authentication status (isAuthenticated) and, when a user is logged in, the user’s details such as name and email.
The clearCookie() function deletes the cookie and redirects the user to the home page — this will be used to handle the logout action.
Only show the account details page to logged in users
For protected routes, such as the account details page, use Next.js middleware to check for a valid token and, if none is found, redirect the user to the authorization URL. Replace the contents of src/middleware.ts with the following code:
After saving, delete the token cookie in the Application tab of your devtools and try to visit the account tab — you’ll be redirected to the AuthKit authorization flow.
Update the UI to use authentication information
The last step is to make the UI react to the presence of a logged in user.
Add user details to the account page
First, make the following changes to src/app/account/page.tsx:
The account page is only available to logged in accounts, so all it needs is the user details returned by getUser().
Turn the “sign in” button to a “sign out” button when logged in
Next, make the following changes to src/app/components/sign-in-button.tsx:
This change uses the actual authenticated status to show a “sign out” button when a user is logged in. It also uses a server action to delete the token cookie when clicked, allowing the user to log out and be redirected to the home page.
Update the home page for logged in users
Finally, make the following changes to src/app/page.tsx:
This swaps out the hard-coded values for real login status and user details. Save to see the user details displayed on the home page when a user is logged in.
Going further with user management
As your app grows, you may want to add new features or customize how things look. This is where AuthKit is uniquely valuable, as far as I can tell.
Bring your own UI
If you want to customize the UI instead of using a hosted workflow, the user management APIs are available in the WorkOS Node SDK to do anything AuthKit can do within your own UI.
I won’t go into how, but they have a ton of examples up on GitHub to get you started.
Add enterprise features
You might have spotted it when you enabled authentication in your WorkOS dashboard, but adding enterprise user management features like single sign-on is a checkbox away. For more details, check out my tutorial on SSO with WorkOS in a Node app.