Ejiro Asiuwhu Frontend Engineer with rock-solid experience in building complex interactive applications with JavaScript, TypeScript Vue.js, NuxtJS, React, Next.js, and other tools in the JavaScript ecosystem. Decomposing complex problems into logic, data, and UI components are my forte, and despite JavaScript frameworks, I build products that scale well 🚀. I author meaningful technical content, regularly ✍🏽.

How to use NextAuth.js for client-side authentication in Next.js

9 min read 2664

Next.js Logo

Introduction

Authentication is an important and sensitive feature in applications where a user’s credential such as username, email, and password are validated to confirm if users are who they say they are.

It is a way of asking users who they are, and then receiving evidence to verify their identity. The system takes credentials provided by the user and checks if they are valid.

In this article, we’ll walk you through how to set up client-side authentication that doesn’t require a password in Next.js using a powerful and secure library called NextAuth.js.

By the end of this post, you will have created an app with authentication where your users will be able to log in using their Github, Google, and Facebook accounts. Upon successful signup, we will display the user’s profile picture, email, which we’ll retrieve from their social media accounts.

We will make use of React Hooks and functional components to build out our app. But before we dive deeper, let’s take a look at the two major tools we will be using.

What is Next.js?

Next.js is a framework built on top of React that makes developing production-ready, fully-optimized React apps super fast and easy. It is one of the best things to have come out of the React ecosystem, as it comes with a whole lot of power with zero config.

Next.js is used in production by top companies like Netflix, Tiktok, and Nike. It is super easy to learn, especially when you’re familiar with React.

What is NextAuth.js?

NextAuth.js is a completely secured authentication solution for implementing authentication in Next.js applications. It is a flexible authentication library designed to sync with any OAuth service, with full support for passwordless sign in.

It can be used with or without a database, and it has default support for popular databases such as MySQL, MongoDB, PostgreSQL, and MariaDB.

It can be used without a database by syncing with services like OAuth and JSON Web Token.

We made a custom demo for .
No really. Click here to check it out.

How NextAuth.js works

With a library like NextAuth.js, you don’t need to be an expert in identity protocol like you would if you were to use OAuth to build secured Next.js applications. NextAuth.js is built to avoid the need to store sensitive data, such as a users’ password. It works perfectly with Next.js. With just 20 lines of code, you can implement an authentication feature in your app.

NextAuth.js has a client-side API you can use to interact with sessions in your app. The session data returned from the Providers contains user payload, and this can be displayed to the user upon successful login.

The session data returned to the client looks like this:

{
  expires: '2055-12-07T09:56:01.450Z';
  user: {
        email: '[email protected]';
        image: 'https://avatars2.githubusercontent.com/u/45228014?v=4';
        name: 'Ejiro Asiuwhu';
    }
}

Observe that the payload doesn’t contain any sensitive data. The session payload or data is meant for presentation purposes — that is, it’s meant to be displayed to the user

NextAuth.js provides the useSession() React Hook, which can be used to check the user login status.

Meanwhile, NextAuth.js provides a REST API which is used by the React app. To learn more about the REST API NextAuth exposes, check out the official docs.

Requirements

  • Nodejs 10.13 or later installed on your local machine
  • Basics of React.js

Get the starter application

I have created a Next.js project using the npx create-next-app.

Clone this repository and checkout to the starter branch if you want to follow along. If you want to see the finished code, check out to the complete branch.

git clone https://github.com/ejirocodes/Nextjs_Authentication.git

Once the repository has been cloned, switch to the working directory:

cd Nextjs_Authentication

Install Next.js dependencies:

npm i

Switch to the starter branch:

git checkout starter

Launch the development server:

npm run dev

By default, the project will run on port 3000. Launch your browser and navigate to http://localhost:3000. You should end up with this:

Starter Project

Connect your Next.js app with NextAuth.js

