Can't get Passport.js to work with Google OAuth 2.0

263 views Asked by At

I'm trying to add the ability to Login/Register with Google to my app. I tried using Passport to create that functionality, but I'm getting this error:

Error: Failed to serialize user into session.

I tried using express-session and cookie-session, but I'm still getting the same error.

This is my app.js:

const express = require('express');
const app = express();
const mongoose = require('mongoose');
const keys = require('./config/keys');
const expressSession = require('express-session');
const cookieParser = require('cookie-parser');
const passport = require('passport');

// Set Mongoose Promise Library To Default
mongoose.Promise = global.Promise;

// Connect To The Database
mongoose.connect(keys.mongodb.dbURI, {useMongoClient: true})
.catch(err => console.log(err));

// -------------------------//
// Middlewares              //
// -------------------------//
// Set View Engine To Pug
app.set('view engine', 'pug');

// Cookie Parser Middleware
app.use(cookieParser());

// Express-Session Config & Middleware
app.use(expressSession({
  secret: keys.session.cookieKey,
  resave: false,
  saveUninitialized: true,
  cookie: {
    maxAge: 60000 
  }
}));

// Passport Middlewares
app.use(passport.initialize());
app.use(passport.session());

// Serve Static Assets
app.use(express.static('public'));

// -------------------------//
// Routes                   //
// -------------------------//
app.get('/', (req, res) => {
  res.render('home');
});

const authRoutes = require('./routes/auth');
app.use('/auth', authRoutes);

// -------------------------//
// Initalize                //
// -------------------------//
const portNum = 5000;
app.listen(portNum, () => console.log(`Started On Port ${portNum}`));

And this is the Passport-setup (Strategy):

'use strict';
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const keys = require('./keys');
const User = require('../models/user');

passport.use(
  new GoogleStrategy({
    clientID: keys.google.clientID,
    clientSecret: keys.google.clientSecret,
    callbackURL: '/auth/google/redirect'
  }, (accessToken, refreshToken, userInfo, done) => {
    User.find({googleId: userInfo.id}).then(foundUser => {
      if (!foundUser) {
        new User({
          userName: userInfo.displayName,
          googleId: userInfo.id
        })
        .save().then(createdUser => done(null, createdUser))
        .catch(err => console.log(err));
      } else {
        done(null, foundUser);
      }
    })
    .catch(err => console.log(err));
  })
);

passport.serializeUser((user, done) => {
  done(null, user.id)
});

passport.deserializeUser((id, done) => {
  User.findById(id).then(foundUser => done(null, foundUser))
    .catch(err => console.log(err));
});

Thanks.

2

There are 2 answers

0
SasoN On BEST ANSWER

The issue was that I used User.find() instead of User.findOne(). User.find() returns an array with an object rather than the object itself.

0
Owen M On

You need to have an if statement in deserializeUser checking that a user with id actually exists. Otherwise you will be deserializing and thus serializing a user that does not exist. In deserializeUser, try adding a DB lookup for the user and then if that user does not exist, call done(null, false).