How to Add Google Sign-In to Your Node.js Application

How to Add Google Sign-In to Your Node.js Application

I have recently added Sign in with Google feature in my NodeJS app P_Blog 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

Go to the Firebase console, make sure you are signed in with your Google account
Click on “Add project” and give your project a descriptive name and follow the prompts to create the project
Navigate to the Authentication section in the sidebar and click on Sign-in method

Click on Add new provider, find Google in the list of provides and click on Enable

Go to your newly created project’s Project settings, from General tab find your “SDK setup and configuration”, and select “CDN”
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}}

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.

Leave a Reply

Your email address will not be published. Required fields are marked *