DEV Community

Cover image for How to implement Google Authentication with NextJS and Passport.
Ayomikun Sholademi
Ayomikun Sholademi

Posted on • Edited on

How to implement Google Authentication with NextJS and Passport.

Introduction

Recently I decided to use NextJS on a project and after so many iterations, I decided to use google authentication with passport. In this article, I would be giving a step by step guide on how to set up authentication in your NextJS application with passport google strategy.

Essentials

Before we get started on the main course, here are a few things you need to know and have set up.

  • You need to have basic knowledge of Javascript or Typescript as well as React (NextJS).
  • You need to understand the concept of http requests and responses.
  • You should have Node set up on your computer.
  • You must have set up your application on Google developers console... you can check 'Register Application' section here on how to go about it.

In this article, I would be using yarn as my package manager, you could go ahead to use npm if you prefer.


First you would need to set up a NextJS project on your computer, so you go to your terminal to run the following command

yarn create next-app --typescript
Enter fullscreen mode Exit fullscreen mode

You would be prompted to enter a name for the project, do so and press enter to proceed.
Once the set up is complete, you need to change directory to the newly setup project by running the next command

cd <your-project-name>
Enter fullscreen mode Exit fullscreen mode

Next up, you install all the dependencies you need to successfully complete your authentication implementation which include:

To install, run the following command in your terminal

yarn add next-connect passport passport-google-oauth20 @types/passport @types/passport-google-oauth20
Enter fullscreen mode Exit fullscreen mode

Next up, You need to add some credentials to your env file. Create a new file named .env and add the following values

GOOGLE_CLIENT_ID: <your app client id>
GOOGLE_CLIENT_SECRET: <your app client secret>
Enter fullscreen mode Exit fullscreen mode

After this, you can now go into writing the main code.

Now, we start coding!

In your root directory, create a new folder called lib. Inside the lib folder, create a new file named passport-google-auth.ts

In the passport-google-auth.ts file, you configure google strategy using passport using the following code.

// /lib/passport-google-auth.ts

import { Profile, Strategy as GoogleStrategy } from "passport-google-oauth20";
import passport from "passport";

// logic to save your user or check if user exists in your record to proceed.
const saveUser = (user: Profile) => {
  return new Promise((resolve, reject) => {
    resolve("Successful");
  });
};

passport.use(
  new GoogleStrategy(
    {
      clientID: process.env.GOOGLE_CLIENT_ID as string,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
      callbackURL: "/api/oauth2/redirect/google", // this is the endpoint you registered on google while creating your app. This endpoint would exist on your application for verifying the authentication
    },
    async (_accessToken, _refreshToken, profile, cb: any) => {
      try {
        await saveUser(profile);
        return cb(null, profile);
      } catch (e: any) {
        throw new Error(e);
      }
    }
  )
);


// passport.serializeUser stores user object passed in the cb method above in req.session.passport
passport.serializeUser((user, cb) => {
  process.nextTick(function () {
    return cb(null, user);
  });
});

// passport.deserializeUser stores the user object in req.user
passport.deserializeUser(function (
  user: any,
  cb: (arg0: null, arg1: any) => any
) {
  process.nextTick(function () {
    return cb(null, user);
  });
});

// for broader explanation of serializeUser and deserializeUser visit https://stackoverflow.com/questions/27637609/understanding-passport-serialize-deserialize

// An article that explains the concept of process.nextTick https://nodejs.dev/learn/understanding-process-nexttick

export default passport;

Enter fullscreen mode Exit fullscreen mode

Next up, you create a new file in /pages/api folder named login.ts.
Inside the login.ts file, you create a get request that uses the google strategy method you configured with passport in the last step by adding the following code:

// /pages/api/login.ts

import passport from "../../lib/passport-google-auth";
import nextConnect from "next-connect";

export default nextConnect()
  .use(passport.initialize())
  .get(
    passport.authenticate("google", {
      scope: ["profile", "email"],
    })
  );
Enter fullscreen mode Exit fullscreen mode

You will now create the callback url for verifying the authentication.
Go to api folder in pages, create a folder named oauth2. Inside the oauth2 folder, create a folder named redirect. Inside the redirect folder, create a new file named google.ts.

// /pages/api/oauth2/redirect/google.ts

import { NextApiRequest, NextApiResponse } from "next";
import nextConnect from "next-connect";
import passport from "../../../../lib/passport-google-auth";

export default nextConnect().get(
  passport.authenticate("google"),
  (req: NextApiRequest & { user: any }, res: NextApiResponse) => {
    // you can save the user session here. to get access to authenticated user through req.user
    res.redirect("/");
  }
);

Enter fullscreen mode Exit fullscreen mode

Now that you are done implementing the backend, you can now use the endpoints on the frontend.
Create a file named login in the pages folder and paste the following code for your login page.

// /pages/login.tsx

import Link from "next/link";

const LoginPage = () => {
  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        justifyContent: "center",
        alignItems: "center",
        height: "100%",
        width: "100%",
        textAlign: "center",
      }}
    >
      <h1 style={{ fontSize: "2.5rem" }}>Login with Google</h1>
      <Link href="/api/login" passHref>
        <button
          style={{
            border: "1px solid black",
            backgroundColor: "white",
            borderRadius: "10px",
            height: "50px",
            width: "200px",
            cursor: "pointer",
          }}
        >
          Proceed
        </button>
      </Link>
    </div>
  );
};

export default LoginPage;
Enter fullscreen mode Exit fullscreen mode

Voila, you can now authenticate your next app with google.

Conclusion

This article shows how you can leverage passport google strategy to authenticate your users in your next app.
You can access the code used in this tutorial here.

Disclaimer

This is my first technical article and I hope I did justice to the topic. Questions or feedback can be dropped in the comments. You can follow me on twitter and github

Top comments (6)

Collapse
 
ikeeptrying profile image
Dre

Small detail: Where does the LoginPage component go? It's not imported / used in any other component. Do you make a button first, and pop up the login? Do you need to know whether or not the person is logged in or not?

Collapse
 
ayo_tech profile image
Ayomikun Sholademi

Hi, I've updated the article to give a bit more direction on there the LoginPage goes.
For more context, Next handles the routes in this scenario using the files in the pages folder nextjs.org/docs/routing/introduction
Or If you want your login screen to be a pop up, then by all means, go for it.

If you check the /lib/passport-google-auth.ts file, the saveUser function is meant to help you store the user's authenticated state which you can use to handle authorisation in your app. I will write an article about Handling authentication in nextjs to show the way I go about it.

Collapse
 
gcphost profile image
William

Hey there, trying this and am getting
"Login sessions require session support. Did you forget to use express-session middleware?"

on the redirect, did I miss a step? Thanks!

Collapse
 
ayo_tech profile image
Ayomikun Sholademi

This article only highlights how you can authenticate a user using passports google library.
However you want to keep sessions of the user is up to you.
Thanks.

Collapse
 
feekunmi profile image
Tabitha🍭🌈

😍😍