DEV Community

Cover image for Implementing user authorization in Next.js
Matt Angelosanto for LogRocket

Posted on • Originally published at blog.logrocket.com

Implementing user authorization in Next.js

Written by Kingsley Ubah✏️

The focus of this tutorial is on helping developers learn how to delegate the responsibilities of user authorization to some other service, such as GitHub or Google, rather than managing them in their application. We will cover:

Authentication vs. authorization in Next.js

Authentication is the act of validating that users are who they claim to be. Usernames and passwords are the most common authentication factors.

When authenticating a user, if the user enters the correct data, the server assumes the identity is valid and grants the user access to the server resource.

On the other hand, authorization in a security system is the process of giving the user permission to access a specific resource or function on the server. This term is often used interchangeably with access control or client privilege.

Usually, authentication precedes authorization; users should first prove their identities are genuine before the backend administrator grants them access to the requested resources.

Introducing our user authorization project in Next.js

OAuth2.0 is an industry-standard authorization protocol that enables internet users to share their account information with third-party websites and applications without having to give out their account credentials.

This guide uses the NextAuth.js library for user authorization (OAuth2.0) implementation in Next.js applications.

NextAuth.js is a full-fledged authentication and authorization solution for Next.js designed to work with any OAuth service. It has built-in support for many popular sign-in services, including Google and GitHub.

To follow this tutorial, you'll need Node.js 12.0 or later along with basic knowledge of React.

Create a Next.js app

Let's begin by creating a new Next.js project.

The following commands show how to create a new Next.js project using npm, Yarn, and pnpm respectively. Open up the terminal and run one of them:

npx create-next-app@latest
# or
yarn create next-app
# or
pnpm create next-app
Enter fullscreen mode Exit fullscreen mode

You'll be prompted by the CLI to provide a name for your new project. Type your preferred name into the command prompt, then click enter on your keyboard to complete the installation.

After installation is complete, run the following command to start the development server on your local machine:

npm run dev
# or 
yarn dev 
# or 
pnpm dev
Enter fullscreen mode Exit fullscreen mode

This should start your dev server at port 3000 by default. Fire up your web browser and navigate to http://localhost:3000\. You should see the Next.js starter page as is shown below. Next Js Starter Page Shown When Opened In Browser At Localhost 3000 With Welcome Message And Links To Documentation, Course, Examples, And Vercel Deployment

Next, you'll create a new OAuth app on GitHub to register your application with OAuth.

Create a GitHub OAuth app

We want users to sign in with their GitHub account and authorize our app to access certain information from their account.

To do this, we need to first create a new GitHub OAuth App. Click on “New OAuth app” and fill out the form accordingly with your website information. Here are some important things to note about the information requested by the form:

  • In the “Application name” field, type the name of your app (for example, “My App”)
  • In the “Homepage URL” field, type the full URL to your website's homepage
    • Since we're in development mode, it is: http://localhost:3000
  • In the “Authorization callback URL” field, type the callback URL of your app

The authorization callback URL is the URL you want GitHub to redirect to after the user has authorized your app. It should be your homepage URL plus /api/auth/callback.

In this case, the full URL should be http://localhost:3000/api/auth/callback.

The other fields are not really important; as such, they can be left blank.

After registering the GitHub app, you'll be moved to a page containing your OAuth Client ID. Click “Generate a new secret key” to generate a Client Secret key as well.

Preserve both keys for the next step.

Add API keys to environmental variables

Next.js comes with built-in support for environment variables. To use them in your project, create a file named .env.local in the root of your project directory:

touch .env
Enter fullscreen mode Exit fullscreen mode

Open .env.local and add the following:

GITHUB_ID=<your-client-id>
GITHUB_SECRET=<your-client-secret>
NEXTAUTH_URL=http://localhost:3000
Enter fullscreen mode Exit fullscreen mode

Replace the above templates with your actual values from GitHub.

Install NextAuth.js and configure the GitHub provider

Now that you've created an OAuth application on GitHub, it's time to set up the front-end application.

First, install NextAuth.js by running the following command:

npm install next-auth --save
Enter fullscreen mode Exit fullscreen mode

With the library installed, you must now create a file named [...nextauth].js in pages/api/auth. This file will contain all the providers that you want to use in your app. Each provider will be configured using the credentials in order for the app to successfully connect with our OAuth identity provider.

Since we registered with GitHub, we'll use just the GitHub provider. Add the following code in the newly created [...nextauth].js file:

import NextAuth from 'next-auth'
import GitHubProvider from "next-auth/providers/github";

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

export default (req, res) => NextAuth(req, res, options)
Enter fullscreen mode Exit fullscreen mode

First, we imported NextAuth and GitHubProvider. Then we configured GitHubProvider with our GITHUB_ID and GITHUB_SECRET environmental variables, retrieved from process.env.

The last line exports a function that returns the NextAuth and takes the options variable as a third parameter.

That's all we need to connect our app with GitHub!

To see this in effect, run your dev server with npm run dev. Using the REST API provided by next-auth, you can sign into the app with your GitHub account. Navigate to http://localhost:3000/api/auth/signin and you should see the below:

Button Prompt To Sign Into Web App With Github Account

Click on the button and you'll be led to the GitHub consent page telling you to authorize the app. If you do, you'll be signed in with GitHub. However, the app will not reflect that you're signed in because we have yet to get the user session data in the app. Let's tackle that next!

Access the user session with <SessionProvider>

