Script Valley
JWT & Session Auth: Deep Dive
OAuth 2.0 and Third-Party AuthLesson 4.2

implementing Google sign-in with Passport.js

passport-google-oauth20 setup, GoogleStrategy configuration, serializeUser, deserializeUser, OAuth callback route, profile data extraction

Google Sign-In with Passport.js

Passport.js OAuth Flow

Passport.js abstracts OAuth flows into configurable strategies. The Google strategy handles the OAuth handshake โ€” you write the user lookup/creation logic.

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

passport.use(new GoogleStrategy({
  clientID: process.env.GOOGLE_CLIENT_ID,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET,
  callbackURL: '/auth/google/callback'
}, async (accessToken, refreshToken, profile, done) => {
  // Find or create user in your database
  let user = await User.findOne({ googleId: profile.id });
  if (!user) {
    user = await User.create({
      googleId: profile.id,
      email: profile.emails[0].value,
      name: profile.displayName
    });
  }
  return done(null, user);
}));

passport.serializeUser((user, done) => done(null, user.id));
passport.deserializeUser(async (id, done) => {
  const user = await User.findById(id);
  done(null, user);
});

// Routes
app.get('/auth/google', passport.authenticate('google', { scope: ['email', 'profile'] }));
app.get('/auth/google/callback',
  passport.authenticate('google', { failureRedirect: '/login' }),
  (req, res) => res.redirect('/dashboard')
);

serializeUser saves the user ID to the session. deserializeUser rehydrates the full user object from the ID on each request. Keep serialize lean โ€” store only the ID, never the full user object.

Up next

what OpenID Connect adds on top of OAuth 2.0

Sign in to track progress

implementing Google sign-in with Passport.js โ€” OAuth 2.0 and Third-Party Auth โ€” JWT & Session Auth: Deep Dive โ€” Script Valley โ€” Script Valley