# Next.js and Next-Auth V5: Guide to Social Logins(OAuth)

`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](https://blog.greenroots.info/what-is-authentication-and-authorization) 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.

```bash
npx create-next-app@latest
```

> Make sure you have the latest [Node.js](https://nodejs.org/en/download/package-manager) 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:

![Create a Next.js project](https://cdn.hashnode.com/res/hashnode/image/upload/v1718121548818/d89db3ac-5f28-41e5-a86f-3746972e26b4.png align="center")

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:

```bash
yarn dev # Or its npm, pnpm, bun equivalent
```

Now, the local server will run on http://localhost:3000 by default.

## Auth.js , aka Next-Auth(Version 5)

[Auth.js](https://authjs.dev/) 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:

```bash
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:

```bash
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.

![Auth Secret](https://cdn.hashnode.com/res/hashnode/image/upload/v1718123368199/e15908cd-314b-4eef-a3d0-629c3cfff935.png align="center")

Alternatively, if you are on a Linux / Mac OS X system, you can use the following command to generate the auth secret:

```bash
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:

![VS Code - Auth Secret](https://cdn.hashnode.com/res/hashnode/image/upload/v1718123559771/74c40c37-6e97-4fba-8d1a-9ceccac0fcfc.png align="center")

### Configurations: The `auth.js` file

Next, create a `auth.js` file at the root of the project folder with the following code:

```javascript
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](https://blog.greenroots.info/dynamic-routes-nextjs-app-router). 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.

```javascript
// 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:

```javascript
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:

```javascript

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](https://blog.greenroots.info/understanding-nextjs-server-actions-with-examples) 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:

```javascript

'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()` and `doLogout()`.
    
* Earlier, the action `doSocialLogin()` we have imported into the `LoginForm` 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 the `action` name to see whether users have clicked on the Google or GitHub buttons to submit the form.
    
* Inside the `doSocialLogin()` function we call the `signIn()` from the `auth.js` by passing a couple of arguments. The first argument is to tell the `Next-Auth` about the provider to use to sign in. In our case, it will be either `google` or `github`. 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 the `signOut()` 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.

![Login Form](https://cdn.hashnode.com/res/hashnode/image/upload/v1718160236423/18c0dbed-6186-4dce-894f-93c7f89ecd89.png align="center")

## 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](https://console.cloud.google.com/apis/credentials) 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 the `OAuth client ID` option as shown in the image below.
    
    ![GCP](https://cdn.hashnode.com/res/hashnode/image/upload/v1718166020933/c5977478-5b0b-4e9e-b608-2f0da76a1bd5.png align="center")
    

* 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 http://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`](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 the `route.js`.
    
* Finally, click on the `CREATE` button.
    
    ![Create OAuth Client ID and Secret](https://cdn.hashnode.com/res/hashnode/image/upload/v1718166344616/a99c0c2f-0609-41a2-a99e-3efe9147de7d.png align="center")
    
* 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.
    
    ![Auth Client Created](https://cdn.hashnode.com/res/hashnode/image/upload/v1718168497849/bb434e78-9f2e-4ed9-85ed-c33817d8f456.png align="center")
    

### 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.
    

![Google Client ID and Secret](https://cdn.hashnode.com/res/hashnode/image/upload/v1718169265899/0d0e7300-a1a0-4625-a538-83d99c98f2cb.png align="center")

### 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.
    

```javascript
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.

![Select an Account - Google](https://cdn.hashnode.com/res/hashnode/image/upload/v1718170870598/6d0bf405-f050-4790-82c1-6982f0dfa6de.png align="center")

The next step will be a consent screen where you have to click on the `Continue` button to log in.

![Consent Screen - Google](https://cdn.hashnode.com/res/hashnode/image/upload/v1718170932522/7f2264ef-1021-433c-8fb5-7feed48256b1.png align="center")

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.

![Home page 404](https://cdn.hashnode.com/res/hashnode/image/upload/v1718170981686/c9bf0fe7-65e1-43ce-8e9c-b409dd9097af.png align="center")

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.

![Google Auth Cookie](https://cdn.hashnode.com/res/hashnode/image/upload/v1718172444516/a54b557c-849b-4884-92b5-d15f51fadfa6.png align="center")

### 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:

```javascript
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. The `auth` 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:

```javascript

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?

![next-image-error](https://cdn.hashnode.com/res/hashnode/image/upload/v1718174719772/25d7db0f-0a62-4955-b6df-068224eb68c4.png align="center")

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:

```javascript
/** @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.

![Successful Home Page](https://cdn.hashnode.com/res/hashnode/image/upload/v1718175077669/7defc945-501d-4341-82df-f348ee85a120.png align="center")

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](https://github.com/settings/developers). 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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718175885004/1b811055-618c-41e9-b14e-77a77ac8b442.png align="center")

Next, you need to fill up a few details like we did for Google. Give a suitable application name, home page URL as http://localhost:3000, and the authorized callback URL. Please provide [`http://localhost:3000/api/auth/callback/github`](http://localhost:3000/api/auth/callback/github) as the value of the authorized callback URL. Then, register the application.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718176088098/9bde3787-6d20-4b38-b73a-0de6607310f6.png align="center")

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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718176318386/b25472e9-0165-4661-a5bf-06e50a2578e4.png align="center")

A new client secret will be generated for you. Please copy and keep this one safe, too.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718176331492/92194e17-6f55-414d-b8d3-372c1fc7d13b.png align="center")

### Set Up Environment

Create two new more environment variables `GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET` and assign the respective values we have created.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718176497013/4ff7a245-0732-434f-83da-0c089ae01055.png align="center")

### 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.

```javascript
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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718176584899/37114f3f-1edd-4754-ade1-496236b492e8.png align="center")

Boom! 💥

The same error as before, but you know how to fix it.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718176614195/a74fc2bc-3248-4553-a59b-13f891a93412.png align="center")

Open the `next.config.mjs` file and add another entry to the `remotePatterns` array for GitHub images.

```javascript
/** @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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718176724085/44f9a4dd-4f2c-4f81-9f3f-f6b00a37c895.png align="center")

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).

%[https://github.com/tapascript/learn-next-auth/tree/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**](https://www.youtube.com/watch?v=4m7u7zGbdTI)
    
* [**Next.js Authentication - Register User To MongoDB With Next-Auth V5**](https://www.youtube.com/watch?v=5kmZAqc2Jeg)
    
* [Next.js Middleware Crash Course & Protected Routes](https://www.youtube.com/watch?v=jHrjnZM26i4)
    

Also, this same tutorial is available as an [interactive video tutorial](https://www.youtube.com/watch?v=O8Ae6MC5bf4).

---

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.

* [**tapaScript on YouTube**](https://www.youtube.com/tapasadhikary?sub_confirmation=1)
    
* [**X(Twitter)**](https://twitter.com/tapasadhikary)
    
* [**LinkedIn**](https://www.linkedin.com/in/tapasadhikary/)
    
* [**GitHub**](https://github.com/atapas)