The first step is to install next-auth. next-auth is an npm package, so installing it will be a breeze.

npm i next-auth

Upon successful installation, next-auth should be added to the dependencies in your package.json file. We are going to give our users the choice to log in to our app using their GitHub, Google, and Facebook accounts.

Next-Auth After installation

Create a GitHub OAuth app

Next, we are going to add a GitHub Authentication Provider, which essentially allows users to log into our app using their GitHub account. But first, we need to create a GitHub OAuth app. Click on New OAuth app and fill the form accordingly. Checkout the official docs to learn more.

  • Application name: This is the name of your application. It can be called anything — it doesn’t really matter
  • Homepage URL: This is the full URL to the homepage of our app. Since we are still in development mode, we are going to fill in the full URL that our development server is running on. In my case, it is http://localhost:3000
  • Authorization callback URL: This is the URL that GitHub will redirect our users to after they have been successfully logged in to our app. It should be your homepage URL plus /api/auth/callback, resulting in http://localhost:3000/api/auth/callback

After registration of our OAuth App, GitHub creates a Client ID and Client secrets specifically for our newly created app. Copy the client ID and secret key to your clipboard. Click on Generate new client secret and get a client secret.

Add environmental variable

Create an .env.local file in the root directory of your project. It can’t be a random name. After that, populate it with the following content:

GITHUB_ID=<cilent id of your github auth app should go in here>
GITHUB_SECRET=<clent secret of your github app should go in here>
NEXTAUTH_URL=http://localhost:3000

NEXTAUTH_URL is the url of our app. Make sure to use the port your development server is running on.

Now, back to our app. We are going to create a file named [...nextauth].js in pages/api/auth and add the following lines of code:

import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'

const options = {
    providers: [
        Providers.GitHub({
            clientId: process.env.GITHUB_ID,
            clientSecret: process.env.GITHUB_SECRET
        }),
    ],
}

export default (req, res) => NextAuth(req, res, options)

On line 1, we are importing NextAuth, which is our main package. In line 2, we are importing Providers from the next-auth library, which are services that we can integrate into our app to allow user sign in with OAuth.

On line 6, we are configuring GitHub on our providers and passing in our GitHub secret and client id through our environmental variables. Finally, in line 13, we are exporting a function that returns the NextAuth and takes in the options variable as a third parameter.

Ladies and gents, the magic has happened already. If we make use of the REST API that next-auth provides us, we can log in to our app using our GitHub account. Navigate to http://localhost:3000/api/auth/signin and you should see this 👇🏽

Sign in With Github Activated

Follow the process, and shazam! You are logged in. Up next, we need to save and display the login state of our users.

Check user login state with the useSession() Hook

We need to get the log in state of our user and render the user’s details on the frontend of our app. This can be easily achieved by using a Next.js feature called custom app. Then, we’ll wrap our component in a Provider.

Create an _app.js file in your pages directory (if it doesn’t already exist) and add the following lines of code:

import { Provider } from 'next-auth/client'
function MyApp({ Component, pageProps }) {
  return (
      <Provider session={pageProps.session}>
        <Component {...pageProps} />
      </Provider>
  )
}
export default MyApp

By wrapping our component in a Provider, it will allow session state to be shared between pages, which will in turn preserve our state during page navigation, improve performance, and reduce network traffic.

Next, open the components/Header.js file and import useSession, signIn and signOut from next-auth/client:

import { useSession, signIn, signOut } from 'next-auth/client'

useSession will be used to manage the sign in and sign out state of our users, while signIn and signOut will be used to perform the login and logout features in our app.

Let’s make use of the useSession Hook:

 const [session] = useSession();

The session will return the user’s details. Let’s use the details returned to conditionally render a sign in and sign out button.

