DEV Community

Cover image for Implementing Passport With Google OAuth2
Ethan
Ethan

Posted on • Originally published at ethan-dev.com

Implementing Passport With Google OAuth2

Introduction

Hello! 😎

In this tutorial I will continue on with the previous tutorial and add authentication with Google OAuth2 with passport. ☺️


Requirements


Creating The OAuth2 Client Id And Secret

First if you don't already have a client id and secret head on over to the Google Developer Console (https://console.cloud.google.com)

Create a new project naming it anything you want (auth-test) for example and then in the search bar search for OAuth and then select credentials like so:

Create Credentials

Next click on Create Credentials and select OAuth client id.

Credentials Creation

Then select Web Application, give it a random name or just leave the default name.

Web Application

Next we need to configure the redirect URIs. I will show you how to do this using Ngrok but if you have your own domain feel free to use that.

If you haven't already install a tool called Ngrok, this tool is useful as it allows us to server local addresses as a global address. (Note since it allows access from outside always stop the command after use).

With ngrok installed just run the below command to get a global domain:

ngrok http 3000
Enter fullscreen mode Exit fullscreen mode

Now we can set the redirect URI, add the ngrok domain you got from the above command and add the following to the end of the URI:

/auth/google/callback
Enter fullscreen mode Exit fullscreen mode

Don't worry about the link just yet as we will support it later.

Once all needed fields are filled out click on Save.

You should be presented with the client id and secret. Make sure to make a note of them.
Now that thats done we can now add Google OAuth2 to our local passport application. πŸ™‚


Setting Up The Database

First what we need to do is alter the users database to allow Google. Since google does not use a passport we will need to allow null passwords, we also need to add a google id field to store the id.

Create a new file called "sql/google.sql" and populate it with the following:

ALTER TABLE users
ADD COLUMN googleId VARCHAR(255);

ALTER TABLE users
ALTER COLUMN password DROP NOT NULL;
Enter fullscreen mode Exit fullscreen mode

The above file adds a new googleId column and alters the password column to allow null passwords.

To execute the above sql log in to postgreSQL database and run the following command:

\i sql/google.sql
Enter fullscreen mode Exit fullscreen mode

This should modify the database. Now we can move on to the TypeScript code.


Adding Google Auth

First we will need to add the Google OAuth2 client id and secret to the .env file.

GOOGLE_CLIENT_ID=google-client-id
GOOGLE_CLIENT_SECRET=google-client-secret
Enter fullscreen mode Exit fullscreen mode

Replace the above with your real id and secret.

Next we will add the needed modules with the following command:

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

First we will edit the database code to allow searching and inserting users into the database when they are authed by google, open up "src/db/psql.ts" and add the following function. (Make sure to not forget exporting it)

const fetchOrCreateByGoogleId = async (googleId: string, email: string): Promise<any | Error> => {
    const res = await pool.query('SELECT * FROM users WHERE googleId = $1', [googleId]);

    if (res.rows.length) {
        return res.rows[0];
    }

    const newUser = await pool.query('INSERT INTO users (googleId, email) VALUES ($1, $2) RETURNING *', [googleId, email]);

    return newUser;
};
Enter fullscreen mode Exit fullscreen mode

The above returns the user if they are found, if not it creates a new user and returns the new user. Don't forget to export it from the index file as well.

Next we will create a new passport strategy for google. Create a new file called "src/routes/auth/passport/google.ts" and populate it with the following code:

import passport from 'passport';
import { Strategy as GoogleStrategy, Profile } from 'passport-google-oauth20';
import { fetchOrCreateByGoogleId, deserializeUserById } from './../../../db';
require('dotenv').config();

passport.use(new GoogleStrategy({
    clientID: (process.env.GOOGLE_CLIENT_ID as string),
    clientSecret: (process.env.GOOGLE_CLIENT_SECRET as string),
    callbackURL: '/auth/google/callback'
}, async (accessToken: string, refreshToken: string, profile: Profile, done: (error: any, user?: any) => void) => {
    try {
        const user = await fetchOrCreateByGoogleId(profile.id, profile.emails![0].value);

        return done(null, user);
    } catch (error) {
        console.error(error);

        return done(error);
    }
}));

passport.serializeUser((user: any, done) => {
    done(null, user.rows[0].id);
});

passport.deserializeUser(async (id: number, done) => {
    try {
        const user = await deserializeUserById(id);

        done(null, (user as Express.User));
    } catch (error) {
        done(error, null);
    }
});

export { passport };
Enter fullscreen mode Exit fullscreen mode

The above pretty much does the same as the local strategy but this time with google profile. (you may need to allow access to profile in the developer console)

Next we need to add new express routes to handle google auth. Open the file "src/routes/auth/auth.ts" and add the following two new routes:

router.get('/auth/google', googlePassport.authenticate('google', { scope: ['profile', 'email'] }));

router.get('/auth/google/callback', googlePassport.authenticate('google'), (req: Request, res: Response) => {
    res.send('Google auth login successful'); 
});
Enter fullscreen mode Exit fullscreen mode

One is for the authentication and one for when the authentication is successful.

Finally we need to initialize the google passport, open up "src/app.ts" and add the following:

app.use(googlePassport.initialize());
app.use(googlePassport.session());
Enter fullscreen mode Exit fullscreen mode

After that you will need to export both passports from some index files like so:

export { passport as localPassport } from './passport';
export { passport as googlePassport } from './google';
Enter fullscreen mode Exit fullscreen mode

Make sure to change the variables to the above for each passport and then run the following command to build:

yarn build
Enter fullscreen mode Exit fullscreen mode

The build should pass, now we can actually test the application. πŸ˜€


Running The Application

To run the application simply run the following command:

node dist/app.js
Enter fullscreen mode Exit fullscreen mode

Now access the ngrok url with the path:

/auth/google
Enter fullscreen mode Exit fullscreen mode

Login using your google account and the verification should pass!

Well done you have now added Google auth to the previous application! πŸ˜†


Conclusion

In this tutorial I have shown you how to add google OAuth2 to the previous application.
I wasn't sure about seperating the passport files but it allows me to copy the same file into another application.

I hope this tutorial has taught you something new.

As always you can find the source code for the above on my Github:
https://github.com/ethand91/passport-local-demo

Happy Coding! 😎


Like my work? I post about a variety of topics, if you would like to see more please like and follow me.
Also I love coffee.

β€œBuy Me A Coffee”

If you are looking to learn Algorithm Patterns to ace the coding interview I recommend the [following course](https://algolab.so/p/algorithms-and-data-structure-video-course?affcode=1413380_bzrepgch

Top comments (0)