Authenticating Next.js with Auth0

Authenticating Next.js with Auth0

Authenticating Next.js applications is one of the first things we need to do when we want to use Next.js to build apps.

There are great options like Auth0 and NextAuth.js. We'll explore using the Next.js Auth0 package.

  1. Create an Auth0 account and app
  2. Install the Next.js Auth0 package
  3. Add environment variables to your .env.local file
  4. Create an API route /api/auth/[...auth0].js
  5. Wrap your app component with <UserProvider>
  6. Use the API routes or the useUser() helper!
  1. Have an Auth0 account and an Auth0 application created in the dashboard
  2. Have a Next.js app

That's it! Let's look at how we can integrate Auth0 to Next.js.

First, we need to install the package:

bash
npm install @auth0/nextjs-auth0

Make sure you can grab your Domain, Client ID, and Client Secret.

Auth0 Dashboard Credentials

Make sure that you create an app in your Auth0 dashboard and configure:

Create an .env.local file and add the following:

# A long, secret value used to encrypt the session cookie
AUTH0_SECRET='LONG_RANDOM_VALUE'

# The base url of your application
AUTH0_BASE_URL='http://localhost:3000'

# The url of your Auth0 tenant domain
AUTH0_ISSUER_BASE_URL='https://YOUR_AUTH0_DOMAIN.auth0.com'

# Your Auth0 application's Client ID
AUTH0_CLIENT_ID='YOUR_AUTH0_CLIENT_ID'

# Your Auth0 application's Client Secret
AUTH0_CLIENT_SECRET='YOUR_AUTH0_CLIENT_SECRET'

You can use the following code to generate an AUTH0_SECRET

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

The Next.js Auth0 package is easy to configure because it only requires adding a single file to your setup!

We will create a /pages/api/[...auth0].js file with the following:

jsx
// šŸ—‚ pages/api/[...auth0].js

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

export default handleAuth();

// you can even put more configuration in this handleAuth()
// https://auth0.github.io/nextjs-auth0/modules/config.html#2-create-your-own-instance-using-initauth0

That's step 1 to setting up the Next.js Auth0 package.

That isn't a typo with the [...auth0].js file. That is called a Catch all API route. This means that the Next.js Auth0 package can create all kinds of functionality with this file. For instance, here are some of the routes that this file creates:

  • /api/auth/login: Redirect a user to login
  • /api/auth/callback: Handle when a user comes back from a login provider like Google
  • /api/auth/logout: Log a user out
  • /api/auth/me: Get a user's information

We could use these routes ourselves (like http://localhost:3000/api/auth/login) and link a user to each one, but the Next.js Auth0 package also gives us helpful functions to do all of the above.

In our pages/_app.js component we can wrap our entire application with the UserProvider that the Next.js Auth0 package provides. This UserProvider provides data to our entire application. What's cool about this is that under the hood, it uses React's built-in Context.

jsx
// šŸ—‚ pages/_app.js

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

export default function App({ Component, pageProps }) {
  return (
    <UserProvider>
      <Component {...pageProps} />
    </UserProvider>
  );
}

And that's step 2 to configuring the Next.js Auth0 package! The next steps are to integrate into the code.

To log a user in, we just need to redirect them to the login route. We'll use the next/link package to do this.

jsx
import Link from 'next/link';

function LoginButton() {
  return (
    <Link href="/api/auth/login">
      <a>Login</a>
    </Link>
  )
}

They will be redirected to the Auth0 login page where they can login with username/password, social, or whatever else you setup.

Configuring the Types of Logins: The login options on the Auth0 login page are determined by your settings in the Auth0 dashboard.

We can direct a user to the API route to logout:

jsx
<Link href="/api/auth/logout">
  <a>Logout</a>
</Link>

To get a logged in user's information, we can use the useUser() hook that comes with the Next.js Auth0 package.

jsx
const { user, error, isLoading } = useUser();

And in a full component:

jsx
// šŸ—‚ pages/dashboard.js

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

export default function Dashboard() {
  const { user, error, isLoading } = useUser();

  // make sure we wait for everything to load
  if (isLoading) return <div>Loading...</div>;

  // if theres an error, show that
  if (error) return <div>{error.message}</div>;

  return (
    <div>
      <h1>Dashboard</h1>

      {/* show the user information */}
      {user && (
        <>
          <img src={user.picture} alt={user.name} />
          <h2>{user.name}</h2>
          <p>{user.email}</p>
        </>
      )}
    </div>
  );
}

Here's how we can use all the above information to create a navbar that shows user information and login/logout.

jsx
// šŸ—‚ components/Navbar.js

import Link from 'next/link';
import { useUser } from '@auth0/nextjs-auth0';

export default function Navbar() {
  const { user, error, isLoading } = useUser();

  // make sure we wait for everything to load
  if (isLoading) return <div>Loading...</div>;

  // if theres an error, show that
  if (error) return <div>{error.message}</div>;

  return (
    <nav>
      {/* left side of nav */}
      <div>
        <Link href="/">
          <a>Home</a>
        </Link>
      </div>

      {/* right side of nav */}
      <div>
        {/* user is not logged in */}
        {/* show login button */}
        {!user && <Link href="/api/auth/login"><a>Login</a></Link>}

        {/* user is logged in */}
        {/* show user info and logout button */}
        {user && (
          <>
            <span>
              <img src={user.picture} alt={user.name} /> {user.name}
            </span>
            <Link href="/api/auth/logout"><a>Logout</a></Link>
          </>
        )}
      </div>
    </nav>
  );
}

When we want to make sure that only an authenticated user uses an API route, we can use the Next.js Auth0 package's withApiAuthRequired() helper.

If the user is not authorized, they will get a 401 Unauthorized response.

jsx
// šŸ—‚ pages/api/protected-route.js

import { withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';

export default withApiAuthRequired(function ProtectedRoute(req, res) {

  const session = getSession(req, res);

    // now we have the user info with:
    // const user = session.user;

});

We've seen how to get user information from the client side with useUser(). We can also protect a route from the server-side so that a user won't see any part of the page. The client side protection way will show parts of the page but restrict sections after authentication is loaded.

We can protect normal page routes with withPageAuthRequired():

jsx
// šŸ—‚ pages/dashboard.js

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

// withPageAuthRequired will pass the user as a prop
export default function Dashboard({ user }) {
  return <div>Hi there {user.name}</div>;
}

export const getServerSideProps = withPageAuthRequired();

If the user is not logged in, they will automatically be redirected to the login page. After they login, they will be redirected back to the page they were trying to go to.

You can also pick the route that you want a user to be redirected to after they log in:

jsx
export const getServerSideProps = withPageAuthRequired({
  returnTo: '/dashboard'
});
Chris Sev

Chris Sev

Chris Sev is the co-founder of Better Dev. Coding better every day. Previously he created Scotch.io which was acquired.

In this article...

Comments

What did you think of the article? Let us know!
(these comments are powered by GitHub issues and use 0 trackers)