When the user authorizes our app, you need to show the user that they are signed in by rendering the user details on the front end of our app. In order for any of this to work, we must first wrap our entire app with <SessionProvider>.

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

import { SessionProvider } from "next-auth/react"
import '../styles/globals.css'

function MyApp({ Component, pageProps }) {
  return (
    <SessionProvider session={pageProps.session}>
      <Component {...pageProps} />
    </SessionProvider>
  )
}

export default MyApp
Enter fullscreen mode Exit fullscreen mode

With this code, all the pages within the app will have access to the user session, and this session will be preserved during site navigation. The session will also be shared with the OAuth provider. That way, the app doesn't re-authenticate the user every time he or she visits the site.

Check the user login state with useSession()

The useSession() hook allows us to check the login state of the user and retrieve the user's session information. We'll use this hook along with signIn and signOut to implement a <Header> component that checks if the user is authenticated and renders either a "Sign in" or "Sign out" link.

Open the components/Header.js file and import useSession, signIn, and signOut from the NextAuth.js client library:

import { useSession, signIn, signOut } from 'next-auth/react'
Enter fullscreen mode Exit fullscreen mode

signIn and signOut will be used to log users in and out of our app. We need to create the handleSignin and handleSignout methods to trigger both functionalities:

const handleSignin = (e) => {
      e.preventDefault()
      signIn()
  }    
const handleSignout = (e) => {
      e.preventDefault()
      signOut()
    }
Enter fullscreen mode Exit fullscreen mode

Next, let's retrieve the user’s session data:

const { data: session } = useSession();
Enter fullscreen mode Exit fullscreen mode

Once the data is retrieved, it can then be displayed to users on the page or manipulated with JavaScript. Let’s use the returned details to conditionally render a sign-in and sign-out button.

Replace everything in the return statement in components/Header.js with the following 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>
Enter fullscreen mode Exit fullscreen mode

Your Header.js file should now look like this:

import { useSession, signIn, signOut } from 'next-auth/react'
import Link from 'next/link'

export default function Header() {  
    const handleSignin = (e) => {
        e.preventDefault()
        signIn()
    }

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

    const { data: session } = useSession();

    return (
      <div className='header'>
        <Link href='/'>
          <a className='logo'>AppLogo</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>

    )
  }
Enter fullscreen mode Exit fullscreen mode

Next, we'll retrieve the user information and display it to the user upon authorizing our app.

Retrieve and display user information

Inside our pages/index.js file, we need to display and conditionally render the user details based on their authentication status.

If the user is logged in, we will render their profile image, name, and photo using the data from our session state. The user will be authorized to view or interact with all app pages, as well as to log out.

If the user is not logged in, we will render a dummy user profile image and text instructing them to log in and authorize the app to access their GitHub profile information. The user will not be authorized to view or interact with any other part of the app.

To do this, replace your index.js file content with the following:

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

export default function Home() {
  const { data: session, status } = useSession()
  const loading = status === "loading"

  return (
    <div className={styles.container}>
      <Head>
        <title>Nextjs | Next-Auth</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <Header />
      <main className={styles.main}>        
        <div className={styles.user}>
           {loading && <div className={styles.title}>Loading...</div>}
           {
            session &&
              <>
                <h1 className={styles.title}>Welcome, {session.user.name ?? session.user.email}!</h1>
               <p style={{ marginBottom: '10px' }}> </p> <br />
               <img src={session.user.image} alt="" className={styles.avatar} />
              </>
            }
           {
            !session &&
              <>
               <p className={styles.title}>Please log in to continue</p>
               <img src="no-user.jpg" alt="" className={styles.avatar} />               
              </>
           }
         </div>
      </main>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Here's the page when I’m logged out: Web App Page Showing Dummy User Profile Image And Login Instruction Text When User Is Not Logged In

And here's the page when I'm logged in with my GitHub account: Web App Page Showing User Details When User Is Signed In With Github

Feel free to grab the complete source code on GitHub!

Get additional scope data

Note that the default scope for the GitHub OAuth Provider is read:users, which authorizes your application to read the user's profile data, such as name, email, and profile picture.

In order to get data from scopes other than the default ones, you'll need to define the scopes in your Provider's configuration object inside the pages/api/auth/[...nextauth].js directory.

For example, let's request permission to read the user's notifications in addition to their profile data by adding the authorization.params.scope property to GitHubProvider:

// imports

const options = {
    providers: [
        GitHubProvider({
            clientId: process.env.GITHUB_ID,
            clientSecret: process.env.GITHUB_SECRET,
            // add this:                     
            authorization: { params: { scope: 'notifications' } },
        }),
    ],
}

// export 
Enter fullscreen mode Exit fullscreen mode

Navigate to http://localhost:3000 on your browser and try signing in with the same GitHub account. You should get the following. User Prompt To Grant Additional Permissions Authorizing App To Read User Notifications With Information About What Access Is Granted And Buttons To Cancel Or Grant Authorization

See the full list of available GitHub OAuth scopes.

To learn more about NextAuth.js, including how to use callbacks, JWT tokens, events, and other advanced configuration options, feel free to read the NextAuth.js documentation.

Conclusion

Using the NextAuth.js library, you should now be able to configure a Next.js application to use the OAuth flow for user authorization. The NextAuth.js library provides built-in support for many popular sign-in services, making the process of API integration quick and easy.

You can get the source code from this GitHub repository. If you have any questions related to this topic, please let me know in the comments.

Top comments (0)