HomeBytesheetsUI TemplatesUI ToolsRoad MapsStack DiscussionByte Camp
March 02, 2024 By Admin

How to Setup Authentication Using next-auth.js in a Next.js Application in a Simple Steps

This guide demonstrates the straightforward approach of incorporating authentication into your Next.js app using the next-auth.js library. While the library provides numerous options (providers), this tutorial focuses on the implementation using Google Provider. You can follow the same approach for other providers as well

Introduction to next-auth

NextAuth.js is a flexible authentication library for Next.js applications that supports various authentication providers such as Google, Facebook, GitHub, etc. It simplifies the process of adding authentication to your Next.js application by providing a clean API and easy-to-use hooks.

Installation

First, make sure you have a Next.js application set up. If not, you can create one using the following command:

npx create-next-app my-next-auth-app

Navigate to your project directory:

cd my-next-auth-app

Install the next-auth.js library with the following command:

npm install next-auth

Create a NextAuth.js Configuration File:

Navigate to your api folder which is inside the pages folder and create an another folder with name auth inside the api folder. Now finally create a file with name [...nextauth].js inside the auth folder.

The filename and folder structure should be like pages/api/auth/[...nextauth].js

Now open the [...nextauth].js and insert the following code


import GoogleProvider from "next-auth/providers/google";

export const authOptions = {
    providers: [
  GoogleProvider({
    clientId: process.env.GOOGLE_CLIENT_ID,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET,
  })
]
}
In order to use Google Provider, we imported GoogleProvider from next-auth as illustrated above. Similarly you can import for other providers as well

Configure Environment Variables:

Make sure to set up environment variables for your Google OAuth credentials. You can do this by creating a .env.local file in the root of your project and adding your credentials or you can use next.config.js file to add your env variables like below

const nextConfig = {
  reactStrictMode: true,
  env: {
    GOOGLE_CLIENT_ID:"dummy.apps.googleusercontent.com",
    GOOGLE_CLIENT_SECRET: "dummy-dummy-dummy-dummy",
},
};

module.exports = nextConfig;

Getting Client Id and Client Secret

To use the Google Provider, first you need to get your clientId and clientSecret from google if you dont have one.

Assuming you already have a Google account, follow these easy steps:
  1. Visit Google Cloud Platform, and click the console button at the top right corner of the navbar.
  2. You'll be directed to your console dashboard. On the top left, right after the Google Cloud logo, click the dropdown menu to create a new project:
  3. Assign your project any name you prefer, and then click the "Create" button.
  4. You will return to your console dashboard, and the same dropdown menu should now display the project you recently created. If it doesn't, click on it and select the project.
  5. Now Scroll down to the "Quick Access" section and choose the "API & Services" card. This action will lead you to the "API & Services" page. In the sidebar of this page, select the "Credentials" option:
  6. You will be directed to the "Credentials" page. Here, click the "CONFIGURE CONSENT SCREEN" button:
  7. This will take you to the consent screen configuration page, where you will determine how you want to configure and register your app. Opt for the "External" option and proceed by clicking the "Create" button:

Setting OAuth2 Consent Screen

  • Beginning with the "OAuth Consent Screen" tab, you'll be prompted to modify your app information. The key sections to focus on are "App Information" and "Developer Contact Information." After filling these fields, click the "SAVE AND CONTINUE" button. You will then transition to the "Scopes" tab. Here, once again, click the "SAVE AND CONTINUE" button.
  • Next is Test Users Tab. Similalrly like before, proceed by clicking the "SAVE AND CONTINUE" button. And finally, you'll reach the last tab, the summary tab. Scroll down and select the "BACK TO DASHBOARD" button.

Now, Return to the "Credentials" page, and there, click the "Create Credentials" button. A dropdown menu will appear. Choose the "OAuth Client ID" option:

In this page, you'll see a single dropdown field for your application type, which will reveal additional fields based on your selection. Select the "Web Application" option from this dropdown:

Scroll down to the "Authorized redirect URI" section and paste the following URI: http://localhost:3000/api/auth/callback/google and hit the "CREATE" button.

Note:If you want to setup for a production app then this URL should be like 'your-app-url/api/auth/callback/google'
(i.e)https://www.bytes4dev.com/api/auth/callback/google

Now at last you will see a popup showing your unique client id and client secret. Keep in mind that both are confidential and don't make it publically visible in you application

Now assume that everything in order and we need to proceed to next steps. Now we need to generate secret key as well

