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
- Introducing our user authorization project in Next.js
- Create a Next.js app
- Create a GitHub OAuth app
- Add API keys to environmental variables
- Install NextAuth.js and configure the GitHub provider
- Access the user session with
<SessionProvider>
- Check the user login state with
useSession()
- Retrieve and display user information
- Get additional scope data
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
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
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, 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
- Since we're in development mode, it is:
- 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
Open .env.local
and add the following:
GITHUB_ID=<your-client-id>
GITHUB_SECRET=<your-client-secret>
NEXTAUTH_URL=http://localhost:3000
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
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)
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:
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
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'
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()
}
Next, let's retrieve the user’s session data:
const { data: session } = useSession();
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>
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>
)
}
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>
)
}
Here's the page when I’m logged out:
And here's the page when I'm logged in with my GitHub account:
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
Navigate to http://localhost:3000 on your browser and try signing in with the same GitHub account. You should get the following.
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)