Skip to main content

Command Palette

Search for a command to run...

Signing In With Google Using NextAuth

A step-by-step guide to adding Google oAuth to a Next.Js project.

Published
7 min read
Signing In With Google Using NextAuth

NextAuth (or soon to be Auth.Js) is a free-to-use open source framework for authentication. Though NextAuth has a good site for documentation, there are times when some steps are missed out and it took me some time to figure it out. I write this article to help beginners setup NextAuth with Google authentication in their projects.

Pre-requisites

To follow this article well, one must have basic knowledge of NextJs. Typescript is used for the code. There is TailwindCSS for the styling, but you should be able to follow along.

Steps

Install NextJS

To get started, lets install NextJS. On your terminal go to the directory where you want to put your project and run the following command:

npx create-next-app@latest

Follow the prompts to set up your project. Choose the default settings highlighted in the prompts.

Go to the NextJs project folder and start the application.

npm run dev

Your NextJS application should now be running on http://localhost:3000.

Setup Google oAuth

I assume you already have a Google or Gmail account. If you don't please create one.

Once you have a Google account, go to the Cloud Platform Console.

On the left-top navigation bar, click on the dropdown Menu.

When the dialog appears click on "New Project"

Put any name for your project and proceed to click the "Create" button.

Select the newly created project in the projects dropdown.

On the projects Quick Access select APIs and Services

On the left sidebar, click on "Credentials".

On the top menu select "+ CREATE CREDENTIALS", when dropdown appears choose the "OAuth Client ID".

Proceed to Configure Consent Screen. Choose the "External" radio button and click the "Create" button.

You will now be in the "Edit app registration" page. The contents in the "Edit app registration" page are what is displayed when the user tries to sign on to Google from your application.

You will now be configuring the OAuth Consent screen. In the App Information, fill up only the mandatory fields for "App name", "User support email", "Email addresses". The other fields are not necessary for now since we are only making a test application. Click on the "Save and Continue" button.

There is no need to update for "Scopes" and "Test users" at this time, proceed to "Save and Continue". Click on the "Back to Dashboard" button. You have now finished configuring the consent screen.

Create OAuth Client ID

On the sidebar click on "Credentials".

On the top menu, click the "+ CREATE CREDENTIALS" and select "OAuth client ID" on the dropdown menu.

Choose "Web application" for the "Application type".

Set the name and javascript origins URI and authorized redirect URI as below.

Since we will run this app only in development mode, setting to localhost at this time is OK. When you deploy to production, you should be creating a separate OAuth client ID for production and use your deployed sites URI.

Click on "Save" button.

The "OAuth Client Created" dialog will appear. Please take note of the Client ID and Client secret. You will have to use this later on your NextJS project folder. Below I hid the Client ID and Client Secret for my own application.

Installing NextAuth

Go back to your NextJS folder and install NextAuth. On terminal type:

npm install next-auth

Configuring NextAuth for Google OAuth

Next we add an API route. Since we are using the src\app folder in NextJS, we will do it as below.

Create a route.ts file in \app\api\auth\[...nextauth]. This contains the dynamic route handler for NextAuth.js. This will also contain all of your global NextAuth.js configurations which is define in the options import.

import NextAuth from "next-auth";
import { options } from "./options";

const handler = NextAuth(options);

export { handler as GET, handler as POST };

Define the options by creating an option.ts file in the same location:

import type { NextAuthOptions } from "next-auth";

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

export const options: NextAuthOptions = {
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_ID as string,
      clientSecret: process.env.GOOGLE_SECRET as string,
    }),
  ],
};

The options file imports and configures a provider from NextAuth which is for Google at this time. Providers are services that allows you to signin from NextAuth.

The lines below configures the Google provider.

    GoogleProvider({
      clientId: process.env.GOOGLE_ID as string,
      clientSecret: process.env.GOOGLE_SECRET as string,
    }),

We need to use the client Id and client secret we obtained from creating the OAuth client in Google Cloud Platform. We need to define GOOGLE_ID and GOOGLE_SECRET in an .env file. We need to store it into a local env file to make it secure.

