Integrating NextAuth with Next.js 15: A Guide to Social Login
By: Bushra Islam - Updated: January 14, 2025
Registering and logging into a new application is somewhat boring. There are a lot of steps to register, and then you can log in to your account.
With OAuth logins ( also known as Social log-in) the user can use their existing logins to use your application.
0Auth comes with 80 providers you can also configure your 0Auth provider.
In today’s article, you will learn how to configure existing OAuth providers into your Next.js project.
You will learn how to set up GitHub, and Google. With these covered, you will learn how to configure any OAuth providers you want.
Let’s get started.
Prerequisites
To follow along you have to have the following:
- Knowledge of JavaScript
- Experience working with Next.js
Setup Next.js Project
To get started you need a Next.js project.
Open up your terminal and run this command to create a fresh Next.js project.
npx create-next-app@latest
Follow the instructions and choose the options you want to have.
I will go with the default configurations, if you want that, just hit Enter until the selection is done.
Once you are done, you will have a Next.js project ready to integrate OAuth providers.
CD into the project directory and run:
npm run dev
It will open up your project on localhost:3000
Install the Dependencies
We will use next-auth to authenticate & prisma to save the user data on our PostgreSQL database.
Here are the dependencies we need:
npm install next-auth prisma @next-auth/prisma-adapter
Configure NextAuth
Now, that we have all the required dependencies installed, Let’s configure next-auth.
Auth config
On the root of your project directory create libs/auth.ts and paste this code into it.
import { prisma } from "@/app/libs/prismaDB";
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { NextAuthOptions } from "next-auth";
export const authOptions: NextAuthOptions = {
session: {
strategy: "jwt",
},
adapter: PrismaAdapter(prisma),
secret: process.env.SECRET,
providers: [
// we will add the providers here
],
};
Here is the break-down of the config:
Session: Defines the session strategy, we have “JWT” session.
Adapter: The Database Adapter connects the database with next-auth. We are using Prisma to connect our database.
Secret: Used to encrypt the JWT token.
Providers: It will have all the providers we want to sign in with, for us GitHub & Google (We will integrate them in a bit)
Auth route
Now, create the auth API.
Go to the app directory and create the auth route api→auth→[…nextauth]→route.ts paste this code snippet:
import NextAuth from "next-auth";
import { authOptions } from "@/app/libs/auth";
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
Here we are initializing NextAuth with the authOptions config we created earlier.
Exporting it as GET and POST we will need both of these handlers.
NextAuth configuration is done.
Let’s configure Prisma with our Database.
Configure Database with Prisma
To save the user on the Database we need a Schema.
On the root of your project directory create a new directory named prisma and create schema.prisma file.
Now, paste this into that file.
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id String @id @default(cuid())
name String?
email String @unique
emailVerified DateTime?
password String?
image String?
accounts Account[]
sessions Session[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Account {
userId String
type String
provider String
providerAccountId String
refresh_token String?
access_token String?
expires_at Int?
token_type String?
scope String?
id_token String?
session_state String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@id([provider, providerAccountId])
}
model Session {
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model VerificationToken {
identifier String
token String
expires DateTime
@@id([identifier, token])
}
Here we got the Schema for the User, Account, Session, and VerificationToken table.
It defines the structure of the data we will store.
As you can see, the Database is connected through the DATABASE_URL. You have to get that URL and add it to the .env file.
DATABASE_URL="YOUR_DATABASE_URL"
There are a lot of PostgreSQL databases available, you can try them and use one for development purposes.
A few of the popular ones are:
Now, run this command to create the tables on your Database.
npx prisma migrate dev --name init
This will create a new database migration file for this migration.
Run this command every time you update your Schema to update the tables on the database.
Alternatively, you can run these commands to migrate the Schema, but these commands won’t create any migration file for you to see the changes.
npx prisma generate
npx prisma db push
Prisma config
On the libs directory create prismaDB.ts file and paste this code snippet.
import { PrismaClient } from "@prisma/client";
const globalForPrisma = global as unknown as { prisma: PrismaClient };
export const prisma =
globalForPrisma.prisma ||
new PrismaClient({
log: ["query"],
});
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
With this client config, you can perform any database operation you want.
All you have to do is import prisma from this config and run the queries like this:
import { prisma } from "@/app/libs/prismaDB";
// run inside `async` function
const newUser = await prisma.user.create({
data: {
name: 'test',
email: 'test-user@gmail.com',
},
})
We configured next-auth, and Prisma now let’s configure the OAuth provider.
We will start with GitHub.
GitHub OAuth Provider integration
To integrate GitHub authentication you have to go through multiple steps.
1. Generate the Secret Keys
2. Update the .env file
3. Add the GitHub Provider in the auth.config file
Let’s go through them one by one.
Get the Client ID and Client Secret
Create an OAuth App in your GitHub account to get the secret key for GitHub.
Follow the steps below to create the OAuth app and get the Secret Key and Client Key.
1. Go to Developer settings then go to OAuth Apps → New OAuth App
2. Now, fill out the form with the required information as shown below:
Note: Update the Callback URL for your live site, you can edit it later. The URL pattern will be this:
www.yoursite.com/api/auth/callback/github
Once you Register the app, you will see something like this 👇
Click the Generate a new client secret button to get the Secret key.
3. Copy the Client ID and Client Secret and save it somewhere.
Update the env file
Open your env file and create two variables for the Client ID and Client Secret.
And update these env variables with your keys.
GITHUB_CLIENT_SECRET=YOUR_CLIENT_SECRET
GITHUB_CLIENT_ID=YOUR_CLIENT_ID
Update the auth config
Open up the auth.ts file from the libs directory.
First, import the GitHub provider from the next-auth.
import GitHubProvider from "next-auth/providers/github";
Then, add the provider inside the providers array.
providers: [
GitHubProvider({
clientId: process.env.GITHUB_CLIENT_ID as string,
clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
}),
]
That’s it!
You configured GitHub authentication with the next-auth.
Now, it’s time to test it if it’s working properly. We will integrate Google OAuth then we will see the authentication in action.
Google OAuth Provider integration
Like GitHub, you need to generate the Keys, update the env file, and finally update the auth config to integrate Google Provider.
Get the Client ID and Client Secret
To generate the Client ID and Client Secret you have to create a project then you have to generate the keys.
Follow the steps below to Generate the Keys.
1. Go to Google Cloud Console then Click on the Credentials tab then Select a Project. If you don’t have a project click on the New Project button and create the project.
2. Once you select the project click on the CREATE CREDENTIALS button and click OAuth client ID it will open up a form.
3. Fill out the form as shown below:
For application type choose Web application.
Authorized origin is your live site URL
Authorized redirect URI is this:
www.yoursite.com/api/auth/callback/github
Note: add localhost for local testing.
Once you are done click on the CREATE button.
You will see a modal with all the keys like this:
Copy the Client ID and Client secret and save it somewhere.
Update the env file
Open the .env file and create two variables for Google Auth keys
GOOGLE_CLIENT_SECRET=YOUR_CLIENT_SECRET
GOOGLE_CLIENT_ID=YOUR_CLIENT_ID
Update auth config
Open up auth.ts file from the libs directory.
Import GoogleProvider from next-auth
import GoogleProvider from "next-auth/providers/google";
Now, update the Providers array with Google provider as shown below:
providers: [
// ...add more providers here
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
}),
],
Log in user with GitHub & Google
Now that we are done with all the integration.
Let’s log in and see if everything is working properly.
Login Page
For this example, I will put everything on the Home page.
So, copy this code and paste it into your page.tsx file inside the app directory.
"use client";
import Link from "next/link";
import { useSession } from "next-auth/react";
import { signOut, signIn } from "next-auth/react";
export default function Home() {
const { data: session } = useSession();
return (
<main className="flex flex-col items-center justify-between p-24">
{session?.user && (
<div>
<p className="text-3xl">Welcome, {session.user.name}</p>
<div className="mb-5">{JSON.stringify(session?.user, null, 2)}</div>
<button
onClick={() => signOut()}
className="bg-black hover:bg-gray-700 text-white font-bold py-2 px-4 rounded"
>
Logout
</button>
</div>
)}
{!session?.user && (
<>
<h1 className="text-3xl font-bold mb-5 text-center">
Login with any of these providers
</h1>
<div className="mb-5 flex flex-col gap-3 w-1/6">
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
onClick={() => signIn("github", { callbackUrl: "/" })}
>
Github
</button>
<button
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
onClick={() => signIn("google", { callbackUrl: "/" })}
>
Google
</button>
<button
className="bg-black hover:bg-gray-700 text-white font-bold py-2 px-4 rounded"
onClick={() => signIn("discord", { callbackUrl: "/" })}
>
Discord
</button>
</div>
</>
)}
</main>
);
}
Here, we are getting the logged-in user session from useSession hook. Then check if the user exists or not.
If the user exists render the Log Out button and user data. Otherwise, render the SignIn buttons.
To use the useSession hook configure the Session provider in the Layout.tsx file.
Configure Session Provider
Inside the app directory create providers → index.tsx and paste this code into it.
"use client";
import { SessionProvider } from "next-auth/react";
const Proveiders = ({ children }: { children: React.ReactNode }) => {
return (
<>
<SessionProvider>{children}</SessionProvider>
</>
);
};
export default Proveiders;
Here we import SessionProvider from next-auth and wrap children with it.
Now, update the layout file with this code:
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import Link from "next/link";
import Proveiders from "./providers";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={inter.className}>
<Proveiders>{children}</Proveiders>
</body>
</html>
);
}
GitHub Login
All the configuration and integration are done, now we have to sign in and see if everything is working.
To sign in click on the GitHub button, and you will be redirected to Authorize the sign-in. Click on the Authorize button, it will sign in and redirect you to the home page.
After sign-in, you will be redirected to the dashboard page and see the login info there.
Google Login
Google login is similar to GitHub login.
Click on the Google Login, you will be redirected to this page:
Choose the email you want to sign in with.
Once you choose the email you will be redirected to the sign-in page.
Click on the Continue button to sign in.
OAuthAccountNotLinked error
You will get an OAuthAccountNotLinked error if you try to log in with a different provider that has the same email connected to it.
To fix this issue you can add allowDangerousEmailAccountLinking: true to the auth provider.
Google({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
allowDangerousEmailAccountLinking: true,
}),
GitHub({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
allowDangerousEmailAccountLinking: true,
}),
As the name suggests, linking accounts is dangerous if you don’t trust the providers.
Read more about DangerousEmailAccountLinking:
Conclusion
In this tutorial, you learned to integrate OAuth into your project. OAuth makes it easier for users to log in and use the product.
In the next part, you will learn how to integrate Credentials authentications and user registration into your Next.js project.
Stay tuned!