jaredhanson / passport-facebook

Facebook authentication strategy for Passport and Node.js.
https://www.passportjs.org/packages/passport-facebook/?utm_source=github&utm_medium=referral&utm_campaign=passport-facebook&utm_content=about
MIT License
1.29k stars 447 forks source link

TypeError: Cannot read property 'id' of undefined /config/passport.js:18:23 #244

Open SpaceG opened 6 years ago

SpaceG commented 6 years ago

Hello Everybody,

I'm working on a sailsjs app, and i'm stuck here a little bit, with the property ID which is undefined, in my passport.js file.

like here a part of my passport.js file:

      passport.serializeUser(function(user, cb) {
        cb(null, user.id);
      });
      passport.deserializeUser(function(id, cb){
        User.findOne({id}, function(err, user) {
          cb(err, users);
        });
      });

this is allready my passport.js file :


const passport = require('passport'),
      LocalStrategy = require('passport-local').Strategy,

      GitHubStrategy = require('passport-github2').Strategy,
      TwitterStrategy = require('passport-twitter').Strategy,
      FacebookStrategy = require('passport-facebook').Strategy,

      shortid = require('shortid');
      generatePassword = require('password-generator');

      bcrypt = require('bcrypt');

      passport.serializeUser(function(user, cb) {
        cb(null, user.id);
      });
      passport.deserializeUser(function(id, cb){
        User.findOne({id}, function(err, user) {
          cb(err, users);
        });
      });

passport.use(new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password'
  },
  function(email, password, done) {

    User.findOne({ email: email }, function (err, user) {
      if (err) { return done(err); }
      if (!user) {
        return done(null, false, { message: 'Incorrect email.' });
      }

      bcrypt.compare(password, user.password, function (err, res) {
          if (!res)
            return done(null, false, {
              message: 'Invalid Password'
            });
          var returnUser = {
            username: user.username,
            createdAt: user.createdAt,
            id: user.id
          };
          return done(null, returnUser, {
            message: 'Logged In Successfully'
          });
        });
    });
  }
));

passport.use(new FacebookStrategy({
  clientID: '169553873736123',
  clientSecret: '3dfef9e57f803b5879700a27d9ff81c3',
  callbackURL: "http://localhost:1337/auth/facebook/callback"
},
function(token, tokenSecret, profile, done) {

  User.findById({ uid: profile.id, provider: profile.provider }, function(err, user) {

    if (user) {
      return done(null, user);
    } else {

      var data = {
        provider: profile.provider,
        uid: profile.id,
        username: profile.username
      };

      var shortid = require('shortid'),
          generatePassword = require('password-generator');

      //Let's generate a fake email and a fake password to match the User model attributes    
      var fakeEmail = 'fake_' + new Date().getTime() + '_' + shortid.generate() + '@fake.com';
          data.email = fakeEmail;

      var password = generatePassword(12, false); 
          data.password = password;         

          User.create(data, function(err, user) {
            return done(err, user);
      });
    }
  });
}
));

