AuthKit Next.js Library
The AuthKit library for Next.js provides convenient helpers for authentication and session management using WorkOS & AuthKit with Next.js.
Note: This library is intended for use with the Next.js App Router.
Installation
Install the package with:
npm i @workos-inc/authkit-nextjs
or
yarn add @workos-inc/authkit-nextjs
Video tutorial
Pre-flight
Make sure the following values are present in your .env.local
environment variables file. The client ID and API key can be found in the WorkOS dashboard, and the redirect URI can also be configured there.
WORKOS_CLIENT_ID="client_..."
WORKOS_API_KEY="sk_test_..."
WORKOS_COOKIE_PASSWORD="<your password>"
NEXT_PUBLIC_WORKOS_REDIRECT_URI="http://localhost:3000/callback"
WORKOS_COOKIE_PASSWORD
is the private key used to encrypt the session cookie. It has to be at least 32 characters long. You can use the 1Password generator or the openssl
library to generate a strong password via the command line:
openssl rand -base64 24
To use the signOut
method, you'll need to set your app's homepage in your WorkOS dashboard settings under "Redirects".
Optional configuration
Certain environment variables are optional and can be used to debug or configure cookie settings.
WORKOS_COOKIE_MAX_AGE='600'
WORKOS_COOKIE_DOMAIN='example.com'
WORKOS_COOKIE_NAME='authkit-cookie'
WORKOS_API_HOSTNAME='api.workos.com'
WORKOS_API_HTTPS=true
WORKOS_API_PORT=3000
WORKOS_COOKIE_DOMAIN
can be used to share WorkOS sessions between apps/domains.
Note: The WORKOS_COOKIE_PASSWORD
would need to be the same across apps/domains.
Not needed for most use cases.
Setup
Callback route
WorkOS requires that you have a callback URL to redirect users back to after they've authenticated. In your Next.js app, expose an API route and add the following.
import { handleAuth } from '@workos-inc/authkit-nextjs';
export const GET = handleAuth();
Make sure this route matches the WORKOS_REDIRECT_URI
variable and the configured redirect URI in your WorkOS dashboard. For instance if your redirect URI is http://localhost:3000/auth/callback
then you'd put the above code in /app/auth/callback/route.ts
.
You can also control the pathname the user will be sent to after signing-in by passing a returnPathname
option to handleAuth
like so:
export const GET = handleAuth({ returnPathname: '/dashboard' });
Middleware
This library relies on Next.js middleware to provide session management for routes. Put the following in your middleware.ts
file in the root of your project:
import { authkitMiddleware } from '@workos-inc/authkit-nextjs';
export default authkitMiddleware();
export const config = { matcher: ['/', '/admin'] };
Custom redirect URI
In cases where you need your redirect URI to be set dynamically (e.g. Vercel preview deployments), use the redirectUri
option in authkitMiddleware
:
import { authkitMiddleware } from '@workos-inc/authkit-nextjs';
export default authkitMiddleware({
redirectUri: 'https://foo.example.com/callback',
});
export const config = { matcher: ['/', '/admin'] };
Custom redirect URIs will be used over a redirect URI configured in the environment variables.
Usage
Wrap your app in AuthKitProvider
Use AuthKitProvider
to wrap your app layout, which adds some protections for auth edge cases.
import { AuthKitProvider } from '@workos-inc/authkit-nextjs';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<AuthKitProvider>{children}</AuthKitProvider>
</body>
</html>
);
}
Get the current user
For pages where you want to display a signed-in and signed-out view, use withAuth
to retrieve the user profile from WorkOS.
import Link from 'next/link';
import { getSignInUrl, getSignUpUrl, withAuth, signOut } from '@workos-inc/authkit-nextjs';
export default async function HomePage() {
const { user } = await withAuth();
if (!user) {
const signInUrl = await getSignInUrl();
const signUpUrl = await getSignUpUrl();
return (
<>
<Link href={signInUrl}>Log in</Link>
<Link href={signUpUrl}>Sign Up</Link>
</>
);
}
return (
<form
action={async () => {
'use server';
await signOut();
}}
>
<p>Welcome back {user?.firstName && `, ${user?.firstName}`}</p>
<button type="submit">Sign out</button>
</form>
);
}
Requiring auth
For pages where a signed-in user is mandatory, you can use the ensureSignedIn
option:
const { user } = await withAuth({ ensureSignedIn: true });
Enabling ensureSignedIn
will redirect users to AuthKit if they attempt to access the page without being authenticated.
Middleware auth
The default behavior of this library is to request authentication via the withAuth
method on a per-page basis. There are some use cases where you don't want to call withAuth
(e.g. you don't need user data for your page) or if you'd prefer a "secure by default" approach where every route defined in your middleware matcher is protected unless specified otherwise. In those cases you can opt-in to use middleware auth instead:
import { authkitMiddleware } from '@workos-inc/authkit-nextjs';
export default authkitMiddleware({
middlewareAuth: {
enabled: true,
unauthenticatedPaths: ['/', '/about'],
},
});
export const config = { matcher: ['/', '/admin/:path*', '/about'] };
In the above example the /admin
page will require a user to be signed in, whereas /
and /about
can be accessed without signing in.
unauthenticatedPaths
uses the same glob logic as the Next.js matcher.
Retrieve session in middleware
Sometimes it's useful to check the user session if you want to compose custom middleware. The getSession
helper method will retrieve the session from the cookie and verify the access token.
import { authkitMiddleware, getSession } from '@workos-inc/authkit-nextjs';
import { NextRequest } from 'next/server';
export default async function middleware(request: NextRequest) {
const response = await authkitMiddleware()(request);
const session = await getSession(response);
return response;
}
export const config = { matcher: ['/', '/account/:path*'] };
Signing out
Use the signOut
method to sign out the current logged in user and redirect to your app's homepage. The homepage redirect is set in your WorkOS dashboard settings under "Redirect".
Visualizing an impersonation
Render the Impersonation
component in your app so that it is clear when someone is impersonating a user.
The component will display a frame with some information about the impersonated user, as well as a button to stop impersonating.
import { Impersonation } from '@workos-inc/authkit-nextjs';
export default function App() {
return (
<div>
<Impersonation />
{/* Your app content */}
</div>
);
}
Get the access token
Sometimes it is useful to obtain the access token directly, for instance to make API requests to another service.
import { withAuth } from '@workos-inc/authkit-nextjs';
export default async function HomePage() {
const { accessToken } = await withAuth();
if (!accessToken) {
return <div>Not signed in</div>;
}
const serviceData = await fetch('/api/path', {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
return <div>{serviceData}</div>;
}
Refreshing the session
Use the refreshSession
method in a server action or route handler to fetch the latest session details, including any changes to the user's roles or permissions.
The organizationId
parameter can be passed to refreshSession
in order to switch the session to a different organization. If the current session is not authorized for the next organization, an appropriate authentication error will be returned.
Debugging
To enable debug logs, initialize the middleware with the debug flag enabled.
import { authkitMiddleware } from '@workos-inc/authkit-nextjs';
export default authkitMiddleware({ debug: true });
Troubleshooting
NEXT_REDIRECT error when using try/catch blocks
Wrapping a withAuth({ ensureSignedIn: true })
call in a try/catch block will cause a NEXT_REDIRECT
error. This is because withAuth
will attempt to redirect the user to AuthKit if no session is detected and redirects in Next must be called outside a try/catch.