Replace everything in the return statement in components/Header.js with the following lines of code:

 <div className='header'>
      <Link href='/'>
        <a className='logo'>NextAuth.js</a>
      </Link>
           {session && <a href="#" onClick={handleSignout} className="btn-signin">Sign out</a>  } 
           {!session && <a href="#" onClick={handleSignin}  className="btn-signin">Sign in</a>  } 
    </div>

We need to create the signin and signout methods to enable our users to sign in and sign out:

const handleSignin = (e) => {
      e.preventDefault()
      signIn()
  }    
const handleSignout = (e) => {
      e.preventDefault()
      signOut()
    }

Your Header.js should now look like this:

import Link from 'next/link'
import { useSession, signIn, signOut } from 'next-auth/client'
export default function Header() {

  const [session] = useSession();

    const handleSignin = (e) => {
      e.preventDefault()
      signIn()
  }
    const handleSignout = (e) => {
      e.preventDefault()
      signOut()
    }
  return (
    <div className='header'>
      <Link href='/'>
        <a className='logo'>NextAuth.js</a>
      </Link>
           {session && <a href="#" onClick={handleSignout} className="btn-signin">Sign out</a>  } 
           {!session && <a href="#" onClick={handleSignin}  className="btn-signin">Sign in</a>  } 
    </div>
  )
}

Feel free to sign in and sign out of the app using the header button.

Retrieve and display user information

Now, onto our pages/index.js. We need to display and conditionally render the user’s details based on their login details. First, we have to import the useSession Hook from next-auth in our node_modules folder.

So, replace your index.js with the following content:

import Head from 'next/head'
import Header from '../components/Header'
import styles from '../styles/Home.module.css'
import { useSession } from 'next-auth/client'

export default function Home() {

  const [session, loading] = useSession();

  return (
    <div className={styles.container}>
      <Head>
        <title>Nextjs | Next-Auth</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <Header />
      <main className={styles.main}>
        <h1 className={styles.title}>Authentication in Next.js app using Next-Auth</h1>
        <div className={styles.user}>
          {loading && <div className={styles.title}>Loading...</div>}
          {session && <> <p style={{ marginBottom: '10px' }}> Welcome, {session.user.name ?? session.user.email}</p> <br />
            <img src={session.user.image} alt="" className={styles.avatar} />
          </>}
          {!session &&
            <>
              <p className={styles.title}>Please Sign in</p>
              <img src="https://cdn.dribbble.com/users/759083/screenshots/6915953/2.gif" alt="" className={styles.avatar} />
        <p className={styles.credit}>GIF by <a href="https://dribbble.com/shots/6915953-Another-man-down/attachments/6915953-Another-man-down?mode=media">Another man</a> </p>            
</>
          }
        </div>
      </main>
    </div>
  )
}

Above, we are conditionally rendering the user’s image, name, and photo using the data gotten from our session state if they are logged into our app. If not, we display a dummy GIF with a text instructing them to sign in.

Create a Google OAuth app

To allow users log in to our app using their Google account, we have to obtain OAuth 2.0 client credentials from the Google API Console. Navigate to credentials and click on Create credentials, and then OAuth client ID:

Create Google Oauth Client ID

You will be asked to fill in the following:

  • Name: This is the name of your application. It can be called anything.
  • URIs: This is the full URL to the homepage of our app. Since we are still in development mode, we are going to fill in the full URL our development server is running on. In my case, it’s http://localhost:3000.
  • Authorization callback URL: Users will be redirected to this path after they have authenticated with Google: http://localhost:3000/api/auth/callback/google

When you are coding, a popup displaying your client ID and client secret will come up. Copy them and add to your env.local file:

GOOGLE_ID=<cilent id of your google auth app should go in here>
GOOGLE_SECRET=<cilent secret of your google auth app should go in here>

Next, navigate to pages/api/auth/[...nextauth].js and add the following to your array of providers:

   Providers.Google({
      clientId: process.env.GOOGLE_ID,
         clientSecret: process.env.GOOGLE_SECRET,
    }),

Your [...nextauth].js should now look like this:

