Zero
Zero
Back

Integrating Auth0 with Next.js for Authentication

Quickly set up authentication in a Next.js app with Auth0 so you don't have to code it yourself.

Sam Magura

Sam Magura

A 3D render of abstract shapes

Building authentication into your app from scratch is a lot of work, especially if you want to support multiple authentication methods — e.g. allowing the user to sign in with their Google account. Your team can save a ton of work by delegating authentication to a third-party service like Auth0 , a comprehensive authentication solution that can be integrated into almost any app.

The most common flow when using Auth0 is that the user clicks a "log in" button in your web app and they get redirected to a login page that's hosted on Auth0's servers. After the user logs in or creates a new account, Auth0 will call your application's "auth callback" with the user's info.

In this blog post, we'll walk through implementing Auth0 authentication in a Next.js web application. The Zero secrets manager will be used to securely retrieve the Auth0 client credentials from the cloud when the application starts up.

🔗 The full code for this example is available in the zerosecrets/examples  GitHub repository.

Secure your secrets conveniently

Zero is a modern secrets manager built with usability at its core. Reliable and secure, it saves time and effort.

Zero dashboard

Creating the Auth0 Application

The Auth0 team has made our job really easy by providing an SDK for Next.js along with a step-by-step guide  for using it. This post will roughly follow the official integration guide, with some changes to support integrating the Auth0 SDK with Zero.

As stated in the integration guide, the first step is to log in to Auth0. This will create a new Auth0 tenant, if you don't already have one. Once you have reached the Auth0 dashboard, create a new application. Select "Regular web application" for the type, and select Next.js for the technology.

With the application created, switch to the Settings tab of the application screen. The following fields should be copied into a new secret within Zero:

  • Domain
  • Client ID
  • Client secret
  • Secret - a random string you can generate by running openssl rand -hex 32 in the terminal

Creating the Auth0 secret in Zero
Creating the Auth0 secret in Zero

Make sure to copy the project's Zero token to a file on your local PC.

Return to the application settings page in Auth0. Set http://localhost:3000/api/auth/callback as an allowed callback URL, and set http://localhost:3000/ as an allowed logout URL. If this was a production tenant, you would replace localhost:3000 with your real domain name.

Creating the Next.js App

Now that the Auth0 configuration is complete, bootstrap a new Next.js application with the command

Terminal
npx create-next-app@latest auth0-app

Make sure to select the App Router at the relevant prompt. I also opted to use Tailwind CSS.

Now, cd into the project's directory and install the Auth0 Next.js SDK and the Zero TypeScript SDK :

Terminal
npm install @auth0/nextjs-auth0 @zerosecrets/zero

Initializing the Auth0 SDK

This is where our walkthrough deviates from the official integration guide provided by Auth0. Their guide configures the Auth0 SDK using environment variables in a .env file. Instead of using .env, we will fetch the secrets from Zero at runtime. This requires us to initialize the Auth0 SDK using the initAuth0 function instead of relying on the automatic initialization mechanism.

Create a new file called util/auth0.ts to initialize the SDK. In this file, we implement the standard pattern for fetching secrets from Zero and passing them to a 3rd party SDK:

util/auth0.ts
import {initAuth0} from '@auth0/nextjs-auth0' import {zero} from '@zerosecrets/zero' export async function getAuth0() { if (!process.env.ZERO_TOKEN) { throw new Error('Did you forget to set the ZERO_TOKEN environment variable?') } const secrets = await zero({ token: process.env.ZERO_TOKEN, pick: ['auth0'], }).fetch() if (!secrets.auth0) { throw new Error('Did not receive Auth0 secrets.') } return initAuth0({ secret: secrets.auth0.secret, baseURL: 'http://localhost:3000', issuerBaseURL: `https://${secrets.auth0.domain}`, clientID: secrets.auth0.client_id, clientSecret: secrets.auth0.client_secret, }) }

Creating the Dynamic Route Handler

The API methods forlogin, logout, and the auth callback are handled by the Auth0 SDK. To hook these API methods up, create a new route handler at app/api/auth/[auth0]/route.ts. Here, [auth0] is a dynamic route segment that can match any string.

The code for the route handler makes use of the getAuth0 function we created in the previous section:

app/api/auth/[auth0]/route.ts
import {getAuth0} from '../../../../../util' const auth0 = await getAuth0() export const GET = auth0.handleAuth()

This creates the following API methods:

  • /api/auth/login
  • /api/auth/logout
  • /api/auth/callback
  • /api/auth/me

Since we're using a top-level await statement, you'll need to tweak your TSConfig to avoid a compiler error. In tsconfig.json, set target: "es2020" to enable support for top-level await.

Now's a good time to run your application to make sure it starts up successfully. Remember to provide the Zero token as an environment variable so the secrets can be retrieved from the cloud:

Terminal
ZERO_TOKEN='...' npm run dev

Building the Frontend

Let's edit the homepage, app/page.tsx, to add log in / log out buttons and a message that displays the currently-signed in user, if authentication was successful. To create a log in button, you'll use a plain <a> tag like this:

app/page.tsx
<a href="/api/auth/login">Log in</a>

Don't use the Next.js <Link> component — that won't work.

Upon clicking the login button, you'll be redirected to the Auth0 login page. Register for a new account, and you'll be redirected back to the Next.js application.

Displaying the Current User

Now, we'd like to display the current user. There are two ways to access the current user — <UserProvider> + useUser for client components, and getSession for server components. I'll be using client components in my demo. There is an example of getSession in the official Auth0 integration guide .

UserProvider is a React context provider that should be rendered at the top of the component tree. To add it to your app, edit the root layout (app/layout.tsx) like so:

app/layout.tsx
export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode }>) { return ( <html lang="en"> <UserProvider> <body className={inter.className}>{children}</body> </UserProvider> </html> ) }

Now, return to app/page.tsx to display the current user, and conditionally render "Log in" or "Log out" based on whether the user is signed in.

app/page.tsx
'use client' import {useUser} from '@auth0/nextjs-auth0/client' export default function Home() { const userContext = useUser() return ( <main> <h1 className="text-4xl mb-6 font-bold">Next.js Auth0 App</h1> <p className="mb-4"> {userContext.user ? `You are logged in as ${userContext.user.email}` : 'You are not logged in.'} </p> <p> {userContext.user ? ( <a href="/api/auth/logout" className="text-blue-600 underline"> Log out </a> ) : ( <a href="/api/auth/login" className="text-blue-600 underline"> Log in </a> )} </p> </main> ) }

Here are screenshots of my finished demo:

The demo app, while not logged in
The demo app, while not logged in

The demo app, while logged in
The demo app, while logged in

Wrapping Up

Integrating Auth0 with Next.js is very straightforward, thanks to the Auth0 Next.js SDK. It would be much more work to accomplish the same thing without this SDK. We also benefitted from using Zero to pull down multiple secrets from the cloud when the app starts up, so we don't have to store them in a .env file.


Other articles

A door handle

Use Pusher to Implement Real-Time Notifications

Pusher makes it easy to add pub-sub functionality to your web apps, allowing you to implement chat, notifications, and more.

Old-school mailboxes at a post office

Using Notion as a Human-Readable Database

Capture form submissions from your web app and store them where your team works.

Secure your secrets

Zero is a modern secrets manager built with usability at its core. Reliable and secure, it saves time and effort.