Implementing Passport With Google OAuth2
Tags: node, typescript, tutorial, beginners
Published: 2024-03-03 09:09:08

## Introduction

Hello! 😎

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

---

## Requirements

- Code from the previous tutorial
- Ngrok (Or a global domain)
- Google Developer Console OAuth2 client ID and secret (https://console.cloud.google.com/)

---

## 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](https://i.ibb.co/Ttg21gy/credentials-create-0.png)

Next click on Create Credentials and select OAuth client id.

![Credentials Creation](https://i.ibb.co/YD0VRND/credentials-create.png)

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

![Web Application](https://i.ibb.co/Hdg3wmM/credentials-create-2.png)

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:

```bash
ngrok http 3000
```

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:

```bash
/auth/google/callback
```

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:

```sql
ALTER TABLE users
ADD COLUMN googleId VARCHAR(255);

ALTER TABLE users
ALTER COLUMN password DROP NOT NULL;
```

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:

```bash
\i sql/google.sql
```

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.

```bash
GOOGLE_CLIENT_ID=google-client-id
GOOGLE_CLIENT_SECRET=google-client-secret
```

Replace the above with your real id and secret. 

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

```bash
yarn add passport-google-oauth20
yarn add -D @types/passport-google-oauth20
```

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)

```typescript
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;
};
```

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:

```typescript
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 };
```

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:

```typescript
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'); 
});
```

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:

```typescript
app.use(googlePassport.initialize());
app.use(googlePassport.session());
```

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

```bash
export { passport as localPassport } from './passport';
export { passport as googlePassport } from './google';
```

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

```bash
yarn build
```

The build should pass, now we can actually test the application. 😀

---

## Running The Application

To run the application simply run the following command:

```bash
node dist/app.js
```

Now access the ngrok url with the path:

```bash
/auth/google
```

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”](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/ethand9999)

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