How to Add Google Sign-In to Your Node.js Application
Published: 2024-04-03 12:09:33

I have recently added `Sign in with Google` feature in my NodeJS app [P_Blog](https://p-blog.online/) which allows users to quickly and easily login in using their existing Google account. `Sign in with Googgle` feature is very convenient as it is trusted and no need to create and memorize password. In this blog post, I would like explain how I implemented `Sign in with Google` feature in my nodejs app.
I have used Nodejs(Expressjs) and Express-handlebars in the app. The app already has traditional email/password login system. Now, let's get right into it.

### Setup a Firebase Project

1. Go to the [Firebase console](https://console.firebase.google.com/u/0/), make sure you are signed in with your Google account
2. Click on "Add project" and give your project a descriptive name and follow the prompts to create the project
3. Navigate to the `Authentication` section in the sidebar and click on `Sign-in method`
4. Click on `Add new provider`, find `Google` in the list of provides and click on `Enable`
5. Go to your newly created project's `Project settings`, from `General` tab find your "SDK setup and configuration", and select "CDN"
6. Copy whole `script`, we need to download the Service Account JSON file for backend but for that we will come latter

### Add `Continue with Google` button

We have set up the project, Now let's create a file `googleLogin.handlebars` in `partials` folder as we will use this button in `login` and `signup` pages. Following code will go in this file including copied project's SDK and configuration.

```
 <script type="module">
  // Import the functions you need from the SDKs you need
  import { initializeApp } from "https://www.gstatic.com/firebasejs/10.8.1/firebase-app.js";
  import {getAuth, GoogleAuthProvider, signOut, signInWithPopup} from "https://www.gstatic.com/firebasejs/10.8.1/firebase-auth.js";


  // TODO: Add SDKs for Firebase products that you want to use
  // https://firebase.google.com/docs/web/setup#available-libraries

  // Your web app's Firebase configuration
  // For Firebase JS SDK v7.20.0 and later, measurementId is optional
  const firebaseConfig = {
    apiKey: "",
    authDomain: "",
    projectId: "",
    storageBucket: "",
    messagingSenderId: "",
    appId: "",
    measurementId: ""

  };

  // Initialize Firebase
  const app = initializeApp(firebaseConfig);
const auth = getAuth(app)
</script>
```

I have used SVG google icon, here is html and css for that-

```

<style>
  .google-btn-container {
    background-color: rgb(66, 133, 244);
    color: rgb(255,
        255, 255);
    height: 50px;
    width: 240px;
    border: none;
    text-align: center;
    box-shadow: rgba(0, 0, 0, 0.25) 0px 2px 4px 0px;
    font-size: 16px;
    line-height:
      48px;
    display: block;
    border-radius: 1px;
    transition: background-color 0.218s ease 0s, border-color 0.218s ease 0s, box-shadow 0.218s ease 0s;
    font-family:
      Roboto, arial, sans-serif;
    cursor: pointer;
    user-select: none;
    margin: .5rem 0;
  }

  .google-icon {
    width: 48px;
    height: 48px;
    text-align: center;
    display:
      block;
    margin-top: 1px;
    margin-left: 1px;
    float: left;
    background-color:
      rgb(255, 255, 255);
    border-radius: 1px;
    white-space: nowrap;
    display: flex;
    align-items: center;
    justify-content: center;
  }
</style>


<div class="google-btn-container">
  <span class="google-icon">

    <svg
      width="32px"
      height="32px"
      viewBox="0 0 32 32"
      data-name="Layer 1"
      id="Layer_1"
      xmlns="http://www.w3.org/2000/svg"
      fill="#000000"
    ><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g
        id="SVGRepo_tracerCarrier"
        stroke-linecap="round"
        stroke-linejoin="round"
      ></g><g id="SVGRepo_iconCarrier"><path
          d="M23.75,16A7.7446,7.7446,0,0,1,8.7177,18.6259L4.2849,22.1721A13.244,13.244,0,0,0,29.25,16"
          fill="#00ac47"
        ></path><path
          d="M23.75,16a7.7387,7.7387,0,0,1-3.2516,6.2987l4.3824,3.5059A13.2042,13.2042,0,0,0,29.25,16"
          fill="#4285f4"
        ></path><path
          d="M8.25,16a7.698,7.698,0,0,1,.4677-2.6259L4.2849,9.8279a13.177,13.177,0,0,0,0,12.3442l4.4328-3.5462A7.698,7.698,0,0,1,8.25,16Z"
          fill="#ffba00"
        ></path><polygon
          fill="#2ab2db"
          points="8.718 13.374 8.718 13.374 8.718 13.374 8.718 13.374"
        ></polygon><path
          d="M16,8.25a7.699,7.699,0,0,1,4.558,1.4958l4.06-3.7893A13.2152,13.2152,0,0,0,4.2849,9.8279l4.4328,3.5462A7.756,7.756,0,0,1,16,8.25Z"
          fill="#ea4435"
        ></path><polygon
          fill="#2ab2db"
          points="8.718 18.626 8.718 18.626 8.718 18.626 8.718 18.626"
        ></polygon><path
          d="M29.25,15v1L27,19.5H16.5V14H28.25A1,1,0,0,1,29.25,15Z"
          fill="#4285f4"
        ></path></g></svg>
  </span>

  <span class="google-text">
    Continue with Google

  </span>

</div>
```
Now, we need to add this in both `Login` and `Signup` page.

```

 {{> googleLogin}}
 
```

![google-btn](https://images2.imgbox.com/6f/e4/bCRcfkcb_o.png)


### Send `userIdToken` to Backend
Once user click on `Continue with Google` button google displays a screen asking user to choose which account to use and outlining the permissions requested by the app. Upon user grants permission, Google provides a secure ID token which contains user information. We need to send this token to backend for verification. Once verified, we will navigate user to the home page.
Here is code for that,

```

const sendUserIdToken = async(userIdToken)=>{

  try{
   const res = await fetch("/googleLogin",{
    headers:{
"Content-Type":"application/json"
    },
    method:"POST",
    body: JSON.stringify({userIdToken})
  })
if(!res.ok){
  throw new Error("Error sending token")
}
const responseData = await res.json();
return responseData;

  }catch(er){
    console.log(er)
  }
}


const googleSignIn = async ()=>{

  try{
const proveder = new GoogleAuthProvider();
const result = await signInWithPopup(auth, proveder);
const userIdToken = await result.user.getIdToken();

if(userIdToken){
 const responseData = await sendUserIdToken(userIdToken);
 if(responseData?.success){
  window.location.href = "/"
 }
  }
  }catch(er){
    console.log(er)
  }


}


const googleBtn = document.querySelector(".google-btn-container");

googleBtn.addEventListener("click", googleSignIn);
```

In above code, we added click event in `googleBtn` which will initiate authentication with Google and obtain a user ID token upon successfull. `sendUserIdToken` sends token to the backend for verification and return response. If we have success response which we will setup in backend in a moment, user will redirect to homepage.

### Token verification in the Backend
First of all, we need to download `service-account-key.json` file from Firebase console. For that go to your `Project settings` and from `Service accounts` tab download `.json` file. We need `firebase-admin` package as well which enables access to Firebase services from nodejs environment. To install run `npm install --save firebase-admin` in your terminal.

I have created `googleLoginRoute` inside `routes` folder and following code goes in that file:

```
const firebase = require("firebase-admin");
const serviceAccount = require("../service-account-key.json");
firebase.initializeApp({
  credential: firebase.credential.cert(serviceAccount),
});

const Users = require("../module/user");
const setUserDataInSession = require("../utils/setUserDataInSession");


const googleLoginRoute = require("express").Router();

googleLoginRoute.post("/", async (req, res) => {
  const { userIdToken } = req.body;
if(!userIdToken || typeof userIdToken !== "string"){
   return  res.status(400).json({success:false, error:"Missing or Invalid token"})
}

  try {
    const {name, picture, email} = await firebase.auth().verifyIdToken(userIdToken);
    
    const foundUser = await Users.findOne({email});

    if(!foundUser){
        const newUserObj ={
            name,
            email,
            authMethod:"Google",
            password:null,
            profileURL: picture
        }
    const newUser =  await new Users(newUserObj).save();
setUserDataInSession(req, newUser);
    } 
   setUserDataInSession(req, foundUser);
    res.status(200).json({ success: true, error: null });
  } catch (er) {
    console.log(er);
    res.status(401).json({ success: false, error: "Invalid Token" });
  }
});

module.exports = googleLoginRoute;

```
In above code, first, we setup `firebase-admin`. We imported `Users` module to save user information in database. We imported `setUserDataInSession` function which will set user information in session once user is verified.

When we got `POST` request at `/googleLogin` endpoint, first we validate the request body whether the `userIdToken` is present or not. Then, it attempts to verify the Google ID token using Firebase Authentication. If the token is valid, we extract the user's `name`, `picture` and `email` from the decoded token as we need these to save it to our database, if user is logging in for the first time.
If no user is found in the database with provided email, we create a new user and save user to database and set user data in the session. Finally, we send a success response to the frontend.

We are all set, now we just need to required this in `app.js` file to handle `/googleLogin` route as following
```
const googleLoginRoute = require("./routes/googleLoginRoute");

app.use("/googleLogin", googleLoginRoute);
```

Thank you for reading! I hope this guide was helpfull in integrating Google Sign-In into your Node.js application.