GOOGLE_ID="DISABLED4396-bi88l0h10sDISABLED1io5hmDISABLED.apps.googleusercontent.com"
GOOGLE_SECRET="GOCSPX-DISABLEDON3jeENe96PDISABLED"

Important: Please make sure to set your GOOGLE_ID and GOOGLE_SECRET from your OAuth Client created and don't use the one in the example.

Important: Make sure you add the .env extension to .gitignore so that you won't accidentally commit it to any public repository.

Sharing The Session Throughout the Application

To be able to get the session context we need to add the <SessionProvider /> to the top level of your application.

First we create a providers.tsx file in src\app.

"use client";

import { SessionProvider } from "next-auth/react";

type Props = {
  children?: React.ReactNode;
};

export const NextAuthProvider = ({ children }: Props) => {
  return <SessionProvider>{children}</SessionProvider>;
};

We declare a NextAuthProvider component that wraps the <SessionProvider />. The <SessionProvider /> component wraps the children components. By doing so, it ensures that any components nested inside NextAuthProvider will have access to authentication session data provided by next-auth.

To use the authentication session throughout the application, we wrapped the <body> tag in the layout.tsx file with the <NextAuthProvider /> component.

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

import { NextAuthProvider } from "./providers";

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <NextAuthProvider>
        <body className={inter.className}>{children}</body>
      </NextAuthProvider>
    </html>
  );
}

Frontend - useSession() Hook

Now its time to test if we have setup our NextAuth configuration correctly. Let's start with the frontend.

Let's create a LoginButton component. This will use the useSession() hook to check the session status. The signIn("google", { callbackUrl: "/" }) calls the signIn function with the Google provider function.

\src\app\Components\LoginButton.tsx

"use client";
import { useSession, signIn, signOut } from "next-auth/react";

export default function LoginButton() {
  const { data: session } = useSession();

  if (session) {
    return (
      <>
        Signed in as {session.user?.email} <br />
        <button
          onClick={() => signOut()}
          className="bg-gray-400 px-4 py-2 rounded-lg"
        >
          Sign out
        </button>
      </>
    );
  } else {
    return (
      <>
        <p>Not signed in.</p>
        <button
          onClick={() => signIn("google", { callbackUrl: "/" })}
          className="bg-gray-400 px-4 py-2 rounded-lg"
        >
          Sign in to Google
        </button>
      </>
    );
  }
}

Then we use the LoginButton component in our main page.tsx.

import LoginButton from "./Components/LoginButton";

export default function Home() {
  return (
    <main className="p-8">
      <LoginButton />
    </main>
  );
}

Expected output when not logged in is below:

If you press the "Sign in to Google" button you should proceed to the Google signin flow.

When you have signed in successfully it would show the message below:

Backend - getServerSession()

To check authentication session on the backend we use the getServerSession() function. To test lets create a Server component in src\app\restricted\page.tsx.

import { getServerSession } from "next-auth/next";
import { options } from "../api/auth/[...nextauth]/options";

export default async function Restricted() {
  const session = await getServerSession(options);

  if (session === null) {
    return (
      <div className="p-8">
        <p>You are not logged in.</p>
        <p>This page is restricted.</p>
      </div>
    );
  } else {
    return (
      <div className="p-8">
        <p>You are logged in as {session.user?.email}</p>
      </div>
    );
  }
}

Rerun the nextJs application and navigate to https://localhost/restricted.

It should display the page below:

Now, go back to the home page in https://localhost and sign in to Google. Once you have successfully signed in, navigate back to the https://localhost:3000/restricted path. You should now be able to see a message that you have signed in.

Wrap Up

I have just shown you how to install NextAuth, create an OAuth Client ID in Google, and use NextAuth to signIn with Google OAuth. We have also tackled how to check the session in both the frontend with useSession() and at the backend with getServerSession().

You can check the source code in this github repository: https://github.com/lemreyes/next-auth-demo