import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
const options = {
    providers: [
        Providers.GitHub({
            clientId: process.env.GITHUB_ID,
            clientSecret: process.env.GITHUB_SECRET
        }),
        Providers.Google({
            clientId: process.env.GOOGLE_ID,
            clientSecret: process.env.GOOGLE_SECRET,
        }),
    ],
}
export default (req, res) => NextAuth(req, res, options)

To test out user login using Google account, quit your development server and run npm run dev.

Now, with our fingers crossed and our heads held high, we should be able to sign in to our app with our Google account:

Sign-in With Google Activated

Create Facebook OAuth app

To use the Facebook login for our app, we will need a Facebook developer account. Create an account and then register your app and fill in the form accordingly. When asked to select a platform for your app, choose Web.

Once that is done, this should appear on your screen:

Login Options

Click on Facebook Login and select Web. Add the following:

To get your app ID and app secret, navigate to Basic in Settings, copy them, and add them to your env.local file as follows:

FACEBOOK_ID=<app id of your facebook app should go in here>
FACEBOOK_SECRET=<app secret of your facebook app should go in here>

Don’t forget to add http://localhost:3000/ in the App Domains field.

Next, navigate to pages/api/auth/[...nextauth].js and add the following to your array of providers:

    Providers.Facebook({
            clientId: process.env.FACEBOOK_ID,
            clientSecret: process.env.FACEBOOK_SECRET
      })

Your [...nextauth].js should now look like this:

import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
const options = {
    providers: [
        Providers.GitHub({
            clientId: process.env.GITHUB_ID,
            clientSecret: process.env.GITHUB_SECRET
        }),
        Providers.Google({
            clientId: process.env.GOOGLE_ID,
            clientSecret: process.env.GOOGLE_SECRET,
        }),
        Providers.Facebook({
            clientId: process.env.FACEBOOK_ID,
            clientSecret: process.env.FACEBOOK_SECRET
        })
    ],
}
export default (req, res) => NextAuth(req, res, options)

Restart your development server and users should be able to log in to your Next.js app using their GitHub, Google, and Facebook accounts:

Sign-in With Facebook Activated

Conclusion

In this post, we have implemented user authentication in Next.js using NextAuth.js, which is a secured library to identify our users, get user profile information, and render them in our frontend.

We have covered most of the used cases, but there is a lot more you can do with NextAuth.js. You can add a database using JSON Web Token, secure pages, and more.

If you are hungry for more content, check out the tutorial page from NextAuth.js official docs.

Let me know in the comments section below what you thought of this tutorial. I am social on Twitter and GitHub. Thank you for reading and stay tuned.

LogRocket: Full visibility into production Next.js apps

Debugging Next applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web apps, recording literally everything that happens on your Next app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your Next.js apps — .

Ejiro Asiuwhu Frontend Engineer with rock-solid experience in building complex interactive applications with JavaScript, TypeScript Vue.js, NuxtJS, React, Next.js, and other tools in the JavaScript ecosystem. Decomposing complex problems into logic, data, and UI components are my forte, and despite JavaScript frameworks, I build products that scale well 🚀. I author meaningful technical content, regularly ✍🏽.

11 Replies to “How to use NextAuth.js for client-side authentication in Next.js”

  1. Great article! However, you called it ‘Nuxt-Auth.js’ and ‘Next-Auth.js’ a few times, it is ‘NextAuth.js’

    – core team member

  2. Really great article 😊 I really enjoyed reading it and it makes me want to switch to Next.js. I was wondering why you called this client-side rather than severless? Is the authentication not done server side by SSR? I really apologize if I’m wrong, I’m just trying to understand the authentication flow.

  3. website: next-auth.js
    Example code : next-auth-example
    npm package : next-auth

    But it is called NextAuth.js and not next-auth.js as one could guess from all your urls.

    Am I missing something here ?

Leave a Reply