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:
Next click on Create Credentials and select OAuth client id.
Then select Web Application, give it a random name or just leave the default name.
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
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
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;
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
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
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
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;
};
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 };
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');
});
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());
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';
Make sure to change the variables to the above for each passport and then run the following command to build:
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:
node dist/app.js
Now access the ngrok url with the path:
/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.
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