this is my terminal details which give me the error output :

 info: Starting app...

 info: ·• Auto-migrating...  (alter)
 info:    Hold tight, this could take a moment.
 info:  ✓ Auto-migration complete.

 info: 
 info:                .-..-.
 info: 
 info:    Sails              <|    .-..-.
 info:    v1.0.1              |\
 info:                       /|.\
 info:                      / || \
 info:                    ,'  |'  \
 info:                 .-'.-==|/_--'
 info:                 `--'-------' 
 info:    __---___--___---___--___---___--___
 info:  ____---___--___---___--___---___--___-__
 info: 
 info: Server lifted in `/Users/jh/Desktop/new/oauthy Kopie`
 info: To shut down Sails, press <CTRL> + C at any time.
 info: Read more at https://sailsjs.com/support.

debug: -------------------------------------------------------
debug: :: Wed May 30 2018 18:09:26 GMT+0200 (CEST)

debug: Environment : development
debug: Port        : 1337
debug: -------------------------------------------------------
TypeError: Cannot read property 'id' of undefined
    at /Users/jh/Desktop/new/oauthy Kopie/config/passport.js:18:23
    at pass (/Users/jh/Desktop/new/oauthy Kopie/node_modules/passport/lib/authenticator.js:294:9)
    at Authenticator.serializeUser (/Users/jh/Desktop/new/oauthy Kopie/node_modules/passport/lib/authenticator.js:299:5)
    at SessionManager.logIn (/Users/jh/Desktop/new/oauthy Kopie/node_modules/passport/lib/sessionmanager.js:14:8)
    at IncomingMessage.req.login.req.logIn (/Users/jh/Desktop/new/oauthy Kopie/node_modules/passport/lib/http/request.js:50:33)
    at /Users/jh/Desktop/new/oauthy Kopie/api/controllers/AuthController.js:94:9
    at Strategy.strategy.error (/Users/jh/Desktop/new/oauthy Kopie/node_modules/passport/lib/middleware/authenticate.js:353:18)
    at /Users/jh/Desktop/new/oauthy Kopie/node_modules/passport-oauth2/lib/strategy.js:197:27
    at /Users/jh/Desktop/new/oauthy Kopie/node_modules/passport-facebook/lib/strategy.js:181:5
    at passBackControl (/Users/jh/Desktop/new/oauthy Kopie/node_modules/oauth/lib/oauth2.js:134:9)
    at IncomingMessage.<anonymous> (/Users/jh/Desktop/new/oauthy Kopie/node_modules/oauth/lib/oauth2.js:157:7)
    at emitNone (events.js:111:20)
    at IncomingMessage.emit (events.js:208:7)
    at endReadableNT (_stream_readable.js:1064:12)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickDomainCallback (internal/process/next_tick.js:218:9)

this is my AuthController.js file

// oAuth beginning here 

facebook: function(req, res){

  passport.authenticate('facebook')(req,res);

},

facebookCallback: function(req, res){

   passport.authenticate('facebook', { failureRedirect: '/login' }, function(err, user) {
    req.logIn(user, function(err) {

      if (err) {
        console.log(err);
      res.view('500',  /*{layout: 'layouts/layout.ejs'}*/);
        return;
      }

      res.redirect('/');
      return;
    });
  })(req, res);

},

};

and this is my User.js file for the MongoDB etc.

/**
 * User.js
 *
 * @description :: A model definition.  Represents a database table/collection/etc.
 * @docs        :: https://sailsjs.com/docs/concepts/models-and-orm/models
 */
const bcrypt = require('bcrypt-nodejs');

module.exports = {

  datastores: 'mongodb',

  attributes: {
      email: {
        type: 'string',
        isEmail: true,
      },
    username: {
      type: 'string',
      required: true,
      unique: true
    },
    password: {
      type: 'string',
      required: true
    },
    state: {
      type: 'string',
      isIn: ['pending', 'approved', 'denied'],
      defaultsTo: 'pending'
    },
    provider: {
      type: 'string',
      isIn: ['local', 'github', 'twitter', 'facebook'],
      defaultsTo: 'local'
    },
    uid: {
      type: 'string'
    },
    // One-to-Many -> Add a reference to Posts 

    },
  customToJSON: function() {
     return _.omit(this, ['password'])
  },
  beforeCreate: function(user, cb){
    bcrypt.genSalt(10, function(err, salt){
      bcrypt.hash(user.password, salt, null, function(err, hash){
        if(err) return cb(err);
        user.password = hash;
        return cb();
      });
    });
  }
};

this is my url : which give a 500 error on sails.js -

http://localhost:1337/auth/facebook/callback?code=AQAsLIz2zQd2LiGvcYSOFmDhBlj4iqu4bq5aFVn3srYGDVsi5lBNMecn_XZYUg7FXatvAg-LMD_elb1CvX5QjkLOseer6_DNh93tnu2becGAOwIGmgZ98IYlHUqE-uzdfFvvXhOGaoAPzoZaK7S-fko-ci-GQJQ4fxoipFov6uM2nVdIwjrRW8T1jAu_F3LHD-MOpLztMwv_OKtJzezVNDTFL13OIVvI7_v0UEaOxjejRZfyinyQCFUtLvzOuGyqMeAkDEi1zP-nfmVP8txYPWyFYpX4CGsmWi-h9HRA_4ExCDw5SxhQX0bVgqFwb_DDhFSRZZ7hKMYgRcvt0BxcRUJo#_=_

would be great when some can give me a tip or fixes!

mbrand1 commented 6 years ago

What exactly is at and around line 18 of your passport.js file? You've pasted a lot but really can't tell without line numbers.

It's not 'id' that's null, but something else that it's the property of...like user.id or profile.id (the user variable is null or profile is null). Maybe your create is failing or you aren't returning 'user' somewhere...

SpaceG commented 6 years ago

@mbrand1

Ha okey, yes, in my passport.js file


const passport = require('passport'),
      LocalStrategy = require('passport-local').Strategy,

      GitHubStrategy = require('passport-github2').Strategy,
      TwitterStrategy = require('passport-twitter').Strategy,
      FacebookStrategy = require('passport-facebook').Strategy,

      shortid = require('shortid');
      generatePassword = require('password-generator');

      bcrypt = require('bcrypt');

      passport.serializeUser(function(user, cb) {
        cb(null, user.id);
      });
      passport.deserializeUser(function(id, cb){
        User.findOne({id}, function(err, user) {
          cb(err, users);
        });
      });

passport.use(new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password'
  },
  function(email, password, done) {

    User.findOne({ email: email }, function (err, user) {
      if (err) { return done(err); }
      if (!user) {
        return done(null, false, { message: 'Incorrect email.' });
      }

      bcrypt.compare(password, user.password, function (err, res) {
          if (!res)
            return done(null, false, {
              message: 'Invalid Password'
            });
          var returnUser = {
            username: user.username,
            createdAt: user.createdAt,
            id: user.id
          };
          return done(null, returnUser, {
            message: 'Logged In Successfully'
          });
        });
    });
  }
));

passport.use(new FacebookStrategy({
  clientID: '169553873736123',
  clientSecret: '3dfef9e57f803b5879700a27d9ff81c3',
  callbackURL: "http://localhost:1337/auth/facebook/callback"
},
function(token, tokenSecret, profile, done) {

  User.findById({ uid: profile.id, provider: profile.provider }, function(err, user) {

    if (user) {
      return done(null, user);
    } else {

      var data = {
        provider: profile.provider,
        uid: profile.id,
        username: profile.username
      };

      var shortid = require('shortid'),
          generatePassword = require('password-generator');

      //Let's generate a fake email and a fake password to match the User model attributes    
      var fakeEmail = 'fake_' + new Date().getTime() + '_' + shortid.generate() + '@fake.com';
          data.email = fakeEmail;

      var password = generatePassword(12, false); 
          data.password = password;         

          User.create(data, function(err, user) {
            return done(err, user);
      });
    }
  });
}
));

this is the full part:

      passport.serializeUser(function(user, cb) {
        cb(null, user.id);
      });
      passport.deserializeUser(function(id, cb){
        User.findOne({id}, function(err, user) {
          cb(err, users);
        });
      });

this part is nr: 18

cb(null, user.id);

to nr: 25

is that full code below:

      cb(null, user.id);
      });
      passport.deserializeUser(function(id, cb){
        User.findOne({id}, function(err, user) {
          cb(err, users);
        });
      });

hope, yes, i know about the Id: but i can't set it the rihg way. becuase i dont know which ID exact. peace L

mbrand1 commented 6 years ago

I would look at this User.create() method and see if it's returning a 'user'...assuming you're getting that far down in the method. Your FacebookStrategy is where you need to look for the undefined user.

SpaceG commented 6 years ago

@mbrand1 need i have to replace something? i dont understand it.

SpaceG commented 6 years ago
      cb(null, user.id);
      });
      passport.deserializeUser(function(id, cb){
        User.create({id}, function(err, user) {
          cb(err, users);
        });
      });

???

does not. work @mbrand1

mbrand1 commented 6 years ago

No sorry, I didn't mean move anything. You already have User.create() that is supposed to create a user if one isn't found. It takes your 'data' and tries to create a user. Then return it. Right after your generatePassword() step. I would output that with console.log(user) or something like that to see what's there. I would also output the error (err) to see if an error is getting generated.

SpaceG commented 6 years ago

@mbrand1

SpaceG commented 6 years ago

@mbrand1 nothing give out in that console. nothing output. peace

mbrand1 commented 6 years ago

Seriously? Your 'user' variable is false. I'm trying to direct you where that could be. But I'm not going to waste my time anymore after that response. Good luck to you.

SpaceG commented 6 years ago

@mbrand1 user variable, which user variable, there are more that one. !- I'm not getting clever. -

SpaceG commented 6 years ago

@mbrand1 there is more that one!

User.findOneById

or

User.findOne

or

User.create

or

User.findOrCreate

or

SpaceG commented 6 years ago

@mbrand1

this is my passportjs now. ! not look! this sucks! pardon my 8 hours for this... and so on.

const passport = require('passport'),
      LocalStrategy = require('passport-local').Strategy,

      GitHubStrategy = require('passport-github2').Strategy,
      TwitterStrategy = require('passport-twitter').Strategy,
      FacebookStrategy = require('passport-facebook').Strategy,

      shortid = require('shortid');
      generatePassword = require('password-generator');

      bcrypt = require('bcrypt');

      /*
      passport.serializeUser(function(user, done) {
        done(null, user);
      });

      passport.deserializeUser(function(user, done) {
        done(null, user);
      });
*/

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

    passport.deserializeUser(function(id, done) {
        User.findOneById(id).done(function (err, user) {
            done(err, user);
        });
    });

passport.use(new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password'
  },
  function(email, password, done) {

    User.findOne({ email: email }, function (err, user) {
      if (err) { return done(err); }
      if (!user) {
        return done(null, false, { message: 'Incorrect email.' });
      }

      bcrypt.compare(password, user.password, function (err, res) {
          if (!res)
            return done(null, false, {
              message: 'Invalid Password'
            });
          var returnUser = {
            username: user.username,
            createdAt: user.createdAt,
            id: user.id
          };
          return done(null, returnUser, {
            message: 'Logged In Successfully'
          });
        });
    });
  }
));

passport.use(new FacebookStrategy({
  clientID: '169553873736123',
  clientSecret: '3dfef9e57f803b5879700a27d9ff81c3',
  callbackURL: "http://localhost:1337/auth/facebook/callback"
},
function(token, tokenSecret, profile, done) {

  User.findOne({ uid: profile.id, provider: profile.provider }, function(err, user) {

    if (user) {
      return done(null, user);
    } else {

      var data = {
        provider: profile.provider,
        uid: profile.id,
        username: profile.username
      };

      var shortid = require('shortid'),
          generatePassword = require('password-generator');

      //Let's generate a fake email and a fake password to match the User model attributes    
      var fakeEmail = 'fake_' + new Date().getTime() + '_' + shortid.generate() + '@fake.com';
          data.email = fakeEmail;

      var password = generatePassword(12, false); 
          data.password = password;         

          User.find(data, function(err, user) {
            if (err) { return done(err); }
            return done(null, user, {
              message: 'Logged In Successfully'
            });
      });
    }
  });
}
));
mbrand1 commented 6 years ago

Why not simply add a fake 'id' property to your data var like provider, uid, and username? Just to see if it works. Since you are just testing with fake data?

var data = { id: 12345, <-------------------------------------
provider: profile.provider, uid: profile.id, username: profile.username };

mbrand1 commented 6 years ago

Understand that the serialize and deserialize are used for sessions. If you don't need a session, you can give the {session: false} option to your passport.authenticate() line like this:

passport.authenticate('facebook', { session: false }), ...

SpaceG commented 6 years ago

@mbrand1

Error: Failed to serialize user into session i dont know, i tried, like your description:

my AuthController.js

// oAuth beginning here 

facebook: function(req, res){

  passport.authenticate('facebook')(req,res);

},

facebookCallback: function(req, res){

   passport.authenticate('facebook', { session: false }, function(err, user) {
    req.logIn(user, function(err) {

      if (err) {
        console.log(err);
      res.view('404',  /*{layout: 'layouts/layout.ejs'}*/);
        return;
      }

      res.redirect('/');
      return;
    });
  })(req, res);

},

};

and here i have my passport.js file


const passport = require('passport'),
      LocalStrategy = require('passport-local').Strategy,

      GitHubStrategy = require('passport-github2').Strategy,
      TwitterStrategy = require('passport-twitter').Strategy,
      FacebookStrategy = require('passport-facebook').Strategy,

      shortid = require('shortid');
      generatePassword = require('password-generator');

      bcrypt = require('bcrypt');

      /*
      passport.serializeUser(function(user, done) {
        done(null, user);
      });

      passport.deserializeUser(function(user, done) {
        done(null, user);
      });
*/

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

    passport.deserializeUser(function(id, done) {
        User.findOneById(id).done(function (err, user) {
            done(err, user);
        });
    });

passport.use(new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password'
  },
  function(email, password, done) {

    User.findOne({ email: email }, function (err, user) {
      if (err) { return done(err); }
      if (!user) {
        return done(null, false, { message: 'Incorrect email.' });
      }

      bcrypt.compare(password, user.password, function (err, res) {
          if (!res)
            return done(null, false, {
              message: 'Invalid Password'
            });
          var returnUser = {
            username: user.username,
            createdAt: user.createdAt,
            id: user.id
          };
          return done(null, returnUser, {
            message: 'Logged In Successfully'
          });
        });
    });
  }
));

passport.use(new FacebookStrategy({
  clientID: '169553873736123',
  clientSecret: '3dfef9e57f803b5879700a27d9ff81c3',
  callbackURL: "http://localhost:1337/auth/facebook/callback"
},
function(token, tokenSecret, profile, done) {

  User.findOne({ uid: profile.id, provider: profile.provider }, function(err, user) {

    if (user) {
      return done(null, user);
    } else {

      var data = {
        id: 12345, 
        provider: profile.provider,
        uid: profile.id,
        username: profile.username
      };

      var shortid = require('shortid'),
          generatePassword = require('password-generator');

      //Let's generate a fake email and a fake password to match the User model attributes    
      var fakeEmail = 'fake_' + new Date().getTime() + '_' + shortid.generate() + '@fake.com';
          data.email = fakeEmail;

      var password = generatePassword(12, false); 
          data.password = password;         

          User.find(data, function(err, user) {
            if (err) { return done(err); }
            return done(null, user, {
              message: 'Logged In Successfully'
            });
      });
    }
  });
}
));

i dont know. - i does not work!!


codes-Mac-mini:oauthy Kopie jh$ sails lift

 info: Starting app...

 info: ·• Auto-migrating...  (alter)
 info:    Hold tight, this could take a moment.
 info:  ✓ Auto-migration complete.

 info: 
 info:                .-..-.
 info: 
 info:    Sails              <|    .-..-.
 info:    v1.0.1              |\
 info:                       /|.\
 info:                      / || \
 info:                    ,'  |'  \
 info:                 .-'.-==|/_--'
 info:                 `--'-------' 
 info:    __---___--___---___--___---___--___
 info:  ____---___--___---___--___---___--___-__
 info: 
 info: Server lifted in `/Users/jh/Desktop/new/oauthy Kopie`
 info: To shut down Sails, press <CTRL> + C at any time.
 info: Read more at https://sailsjs.com/support.

debug: -------------------------------------------------------
debug: :: Thu May 31 2018 01:42:26 GMT+0200 (CEST)

debug: Environment : development
debug: Port        : 1337
debug: -------------------------------------------------------
Error: Failed to serialize user into session
    at pass (/Users/jh/Desktop/new/oauthy Kopie/node_modules/passport/lib/authenticator.js:281:19)
jyang0110 commented 5 years ago

I am facing the same problem. Is there any solution?

sjohann21 commented 4 years ago

I also have the same issue: (node:54362) UnhandledPromiseRejectionWarning: TypeError: Cannot read property '_id' of undefined at signToken

sjohann21 commented 4 years ago

signToken = user => { return JWT.sign({ iss: 'medicentric', sub: user.id, iat: new Date().getTime(), exp: new Date().setDate(new Date().getDate() + 1) }, JWT_SECRET) }