Skip to main content
Post image
· 15 min read

NextAuth - Google And GitHub Authentications for Nextjs

Introduction

We know how exhausting and time-consuming it can be to set up authentication, which includes handling databases, cookies, JWT, sessions, etc., on your own. The goal of this article is for you to learn about an alternative and simple tool (NextAuth), which we will use to easily add Google and GitHub authentication to our application.

Steps we’ll cover:

Prerequisites

We will be building a simple landing page to demonstrate how you can simply add Google and GitHub authentication to your Next.js app, and to follow along, you need to have the following in place:

  • Node.js 12.22.0 or later
  • Google console account.
  • GitHub account.

What is NextAuth?

NextAuth.js is an easy-to-implement open source authentication library originally designed for Nextjs and serverless. With NextAuth, you don’t necessarily have to create and use any database or any backend of any kind for authentication because it takes care of all that. It allows your users to sign in with their favorite preexisting logins. You can add as many predefined providers provided by NextAuth to your applications.

Why use NextAuth.js?

  • It supports OAuth 1.0, 1.0A, 2.0, and OpenID Connect and is designed to work with any OAuth service.
  • Many popular sign-in services are already supported.
  • Email and passwordless authentication are supported.
  • Allows for stateless authentication with any backend (Active Directory, LDAP, etc.)
  • JSON Web Tokens and database sessions are both supported.
  • Designed for Serverless but runs anywhere (AWS Lambda, Docker, Heroku, and so on…).
  • An open-source solution that gives you control over your data *
  • MySQL, MariaDB, Postgres, SQL Server, MongoDB, and SQLite are all supported natively.
  • Excellent compatibility with popular hosting provider databases
  • It can be used without a database (for example, OAuth + JWT).
  • Secure by default

Project setup

To create a project, run:

yarn create next-app

The command above creates a new Next.js app using create-next-app, which sets up everything automatically for you. You will be prompted to enter your project name to complete the installation. We used the yarn package manager here, feel free to use npm if you have to.

Once the installation is completed, move into your folder directory and run the below command to start the project:

yarn dev

Now your app has started you need to install the NextAuth package which is essential for the authentications.

yarn add next-auth

Once this is done, you will have all the dependencies required to follow up with this tutorial set up and can proceed with s authentication in your next application.

If you are using TypeScript, NextAuth.js comes with its types definitions within the package. To learn more about TypeScript for next-auth, check out the TypeScript documentation

Create API Routes

To get started with adding NextAuth.js to your project, you first create a new folder named auth inside the pages/api directory. Inside this new folder, you will create a file called [...nextauth].js.

This will contains the dynamic route handler for NextAuth.js which will also contain all of your global NextAuth.js configurations.

