Next.js and Next-Auth V5: Guide to Social Logins(OAuth)
Using Next-Auth V5 for Google and GitHub OAUTH Login in a Next.js app: A complete guide
Authentication
and Authorization
are the implicit needs for any user-facing application. Using authentication users let the application and underlying services know who they are, and if they are the legitimate people to get access to the system. There are various ways of authenticating like credential-based authentication, OTP-based authentication, magic links, biometrics, and more.
While authentication is the way to tell someone who you are, authorization is the way to provide someone access to resources they are supposed to have. There are role-based, policy-based authorization models that ensure the right access to resources when users try accessing them after authentication.
You will find this article helpful if you are looking for a guide to learning about
Authentication and Authorization
.
In this step-by-step tutorial, we will focus on setting up authentication using OAuth providers like Google and Github with a Next.js
application. We will use Auth.js
or Next-Auth V5
, an open-source authentication tool for the web to get the auth set-up done.
Let's get started ๐
Note: It would be great if you code as you follow along the sections of this article. The source code used in this article is publicly available on GitHub for you to access and use. You can find the link to it at the bottom of this article.
Create a Next.js App Router Project
First, create a Next.js app using the command below from your terminal/command prompt.
npx create-next-app@latest
Make sure you have the latest Node.js installed.
The prompt will guide you to create a Next.js app with a name of your choice, a target tech stack (JavaScript or TypeScript), and a few more configurations. In my case, I went ahead with the following choices:
Please note, that I have selected JavaScript, TailwindCSS, and most importantly, the App Router
. After the project completion, change the directory to the project directory and start the local server using the following command:
yarn dev # Or its npm, pnpm, bun equivalent
Now, the local server will run on localhost:3000 by default.
Auth.js , aka Next-Auth(Version 5)
Auth.js is an open-source authentication library that integrates with modern JavaScript frameworks like Next.js, Svelte, and Express. Previously the project was available only for Next.js and thus it used to be called Next-Auth. Today, a portion of Auth.js is still supports Next-Auth
, but along with it, there are SvelteKitAuth
, and ExpressAuth
available too.
Installation
We will use Next-Auth Version 5 which is in its beta while writing this article. Open a terminal and install next-auth
with the following command:
yarn add next-auth@beta
# Or
# npm install next-auth@beta
# pnpm add next-auth@beta
# bun add next-auth@beta
Setting up environment
Create a file called .env.local
at the root of your project folder. We need to add a key called AUTH_SECRET
with a value. You can generate the secret by using the following command from your terminal or command prompt:
npx auth secret
You should see an output like below which prompts you to copy the key-value pair and paste it into the .env.local
file.
Alternatively, if you are on a Linux / Mac OS X system, you can use the following command to generate the auth secret:
openssl rand -base64 33
In whatever ways you generate the secret, please ensure to copy-paste and create a key-value pair in the .env.local file like this:
Configurations: The auth.js
file
Next, create a auth.js
file at the root of the project folder with the following code:
import NextAuth from "next-auth";
export const {
handlers: { GET, POST },
auth,
signIn,
signOut,
} = NextAuth({
providers: [
// WE WILL ADD THINGS HERE SHORTLY
],
});
Here we have created a minimalistic configuration of the Next-Auth to avail functionalities like signIn
, signOut
, along with an auth
object that can provide us with all information about the session and the logged-in user in the session. The GET
, and POST
handlers will be used in a route handler that we will learn about soon.
At this point, the only configuration we pass to the NextAuth
is an empty providers
array. However, do not worry much about it, as we will be filling it soon.
The callback
route
Now we will create a route handler specially for Next-Auth. This route handler will be used as a callback route from the OAuth providers when we configure them after a while.
Create a folder hierarchy called api/auth/[...nextauth]/
under the app/
folder. The [...nextauth]
directory creates a dynamic route. Now create a file called route.js
under this hierarchy as follows: /app/api/auth/[...nextauth]/route.js
.
Copy and paste the following code snippet inside the route.js file.
// Here the GET and POST is being imported
// from the auth.js file before we export
// them from here.
export { GET, POST } from "@/auth";
That's it. We are done with the installation, set-up, and basic configurations of Next-Auth. Let us now shift our focus to building the user interface(UI) needed for the authentication.
Create Login Form
Create a components
folder at the root of your project folder and create a file called LoginForm.jsx
under it with the following code:
import { doSocialLogin } from "@/app/actions";
const LoginForm = () => {
return (
<form action={doSocialLogin}>
<button
className="bg-pink-400 text-white p-1 rounded-md m-1 text-lg"
type="submit"
name="action"
value="google">
Sign In With Google
</button>
<button
className="bg-black text-white p-1 rounded-md m-1 text-lg"
type="submit"
name="action"
value="github">
Sign In With GitHub
</button>
</form>
);
};
export default LoginForm;
A few things to note here:
We have created a login form with two submit buttons to sign in with Google and GitHub respectively.
We have imported a server action called
doSicialLogin
and using it as the form action so that the function gets invoked when the user submits the form by clicking on either button. The server action function doesn't exist yet, we will create it soon.Each of the submit buttons has the same name attribute value called
action
. It is helpful to identify the button that triggers the form submission inside the server action.
The Home Page
Now, open the page.js
file under the app/
folder and replace its content with the following code:
import LoginForm from "@/components/LoginForm";
export default function Home() {
return (
<div className="flex flex-col justify-center items-center m-4">
<h1 className="text-3xl my-3">Hey, time to Sign In</h1>
<LoginForm />
</div>
);
}
It is a simple component that imports the LoginForm
we created above and used it in the JSX. If you try to access the app now, you will get an error due to the non-existence of the doSocialLogin
server action used in the login form. Let's fix that.
Next.js Server Actions: Log in and out
Server Action
in Next.js are built on React Actions
that you can define in server components and/or calls from client components. Server actions are JavaScript async
functions that run on the server by the user interactions with the client.
It helps to build a data mutation technique more often when you want to submit a form to create, update, or delete data on the server. It can also be useful to perform isolated server-side actions like sending emails, processing payments, user login, logout, and many more use cases.
Read this article to understand the usages and use cases of Server Actions in-depth.
Create a folder called actions/
under the app/
folder. Now, create a file called index.js
under the app/actions/
with the following code:
'use server'
import { signIn, signOut } from "@/auth";
export async function doSocialLogin(formData) {
const action = formData.get('action');
await signIn(action, { redirectTo: "/home" });
}
export async function doLogout() {
await signOut({ redirectTo: "/" });
}
Let us understand what is happening there.
We used a directive called
'use server'
at the top of the file to inform Next.js that this file contains server actions and they must be executed on the server side.Then, we have defined two server actions,
doSocialLogin()
anddoLogout()
.Earlier, the action
doSocialLogin()
we have imported into theLoginForm
component to invoke it when the login form is submitted. Hence it receives a formData object containing the information of the submitted form fields. In our case, the login form doesn't have any other fields than two submit buttons sharing the same name value,action
. Hence we retrieve the button value using theaction
name to see whether users have clicked on the Google or GitHub buttons to submit the form.Inside the
doSocialLogin()
function we call thesignIn()
from theauth.js
by passing a couple of arguments. The first argument is to tell theNext-Auth
about the provider to use to sign in. In our case, it will be eithergoogle
orgithub
. The second parameter is a configuration object informing auth.js about the redirection page after login. It says, redirect to the home page(/home route) once authenticated.The
doLogout()
action invokes thesignOut()
function from auth.js and redirect to the root route(/) on log out.
Now access the app, you should see it running and showing you the user interface like the image below. Clicking on either of the buttons will not do much as we haven't configured the providers yet, and the great news is, that we will be doing it next.
Social Login With Google Oauth
Let us make the sign-in with Google work first. This is a multi-step procedure. First, we need to create a client ID and client secret from Google Cloud Console. Once we have them, we need to configure the Google Provider in the auth.js
file,
Client ID and Secret from Google
Go to Google Cloud Console and follow these steps to generate a client ID and secret. You can also use an existing client ID and client secret.
Log in to the Google Cloud console and click on the
Credentials
option from the left menu. Then click on the+ CREATE CREDENTIALS
drop down from the top and select theOAuth client ID
option as shown in the image below.
In the next screen, select
Web application
as an application type, give a suitable name for the OAuth 2.0 client. I preferred to keep it the same as my project name. Then provide localhost:3000 as the authorized JavaScript origin URL. It will make sure that the client and secrets can not be used from elsewhere.Next, provide the URL
http://localhost:3000/api/auth/callback/google
as the value of the authorized redirect URI. Does this URI ring a bell ๐? Yes, this is the same route pattern we created earlier with theroute.js
.Finally, click on the
CREATE
button.Now you will see a modal dialog with the OAuth client ID and secret created. Make sure you copy them, and optionally you can download them in a JSON file to use later.
Click on
OK
to close the modal.
Set Up Environment
In the .env.local
file add two entries:
Key
GOOGLE_CLIENT_ID
, and the value will be the client ID we created above.Key
GOOGLE_CLIENT_SECRET
, and the value will be the client secret we created above.
Configure the Google Provider for Next-Auth
Open the auth.js
file and import GoogleProvider
as shown below. Also, add the GoogleProvider
configuration in the providers
array as mentioned in the code below.
Please note,
We are using the client ID and secret from the environment variables.
We also configured to provide a consent UI for our users to provide their consent to use their Google auth every time they authenticate.
import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";
export const {
handlers: { GET, POST },
auth,
signIn,
signOut,
} = NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code",
},
},
})
],
});
Test it out from the UI
Now, it's time to test out the Sign in with Google
flow. So, go to the app and click on the button to log in with Google. You will see a redirection to select an account to authenticate. If you have multiple Google accounts, please select the one you want to authenticate with.
The next step will be a consent screen where you have to click on the Continue
button to log in.
After this, you will be redirected to a route called /home
because that's how we have configured the signIn()
function above. You will see a 404-page not found error because we have not created the route yet. However, the best part is, that our authentication is successful.
To validate the cookie created for the session token, open up the browser dev tools and move to the Application
tab. In the left panel, expand the Cookies
options and click on the http://localhost:3000
. You should find the authjs.session-token
cookie with the token value at the bottom.
Show LoggedIn User's Details
It's time to fix the /home
route and show something other than a 404 error. How about showing the logged-in user's details like name and profile image? We can also show a logout option to sign out from the app when the user is already logged in.
Create a folder called home/
under the app/
folder, and create a page.js
file under the app/home/
with the following code:
import Image from "next/image";
import Logout from "@/components/Logout";
import { auth } from "@/auth";
import { redirect } from "next/navigation";
const HomePage = async () => {
const session = await auth();
if (!session?.user) redirect("/");
return (
<div className="flex flex-col items-center m-4">
<h1 className="text-3xl my-2">
Welcome, {session?.user?.name}
</h1>
<Image
src={session?.user?.image}
alt={session?.user?.name}
width={72}
height={72}
className="rounded-full"
/>
<Logout />
</div>
);
};
export default HomePage;
Here:
We have created a static route called
/home
.We imported the
Logout
component. We haven't created the Logout component yet, will do that next.Then we imported
auth
from the auth.js. Theauth
is an async function that returns us with the session information, including the logged-in user's details.We retrieved the session information and checked if the logged-in user information was available. If not, we redirected the user to the root route where we have the login form. So this way, we can protect a specific route at the page level.
In the JSX, we displayed the logged-in user's name and image and the Logout component. Let's create the Logout component.
Add Sign Out(Logout) Functionality
Create a file called Logout.jsx
under the components
folder with the following code:
import { doLogout } from "@/app/actions"
const Logout = () => {
return (
<form action={doLogout}>
<button
className="bg-blue-400 my-2 text-white p-1 rounded"
type="submit">
Logout
</button>
</form>
)
}
export default Logout
Explanation:
It is a simple React component with a form and a submit button.
With the click of a button, we submit the form and invoke the
doLogout()
server action we have created already!
That's it. Time for a final test. Perform the login with Google as before. Wait, do you get an error like this instead of seeing the logged-in user's details?
Don't worry. It is because we haven't informed Next.js about the source of the profile image coming from Google. Open the next.config.mjs
file and replace the content with the following configuration:
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'lh3.googleusercontent.com'
},
],
},
};
export default nextConfig;
In the code above, we have provided the trusted hostname as the image source. The hostname was mentioned in the error as a suggestion for us to configure.
Now refresh the UI. You should see the home page up and running with the logged-in user's name, image, and a Logout button. Clicking on the Logout button will log you out of the app and take you to the login form.
Now, You can also check the cookies like the last time. You will not find the session token cookie when you log out.
Wow! Finally, we are here after implementing the social login using Google by using Next-Auth/Auth.js.
Let's finish the configurations for GitHub as well.
Social Login With GitHub OAuth
We will be re-using a lot of things done so far. First, let us create the client ID and client secret for a GitHub OAuth app.
Client ID and Secret from GitHub
Log in to your GitHub account and go to the developer settings following this URL. Under the OAuth Apps
section, you will find your existing Oauth Apps, if any. Now, create a new OAuth app by clicking the button at the top-right corner of the page.
Next, you need to fill up a few details like we did for Google. Give a suitable application name, home page URL as localhost:3000, and the authorized callback URL. Please provide http://localhost:3000/api/auth/callback/github
as the value of the authorized callback URL. Then, register the application.
You will see a client ID generated. Please copy and keep it safe somewhere. Now, click on the Generate a new client secret
button to create a client secret.
A new client secret will be generated for you. Please copy and keep this one safe, too.
Set Up Environment
Create two new more environment variables GITHUB_CLIENT_ID
and GITHUB_CLIENT_SECRET
and assign the respective values we have created.
Configure GitHub Provider From Next-Auth
The last thing remaining is to configure the GitHub provider. Open the auth.js
file and import the GitHubProvider
as shown below. Then, add the GitHubProvider object in the providers
array.
import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import GitHubProvider from "next-auth/providers/github";
export const {
handlers: { GET, POST },
auth,
signIn,
signOut,
} = NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code",
},
},
}),
GitHubProvider({
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code",
},
},
})
],
});
That's it. Go back to UI and Sign in with GitHub. You should get a screen to Authorize the Oauth app. Click on the Authorize button.
Boom! ๐ฅ
The same error as before, but you know how to fix it.
Open the next.config.mjs
file and add another entry to the remotePatterns
array for GitHub images.
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'lh3.googleusercontent.com'
},
{
protocol: 'https',
hostname: 'avatars.githubusercontent.com'
},
],
},
};
export default nextConfig;
Now refresh the screen and you should see the logged-in user's name, image, and the Logout button.
Incredible! We have learned to set up and code both Google and GitHub Oauth login using Next-Auth/Auth.js with Next.js App Router. It feels amazing!
Source Code
All the source code you have written so far as you explored this article can be found in this repository(under the branch 02-integrate-github-provider).
If you like the work, do not forget to encourage me with a star โญ.
Further Learning
If you enjoyed this article and developing the app, you may also like to explore a few more related topics on Next.js and Auth.js. Here are the links:
Next.js Authentication With Next-Auth V5 Credential Provider
Next.js Authentication - Register User To MongoDB With Next-Auth V5
Also, this same tutorial is available as an interactive video tutorial.
Liked it? Please let me know with your comments and likes. โค๏ธ
Let's connect. I share knowledge on web development, content creation, Open Source, and careers on these platforms.