Generate your secret key by executing the following command in your terminal:

openssl rand -base64 32

This command will generate a unique secret key, keep this as well private and put in your .env file or next.config.js file

const nextConfig = {
  reactStrictMode: true,
  env: {
    NEXTAUTH_SECRET:"put your generated secret key",
    GOOGLE_CLIENT_ID:"dummy.apps.googleusercontent.com",
    GOOGLE_CLIENT_SECRET: "dummy-dummy-dummy-dummy",
},
};

module.exports = nextConfig;

Now head back to the [...nextauth.js] file inside pages/api directory and add these new code


import GoogleProvider from "next-auth/providers/google";

export const authOptions = {
    providers: [
  GoogleProvider({
    clientId: process.env.GOOGLE_CLIENT_ID,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET,
  })
],
callbacks: {
    async signIn({ user}) {
      if (account.provider === "google") {
        const response = await fetch(your backend url + "/auth/signup",{
            method: "POST",
            headers: {
              "Content-Type": "application/json",
            },
            body: JSON.stringify({
              name: user.name,
              email: user.email,
              image: user.image,
            }),
          }
        );
        if(response.status===200) return true
        if (response.status === 500) {
            throw new Error("Internal server error");
          }
      }
    }
    },
}

Now lets breakdown the above code

AuthOptions Object

The authOptions object is an object that contains configuration options for authentication. In this object:

  • providers: It specifies the authentication providers that your application will support. In this case, it only includes the GoogleProvider.
  • callbacks: It specifies callback functions that are triggered during the authentication process. This part of the code is incomplete and needs further explanation, which I'll cover in the next point.

Callbacks Configuration

The signIn callback function is triggered when a user signs in. Within this function, it checks if the authentication provider used is Google. If it is, it sends a POST request to a backend endpoint for user signup. The user data (name, email, image) is sent in JSON format in the request body. If the signup is successful (response status is 200), it returns true.

This true return value indicates to NextAuth.js that the authentication is successful. So you should not return anyother return statement if authentication is success.

But if you want to handle incorrect authentication or account already exist based on the response from backend, You need to throw a new error inside this function. We will see this in action


//Previous code
callbacks: {
    async signIn({ user}) {
      //Previous code
        if(response.status===200) return true

        if (response.status === 500) throw new Error(JSON.stringify(
            {error: "Internal server error",  routeTo: "signIn",})
          );
        }
        if (response.status===401) throw new Error( JSON.stringify(
            {error: "User Exists",routeTo: "signIn"})
          );
      }
    }
    },
}

Lets Breakdown the above code

If there is an error from backend or account already exists you can handle the fallback to signup process by throwing the error like above code. Next auth will automatically handle the error fallback logic. But if you want to handle on your own you can create another file with name error.js in the same directory where the [...nextauth.js] file is placed

You can write any routing or fallback logic as per your own once you familiarized with next auth but for now put the below code to error.js file

export default function handler(req, res) {
  try {
    const parsedQuery = JSON.parse(req.query.error);
    res.redirect(`${'/auth/' + parsedQuery.routeTo}?error=${parsedQuery.error}`);
  } catch (error) {
    res.redirect(`/auth/signIn?error=${req.query.error}`);
  }
}

The above code will route to the signin page with the error in the url as a query params which is passed by the above code. Then you can retrieve the error code and show the error to user using your own functionality

Signin from React

import { signIn } from 'next-auth/react';

function SignInButton() {
  const handleSignIn = async () => {
    await signIn('google'); 
    // You can replace 'google' with the name of your desired authentication provider
  };

  return (
    <button onClick={handleSignIn}>Sign In with Google</button>
  );
}

export default SignInButton;

Ready For Production?

If you are going to push your code to production then make sure to change the callback url to your production url as mentioned earlier in the section: Setting OAuth2 Consent Screen

Also you need to add your production url with name NEXTAUTH_URL to .env or next.config.js file like below. next-auth will automatically pick this url in production environment

const nextConfig = {
  reactStrictMode: true,
  env: {
    NEXTAUTH_URL:"https://www.bytes4dev.com"
    NEXTAUTH_SECRET:"put your generated secret key",
    GOOGLE_CLIENT_ID:"dummy.apps.googleusercontent.com",
    GOOGLE_CLIENT_SECRET: "dummy-dummy-dummy-dummy",
},
};

module.exports = nextConfig;
Edit this page