GoogleStrategy is not saving the user.google #30

Closed
teddychan opened this Issue Dec 30, 2012 · 8 comments

Comments

Projects
None yet
8 participants

in the user model.

var UserSchema = new Schema({
    name: String
    , email: String
    , username: String
    , provider: String
    , hashed_password: String
    , salt: String
    , facebook: {}
    , twitter: {}
    , github: {}
})

the , google: {} is missing.

However, after added, it can't create the user record.

any hints?

Owner

madhums commented Dec 30, 2012

I am trying to fix it, looks like some kind of parsing issue...

Error: key $t must not start with '$'
    at Error (unknown source)
    at Function.checkKey (/Users/madhu/code/nodejs-express-mongoose-demo/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:1395:11)
    at serializeObject (/Users/madhu/code/nodejs-express-mongoose-demo/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:350:14)
    at packElement (/Users/madhu/code/nodejs-express-mongoose-demo/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:840:23)
    at serializeObject (/Users/madhu/code/nodejs-express-mongoose-demo/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:354:15)
    at packElement (/Users/madhu/code/nodejs-express-mongoose-demo/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:840:23)
    at serializeObject (/Users/madhu/code/nodejs-express-mongoose-demo/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:354:15)
    at packElement (/Users/madhu/code/nodejs-express-mongoose-demo/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:840:23)
    at serializeObject (/Users/madhu/code/nodejs-express-mongoose-demo/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:354:15)
    at Function.serializeWithBufferAndIndex (/Users/madhu/code/nodejs-express-mongoose-demo/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/bson.js:327:10)

the problem is the google json key has some key name start with "$" and monogo db don't support.

I have work around:

// use google strategy
  passport.use(new GoogleStrategy({
      consumerKey: config.google.clientID,
      consumerSecret: config.google.clientSecret,
      callbackURL: config.google.callbackURL
    },
    function(accessToken, refreshToken, profile, done) {
      User.findOne({ 'google.id': profile.id }, function (err, user) {
        if (!user) {
          // make a new google profile without key start with $
          var new_profile = {}
          new_profile.id = profile.id
          new_profile.displayName = profile.displayName
          new_profile.emails = profile.emails
          user = new User({
              name: profile.displayName
            , email: profile.emails[0].value
            , username: 'google'
            , provider: profile.username
            , google: new_profile._json
          })
          user.save(function (err) {
            if (err) console.log(err)
            return done(err, user)
          })
        } else {
          return done(err, user)
        }
      })
    }
  ));

My GoogleStrategy code is here,

passport.use(new GoogleStrategy({
            clientID:config.google.clientID,
            clientSecret:config.google.clientSecret,
            callbackURL:config.google.callbackURL,
            passReqToCallback:true
        },
        function (req, accessToken, refreshToken, profile, done) {
            process.nextTick(function () {
                User.findOne({ 'google.id':profile.id }, function (err, user) {
                    if (err) {
                        return done(err)
                    }
                    if (req.user !== undefined || user) {
                        if (req.user !== undefined)
                            user = req.user;
                        user = UserControl.extractProfile(user, profile, accessToken, refreshToken)
                    } else {
                        user = UserControl.extractProfile(new User(), profile, accessToken, refreshToken)
                    }
                    user.save(function (err, user) {
                        if (err) console.log(err)
                        return done(err, user)
                    })
                });
            });
        }
    ));

and UserControl.extractProfile is only get some extra data with using tokens

teddychan's workaround fixed it but needed a small edit:

, username: profile.username
, provider: 'google'

Another solution ist using OAuth2Strategy

GoogleStrategy = require('passport-google-oauth').OAuth2Strategy

Than you have to change:

consumerKey: GOOGLE_CLIENT_ID,
consumerSecret: GOOGLE_CLIENT_SECRET,
callbackURL: "http://127.0.0.1:3000/auth/google/callback"

to:

clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: "http://127.0.0.1:3000/auth/google/callback"

and it should work like a charm ;)

Edit:
Route should be something like this:

app.get('/auth/google', passport.authenticate('google', { scope: ['https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/userinfo.email'] }));
app.get('/auth/google/callback', passport.authenticate('google', { failureRedirect: '/login', successRedirect: '/' }));   

I was wandering how to switch to oauth2, I was commenting a line in the module index.js, this is prettier way. Thanks

In addition, you need to update config/passport.js's "passport.use(new GoogleStrategy" block to define clientID and clientSecret (replacing consumerKey and consumerSecret).

amirmog commented May 24, 2013

Thanks everyone for their solutions.

Both solutions work however, the Oauth2 maybe a better way to go since google recommends it.

Here is the OAuth2Strategy again exactly as it was mentioned above, but all in one place:

change the passport.use(new GoogleStrategy({ block in passport.js to:

// use google strategy
  passport.use(new GoogleStrategy({
      clientID: config.google.clientID,
      clientSecret: config.google.clientSecret,
      callbackURL: config.google.callbackURL
    },
    function(accessToken, refreshToken, profile, done) {
      User.findOne({ 'google.id': profile.id }, function (err, user) {
        if (!user) {
          // make a new google profile without key start with $
          var new_profile = {}
          new_profile.id = profile.id
          new_profile.displayName = profile.displayName
          new_profile.emails = profile.emails
          user = new User({
              name: profile.displayName
            , email: profile.emails[0].value
            , username: profile.username
            , provider: 'google'
            , google: new_profile._json
          })
          user.save(function (err) {
            if (err) console.log(err)
            return done(err, user)
          })
        } else {
          return done(err, user)
        }
      })
    }
  ));

change the routes for google in routes.js to:

  app.get('/auth/google', passport.authenticate('google', { scope: ['https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/userinfo.email'] }))
  app.get('/auth/google/callback', passport.authenticate('google', { failureRedirect: '/login', successRedirect: '/' }))

@madhums madhums closed this in a06d499 Jun 20, 2013

madhums added a commit that referenced this issue Jun 20, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment