How to Implement Google Sign-In and Sign-Up in Your Web Application

In today’s world, user authentication is a crucial part of web development. Integrating third-party authentication providers like Google has become the norm, it makes it super easy for users to create accounts without the hassle of remembering passwords, it also adds an extra layer of security. In this article, I'll walk you through how to implement Google Sign-In and Sign-Up using Google Console and Passport.js in a Node.js-based web application.

Prerequisites

Before we get into any kind of code, make sure you have the following:

  1. Node.js and Express installed.

  2. MongoDB for storing user information (you can use other databases, but I'll use MongoDB here).

  3. A basic understanding of JavaScript, Node.js, and OAuth.

  4. Google Developer Console credentials for OAuth.

Step 1: Set up Google Developer Console

To allow users to log in using their Google accounts, you first need to set up a project on Google Developer Console.

  1. Go to Google Developer Console: Visit Google Cloud Console.

  2. Create a new project: If you don’t have an existing project, create one.

  3. Enable OAuth 2.0: Under the APIs & Services section, select Credentials and click on "Create Credentials". Select OAuth 2.0 Client IDs.

  4. Configure consent screen: You’ll be prompted to set up the OAuth consent screen, where you'll provide basic app details such as app name, support email, etc.

  5. Set up OAuth Credentials: After configuring the consent screen, you'll create OAuth 2.0 credentials. Provide your Authorized Redirect URIs. This is typically a URL like https://your-app-url.com/api/auth/google/callback.

  6. Get the Client ID and Client Secret: After setting up the credentials, you will get a Client ID and Client Secret, which are required for the authentication process.

Step 2: Install Dependencies

You’ll need the following npm packages for the implementation:

  • passport: Middleware for authentication.

  • passport-google-oauth20: OAuth 2.0 authentication strategy for Google.

  • express-session: To handle user sessions.

  • dotenv: For environment variable management.

  • mongoose: For MongoDB connection.

npm install passport passport-google-oauth20 express-session dotenv mongoose

Step 3: Configure Environment Variables

Create a .env file in the root of your project to store sensitive information like your Google Client ID and Secret.

GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
REACT_APP_BASE_URL_SERVER=http://localhost:5000

This file should not be committed to version control. Add .env to your .gitignore.

Step 4: Set up Passport for Google Authentication

In your app’s auth middleware file, integrate Passport.js to handle Google OAuth 2.0.

1. Initialize Passport.js and the Google Strategy

const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const User = require('../models/User');

passport.use(new GoogleStrategy({
  clientID: process.env.GOOGLE_CLIENT_ID,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET,
  callbackURL: `${process.env.REACT_APP_BASE_URL_SERVER}/api/auth/google/callback`
}, async (accessToken, refreshToken, profile, done) => {
  try {
    // Find user by Google email
    let user = await User.findOne({ email: profile.emails[0].value });

    // If user doesn't exist, create a new one
    if (!user) {
      user = await User.create({
        googleId: profile.id,
        email: profile.emails[0].value,
        name: profile.displayName,
        isVerified: true
      });
    }

    // Return the user in the callback
    done(null, user);
  } catch (err) {
    done(err, false);
  }
}));

Here’s a breakdown:

  • The GoogleStrategy takes your Client ID, Client Secret, and the callback URL that Google will redirect users to after authentication.

  • The profile object contains user information from Google, including the user's email and display name.

  • If the user doesn’t exist in the database, they are created.

  • The done function is a callback that signifies the authentication is complete.

2. Serialize and Deserialize User

To manage user sessions, you must serialize and deserialize the user:

passport.serializeUser((user, done) => {
  done(null, user.id); // Store user ID in session
});

passport.deserializeUser(async (id, done) => {
  try {
    const user = await User.findById(id);
    done(null, user);  // Retrieve user details from the session
  } catch (err) {
    done(err, null);
  }
});

Step 5: Set up Routes for Authentication

Create routes for signing in with Google and handling the callback after authentication.

const express = require('express');
const passport = require('passport');
const router = express.Router();

// Route to initiate Google sign-in
router.get('/google', passport.authenticate('google', { scope: ['profile', 'email'] }));

// Google callback route
router.get('/google/callback', 
  passport.authenticate('google', { failureRedirect: '/login' }),
  (req, res) => {
    res.redirect('/dashboard');  // Redirect after successful login
  }
);

module.exports = router;

Step 6: Set up Express Session Middleware

You need to set up sessions so that users stay logged in across different requests.

const express = require('express');
const session = require('express-session');
const passport = require('passport');
const mongoose = require('mongoose');
const authRoutes = require('./routes/auth');
require('dotenv').config();

const app = express();

// MongoDB connection
mongoose.connect('mongodb://localhost:27017/your-db', { useNewUrlParser: true, useUnifiedTopology: true });

// Express session middleware
app.use(session({
  secret: 'your-secret',
  resave: false,
  saveUninitialized: true,
}));

// Passport middleware
app.use(passport.initialize());
app.use(passport.session());

// Routes
app.use('/api/auth', authRoutes);

// Server
app.listen(5000, () => {
  console.log('Server running on http://localhost:5000');
});

Step 7: User Model for MongoDB

Your user model should have fields to store Google user data, such as Google ID, name, email, and verification status.

const mongoose = require('mongoose');

const UserSchema = new mongoose.Schema({
  googleId: { type: String, required: true },
  email: { type: String, required: true, unique: true },
  name: { type: String, required: true },
  isVerified: { type: Boolean, default: false }
});

module.exports = mongoose.model('User', UserSchema);

Step 8: Testing the Implementation

Now that everything is set up, run the application:

node app.js

Navigate to http://localhost:5000/api/auth/google to trigger the Google OAuth flow. After signing in, you should be redirected to your dashboard or another success page of your choice.

Step 9: Deployment Considerations

When deploying your application:

  • Update the callback URL in Google Developer Console to match your live URL.

  • Ensure that environment variables like GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET are correctly set in your production environment.

Conclusion

Integrating Google Sign-In/Sign-Up into your web application can greatly improve user experience by reducing friction in the registration process. With Passport.js and Google OAuth, you can handle authentication securely and efficiently. I hope this guide helps you set up Google authentication in your Node.js app.

If you have any questions or need further clarification, feel free to leave a comment below or connect with me on LinkedIn.