Using Fastify with Passport.js for Google OAuth

Prashant Kandathil
Four Nine Digital
Published in
3 min readMar 9, 2022

I was looking for an example of how to use Passport + Google Auth with Fastify and most examples I could find were for Express. So I decided to create my own example.

TLDR;

Setup Google OAuth Credentials in the Google console

Log into your Google Cloud Platform console. (You might need to create an account).

  1. In the left hand menu: APIs & Services > Credentials

2. On the next page find: Create Credentials > OAuth Client ID > Web application

3. Fill out the details:

4. Click Create

You should get client ID and secret that you need to copy and save.

Pull the code and setup environment

Pull the code from this repository https://github.com/pkandathil/fastify-passport-google

Follow the setup instructions in the README.md in the repository

Code explanation

Load all .env variables into process.env The .env file stores the Google client ID and secret you generated earlier.

require('dotenv').config()

Loads the secret key from the base folder and provide it for encrypting the session data that is stored in a cookie

server.register(fastifySecureSession, {
key: fs.readFileSync(path.join(__dirname, ‘secret-key’)),
cookie: {
path: ‘/’
}
})

The Google OAuth2 Strategy requires the following data

clientId: Data from Google Console
clientSecret: Data form Google Console
callbackURL: The application URL where Google will redirect with the OAuth token
function (accessToken, refreshToken, profile, cb): Verify function
fastifyPassport.use('google', new GoogleStrategy.OAuth2Strategy({
clientID: process.env['AUTH0_CLIENT_ID'],
clientSecret: process.env['AUTH0_CLIENT_SECRET'],
callbackURL: 'http://localhost:8080/api/auth/google/callback',
},
function (accessToken, refreshToken, profile, cb) {
return cb(null, profile)
}
))

The function (registerUserSerializer) receives the data from Google and gives you the chance to store the data you want in the session. Here you can:

  1. Store the whole object sent from Google in your session.
  2. Use the Google ID to look up the user from your DB and store that user info in the session
  3. Or just store the Google ID as a key to the user object in your DB. You will have to look up the user on each request
fastifyPassport.registerUserSerializer(
async (user, request) => {
const { id, displayName } = user
const userForSession = { id, displayName }
return userForSession
}
)

When a request is processed by Fastify, the function (registerUserDeserializer) is called. It is responsible for decrypting the session to retrieve the stored user information.

fastifyPassport.registerUserDeserializer(async (userFromSession, request) => {
return userFromSession
})

This is the home page URL:

server.get('/',
{
preValidation: (req, res, done) => {
if (!req.user) {
res.redirect('/login')
}
done()
}
},
async (req, res) => {
res.send(`Hello ${req.user.displayName}!`)
}
)

The preValidation hook checks if the user is logged in. If the user is not logged in, send them to the login page.

server.get(
'/login',
{
preValidation: fastifyPassport.authenticate('google', { scope: [ 'profile', 'email'] })
},

async () => {
console.log('GOOGLE API forward')
}
)

The login page forwards the user to the Google login screen. Google provides the requested profile and email and information upon successful authentication of the user.

Google will redirect to this URL after login with the users token to the callback URL.

server.get(
'/api/auth/google/callback',
{
preValidation: fastifyPassport.authenticate('google', { scope: [ 'profile', 'email']})
},
function (req, res) {
res.redirect('/');
}
)

After successful processing, the user is redirected to the home page. The homepage will now have access to req.user that will have the user’s profile details in it.

server.get('/',
{
preValidation: (req, res, done) => {
if (!req.user) {
res.redirect('/login')
}
done()
}
},
async (req, res) => {
res.send(`Hello ${req.user.displayName}!`)
}

)

Hopefully this was helpful.

--

--