Next, inside the `[...nextauth].js you've created, you will configure the global NextAuth configurations for Github and Google providers.

pages/api/auth/[...nextauth].js
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google";
import GithubProvider from "next-auth/providers/github"

export default NextAuth({
// Configure one or more authentication providers
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET
}),
GithubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
// ...add more providers here
],
})

Looking at the code snippet above, we started by importing NextAuth from the next-auth package we installed earlier, and since we will be adding only Google and Github auth in this tutorial, GoogleProvider and GithubProvider were also imported and passed in the providers array which stores all NextAuth providers.

Next, we will be looking into how we can obtain the clientId and clientSecret for each of the providers.

For GoogleProvider (Make sure you have a Google account):

Navigate to your Google console credentials tab.

Create a Google project

If you have created and selected a project before now, you will see a button at the top that says "CREATE CREDENTIALS" but if you haven't you need to create a project by clicking on the "CREATE PROJECT" action button like the one circled in the image above. You will be taken to a page where you will enter your project name and organization (optional).

When that is done, ensure you select the project you just created when notified.

Google select project

Once that is done, proceed to create credentials by clicking on the "CREATE CREDENTIALS" action button at the top, this will open a dropdown containing four items. Click on the item circled in the below image to create an OAuth client ID.

Google select auth provider

If you come across anything like:

To create an OAuth client ID, you must first configure your consent screen

Please, go ahead to configure the consent screen by providing some information on your app, and when that is done, proceed to continue creating the OAuth client ID by choosing the application type and filling up the rest of the fields.

Create an auth client

After entering the name of your OAuth 2.0 client. You will see a section that requests adding an "Authorised JavaScript origins", click on the "+ ADD URI" action button to add your app origin. Since we are working in the development environment, all we need to do is to copy/paste our app URL which is running on localhost.

Authorised origins

For the "Authorised redirect URIs", you must include your full domain and end in the callback path.

  • For production: https://{YOUR_DOMAIN}/api/auth/callback/google
  • For development: http://localhost:3000/api/auth/callback/google
Redirect URL

note

If you eventually push to production, you need to change the Authorised JavaScript Origin and Authorised redirect URIs to the production URIs.


Please verify the details provided and if they are all correct, click on "CREATE" to finally create your OAuth client ID.

Auth client verified

Congratulations! You've successfully created Google OAuth client ID and SECRET.

Where do you store it?

Next, you will create a .env.local file in the root level of your app folder and inside of it you will create GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET environment variables and assign the OAuth client values we just created for each.

You also need to include NEXTAUTH_URL (assign your app origin) and NEXTAUTH_SECRET environment variables in the .env.

When deploying to production, set the NEXTAUTH_URL environment variable to the canonical URL of your site.

Create a NEXTAUTH_SECRET environment variable for all environments.

Your .env.local file should be looking like this when you're done.

.env
GOOGLE_CLIENT_ID=YOUR_CLIENT_ID
GOOGLE_CLIENT_SECRET=YOUR_CLIENT_SECRET

NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=YOUR_SECRET

github support banner

For GithubProvider (you will need a GitHub account):

To create your GithubProvider ID and SECRET, navigate to your GitHub account developer settings and click on the OAuth Apps tab to register a new application.

Github register

Complete application registration by filling out the fields.

Github register enable

Once completed, click on the "Register application" action button to register your app. Remember to go back and change the URIs to your production URI once you push to production.

Github secrets

Congratulations! You've just created your Github OAuth Client ID and SECRET. You can generate a new client secret by clicking on the "Generate a new client secret" action button.

Recall you've already created a .env file for your environment variables, go ahead and assign the Client ID and Client secrets you just generated to the GITHUB_ID and GITHUB_SECRET variables.

.env
GOOGLE_CLIENT_ID=YOUR_CLIENT_ID
GOOGLE_CLIENT_SECRET=YOUR_CLIENT_SECRET

NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=YOUR_SECRET

GITHUB_ID=YOUR_ID
GITHUB_SECRET=YOUR_SECRET

This is the final look of our .env file.

Next, you will head into your [...nextauth].js file and add the secret, remember you've already added the environment variable as NEXTAUTH_SECRET.

pages/api/auth/[...nextauth].js
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google";
import GithubProvider from "next-auth/providers/github"

export default NextAuth({
// Configure one or more authentication providers
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET
}),
GithubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
// ...add more providers here
],
secret: process.env.NEXTAUTH_SECRET
})

Congratulations! You’ve added your complete API route. The next thing you are going to do is to configure the shared session state.

Configure Shared Session State

The useSession() React Hook in the NextAuth.js client is the easiest way to check if someone is signed in, and to be able to use this hook, first you’ll need to expose the session context, <SessionProvider />, at the top level of your application:

pages/_app.jsx
import { SessionProvider } from "next-auth/react"

export default function App({
Component,
pageProps: { session, ...pageProps },
}) {
return (
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
)
}

Instances of useSession will then have access to the session data and status. The <SessionProvider /> also takes care of keeping the session updated and synced between browser tabs and windows.

Update Page Components

Now update the pages/index.js file to create a blog application. To that, add the code snippet below to the page/index.js.

page/index.js
import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";

export default function Home() {
return (
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<h1 className={styles.title}>My Blog</h1>
<div className={styles.row}>
<div className={styles.blogCard}>
<Image
src="/Getting-Started-with-NextJS-Inside.jpeg"
alt="blog1"
width={300}
height={200}
/>
<div className={styles.blogCardContent}>
<h2>Nexjs for Beginers</h2>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit.
Quisquam, quidem.
</p>

<a href="/blog1">Read More</a>
</div>
</div>
<div className={styles.blogCard}>
<Image
src="/pasted image 0.png"
alt="blog1"
width={300}
height={200}
/>
<div className={styles.blogCardContent}>
<h2>Django Full Course</h2>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit.
Quisquam, quidem.
</p>

<a href="/blog1">Read More</a>
</div>
</div>
</div>
</main>
</div>
);
}

Then add the code snippets in the styles/Home.module.css file to style the application.

styles/Home.module.css
.blogCard {
margin: 1rem;
padding: 1.5rem;
text-align: left;
color: inherit;
text-decoration: none;
border: 1px solid #eaeaea;
border-radius: 10px;
transition: color 0.15s ease, border-color 0.15s ease;
max-width: 300px;
}
.blogCardContent {
margin-top: 1rem;
}

.login {
margin: 1rem;
padding: 1.5rem;
text-align: left;
color: inherit;
text-decoration: none;
border: 1px solid #eaeaea;
border-radius: 10px;
transition: color 0.15s ease, border-color 0.15s ease;
max-width: 300px;
}
.row {
display: flex;
flex-wrap: wrap;
width: 100%;
margin-right: -15px;
margin-left: -15px;
justify-content: center;
}
.header {
display: flex;
align-items: center;
}
.header button {
margin-left: 10rem;
padding: 4px;
height: 2rem;
background-color: #ad270c;
border: none;
}

So if you refresh the application, you should see the blog application as shown in the screenshot below.

Result view

Right now, everyone can have access to the application. Let's add a hook to restrict access to only authenticated users.

Add React Hook

To know if a user is authenticated, we'll use the useSession() hook. To get started, we need to import and update the pages/index.js with the code snippet below.

pages/index
import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";
import { useSession, signIn, signOut } from "next-auth/react";

export default function Home() {
const { data: session } = useSession();
return (
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
{!session ? (
<>
<p>Not signed in</p>
<br />
<button onClick={() => signIn()}>Sign in</button>
</>
) : (
<main className={styles.main}>
<div className={styles.header}>
<h4>Signed in as {session.user.name}</h4>
<button onClick={() => signOut()}>Sign out</button>
</div>
<h1 className={styles.title}>My Blog</h1>
<div className={styles.row}>
<div className={styles.blogCard}>
<Image
src="/Getting-Started-with-NextJS-Inside.jpeg"
alt="blog1"
width={300}
height={200}
/>
<div className={styles.blogCardContent}>
<h2>Nexjs for Beginers</h2>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit.
Quisquam, quidem.
</p>

<a href="/blog1">Read More</a>
</div>
</div>
<div className={styles.blogCard}>
<Image
src="/pasted image 0.png"
alt="blog1"
width={300}
height={200}
/>
<div className={styles.blogCardContent}>
<h2>Django Full Course</h2>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit.
Quisquam, quidem.
</p>

<a href="/blog1">Read More</a>
</div>
</div>
</div>
</main>
)}
</div>
);
}

Let's point out what we did in the above code. First, we NextAuth hooks, the useSession which helps us know if a user is authenticated, the signIn hook to load the sign-in buttons and the signOut hook to log a user out. Then we destructured the session object from the useSession hook. The session object provides us with the information of the logged-in user. Using conditional rendering, we check if a user is logged in and render the blogs else show the user a sign-in button.

Now, if you refresh the application, it will look like the screenshot below for non-authenticated users.

Not sign in

When the user clicks the sign-in button, they will be redirected to the sign-in button page as shown in the screenshot below.

Sign in box

Now when they click on any of the buttons, they will be redirected to the Google or Github page depending on which button they click. Once they are authenticated, the application will look like the screenshot below.

Sign in result

Protect API Routes

NextAuth also allows you to protect your API routes. You can use the unstable_getServerSession() method to do that. Let's update and protect the pages/api/hello.js API with the code snippet below.

pages/api/hello.js
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import { unstable_getServerSession } from "next-auth/next"
import { authOptions } from "../api/auth/[...nextauth]"

export default async function handler(req, res) {
const session = await unstable_getServerSession(req, res, authOptions)
if (session) {
const blogData = [
{
id: 1,
title: "Blog 1",
content: "Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quidem.",
image: "/images/blog1.jpg",
},
{
id: 2,
title: "Blog 2",
content: "Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quidem.",
image: "/images/blog2.jpg",
},
]
res.status(200).json(blogData)
} else {
res.status(401).json({ message: "Unauthorized" })
}
}

In the above code snippet, we imported the unstable_getServerSession method and the authOptions props. Then we created a session object from the unstable_getServerSession method passing in the req, res and authOptions as arguments. The session object will provide us with the details of the logged-in user. We check if a session exists and send the blog data to the client else send a 401 (Unauthorized) response.

Conclusion

Throughout this tutorial, we've implemented how to add Google and GitHub authentication to a Nextjs application using NextAuth. We started by knowing what NextAuth is and why you should use it. Then we built a blog application for the demonstration. Now that you have the knowledge you seek, how would you add authentication to your next Nextjs project? Perhaps you can learn more about NextAuth from the documentation.


discord banner

Build your React-based CRUD applications without constraints

Low-code React frameworks are great for gaining development speed but they often fall short of flexibility if you need extensive styling and customization for your project.

Check out refine, if you are interested in a headless framework you can use with any custom design or UI-Kit for 100% control over styling.

refine blog logo

refine is a React-based framework for building CRUD applications without constraints. It can speed up your development time up to 3X without compromising freedom on styling, customization and project workflow.

refine is headless by design and it connects 30+ backend services out-of-the-box including custom REST and GraphQL API’s.

Visit refine GitHub repository for more information, demos, tutorials and example projects.



Related Articles

Software Developer
A Guide for Next.js with TypeScript
· 8 min read
Frontend developer
Build a Progressive Web App (PWA) with Next.js
· 19 min read
Software Developer
Nextjs image optimization with examples
· 14 min read

From Same Author

Software Engineer
How to create a CRUD app with SvelteKit
· 11 min read