MB
Auth0 Next.js Implementation Guide (with app router)

Auth0 Next.js Implementation Guide (with app router)

February 4, 2024

In this guide, we'll walk through the steps to integrate Auth0 into a Next.js application, leveraging the Next.js framework for server-side rendered applications. Auth0 provides a flexible, secure platform for authentication and authorization, and integrating it with Next.js allows for building secure, scalable, and user-friendly web applications.

Prerequisites

Before starting, ensure you have:

  • A basic understanding of Next.js.
  • An Auth0 account. Sign up for free if you don't have one.
  • Node.js installed on your computer.

Step 1: Setting Up Your Auth0 Account

  1. Create a New Application in Auth0: Log into your Auth0 dashboard, navigate to Applications > Applications, and click "Create Application."
  2. Select a Regular Web Application and proceed.
  3. Configure Your Application Settings: Specify your "Allowed Callback URLs," "Allowed Logout URLs," and "Allowed Web Origins" to include your development and production URLs.

Step 2: Installing Auth0 SDK for Next.js

Auth0 provides an SDK specifically designed for Next.js applications. Install it using npm or yarn:

scss

npm install @auth0/nextjs-auth0

Step 3: Setting Up Auth0 SDK


Configure the SDK by creating a .env.local file at the root of your project and adding your Auth0 credentials base on project setting configuration on the auth0 app dashboard

auth0 settings
auth0 settings

To create your secret, use the command:

sh

node -e "console.log(crypto.randomBytes(32).toString('hex'))"
auth0 secret

sh

AUTH0_SECRET='YOUR_SECRET'
AUTH0_BASE_URL='http://localhost:3000'
AUTH0_ISSUER_BASE_URL='https://YOUR_DOMAIN.auth0.com'
AUTH0_CLIENT_ID='YOUR_CLIENT_ID'
AUTH0_CLIENT_SECRET='YOUR_CLIENT_SECRET'

Replace placeholders with your actual Auth0 domain and client details.

Create a file named route.ts inside the src/app/api/auth/[auth0] directory. This file will handle login, logout, and callback URLs:

typescript

import { handleAuth } from '@auth0/nextjs-auth0';

export default handleAuth();

Next wrap the RootLayout component with UserProvider

typescript

import Navbar from "@/components/NavBar";
import { UserProvider } from "@auth0/nextjs-auth0/client";
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};

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

Step 4: Using Auth0 for Authentication

To add login and logout functionality, use the Auth0 hooks and components provided by the SDK. For example, create a components/NavBar.js:

typescript

"use client";
import { useUser } from "@auth0/nextjs-auth0/client";
import Link from "next/link";

const Navbar = () => {
const { user, isLoading } = useUser();

return (
<nav className="bg-gray-800 text-white p-4">
<div className="container mx-auto flex justify-between items-center">
<div className="text-lg font-semibold">MyApp</div>
<div>
{user && (
<Link
href="/api/auth/logout"
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
>
Sign Out
</Link>
)}
{!user && !isLoading && (
<Link
href="/api/auth/login?returnTo=%2Fprofile"
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
>
Login
</Link>
)}
</div>
</div>
</nav>
);
};

export default Navbar;

Authentication Links:

  • Sign Out: When a user is authenticated (user object exists), a "Sign Out" link is displayed. Clicking this link redirects the user to /api/auth/logout, triggering the Auth0 logout process. This link is styled with Tailwind CSS to stand out and provide feedback on hover, indicating it's clickable.
  • Login: If there's no authenticated user (user is falsy) and the component is not in a loading state (isLoading is falsy), a "Login" link is shown. This link directs the user to /api/auth/login?returnTo=%2Fprofile, where Auth0 handles the authentication, and upon successful login, the user is redirected back to the /profile page. The login link is also styled for visual consistency and interactivity.

When you set up all correctly, you would see the login form after clicking the sign in button:

Step 5: Protecting Routes

To secure a page or API route, use the withPageAuthRequired higher-order function for pages and withApiAuthRequired for API routes. Only logged in users will be able to access it. If the user is logged out, they will be redirected to the login page instead.

Client side rendering

typescript

"use client";

import { withPageAuthRequired } from "@auth0/nextjs-auth0/client";

export default withPageAuthRequired(function CSRPage() {
return (
<>
<div className="mb-5">
<h1>Client-side Rendered Page</h1>
<div>
Protected client-side rendered page. Only logged in users can access
</div>
</div>
</>
);
});

Client Site profile page

Using the useUser from @auth0/nextjs-auth0 to get the current user state.

typescript

"use client";

import { useUser, withPageAuthRequired } from "@auth0/nextjs-auth0/client";

import Alert from "@/components/Alert";
import Highlight from "@/components/Highlight";
import Loading from "@/components/Loading";
import Image from "next/image";

function Profile() {
const { user, isLoading } = useUser();

return (
<>
{isLoading && <Loading />}
{user && (
<>
<div>
<Image
src={user.picture || "https://via.placeholder.com/200"}
alt={user.name || "profile picture"}
width={200}
height={200}
/>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>

<Highlight>{JSON.stringify(user, null, 2)}</Highlight>
</>
)}
</>
);
}

export default withPageAuthRequired(Profile, {
onRedirecting: () => <Loading />,
onError: (error) => <Alert>{error.message}</Alert>,
});

Handling the Redirect with onRedirecting

When a user accesses a page that requires authentication, there's a brief period during which the authentication status is being determined before potentially redirecting them to the login page. The onRedirecting option allows developers to define a custom behavior or display a specific component during this interim period. This feature is invaluable for maintaining a smooth and informative user experience, as it enables you to present a loading indicator or a message indicating that the authentication process is underway.

For example, you might utilize onRedirecting to show a spinner or a "Please wait" message. This immediate feedback to the user helps prevent confusion and reassures them that the application is processing their request, thus enhancing the overall perception of your application's responsiveness.

Graceful Error Handling with onError

Despite our best efforts, errors can occur during the authentication process. These could be due to network issues, configuration errors, or expired sessions. The onError option is your tool for gracefully handling such incidents. It allows you to define how to respond to authentication errors, be it through displaying an error message to the user, redirecting them to an error page, or logging the error for further investigation.

Implementing a thoughtful onError strategy ensures that users are not left stranded without guidance when something goes wrong. Instead, they receive clear communication about the issue and, when possible, instructions on how to resolve it or proceed.

Server side rendering

typescript

import { getSession, withPageAuthRequired } from "@auth0/nextjs-auth0";

import Highlight from "@/components/Highlight";

export default withPageAuthRequired(
async function SSRPage() {
const session = await getSession();
const user = session?.user;
return (
<>
<div className="mb-5">
<h1>Server-side Rendered Page</h1>
<div>
Protected server-side rendered page. Only logged in users can access
</div>
</div>
<h6>User</h6>
<Highlight>{JSON.stringify(user, null, 2)}</Highlight>
</>
);
},
{ returnTo: "/ssr" }
);

Customization of Redirect Behavior: The withPageAuthRequired function is configured with an option ({ returnTo: "/ssr" }) specifying the URL to redirect users to after they log in. This customization enhances the user experience by directing users back to the intended page once they are authenticated.

example code: github Auth0-example

Conclusion

You have now successfully integrated Auth0 into your Next.js application, enabling secure authentication and protecting routes. This setup provides a robust authentication mechanism, enhancing the security and user experience of your Next.js application.

For further details and advanced configurations, visit the Auth0 documentation.

Happy coding!