Emmanuel Wayne
Emmanuel Wayne

Reputation: 33

Facebook authentication with passport. Cannot read property '0' of undefined error

I'm learning to add social authentication with Facebook to an app. Everything works fine, until I actually try to login to my test app with Facebook. Instead of being routed to the profile page, I get this error:

Cannot read property '0' of undefined

TypeError: Cannot read property '0' of undefined
    at Strategy.generateOrFindUser [as _verify] (C:\projects\Side            Projects\passyapp\app.js:16:19)
    at C:\projects\Side Projects\passyapp\node_modules\passport-  oauth2\lib\strategy.js:193:24
    at C:\projects\Side Projects\passyapp\node_modules\passport-  github\lib\strategy.js:174:7
    at passBackControl (C:\projects\Side Projects\passyapp\node_modules\oauth\lib\oauth2.js:134:9)
    at IncomingMessage.<anonymous> (C:\projects\Side Projects\passyapp\node_modules\oauth\lib\oauth2.js:157:7)
    at emitNone (events.js:91:20)
    at IncomingMessage.emit (events.js:185:7)
    at endReadableNT (_stream_readable.js:974:12)
    at _combinedTickCallback (internal/process/next_tick.js:74:11)
    at process._tickCallback (internal/process/next_tick.js:98:9)

BELOW IS A SNIPPET FROM MY APP.JS FILE:

function generateOrFindUser(accessToken, refreshToken, profile, done){
  if(profile.emails[0]) {
    User.findOneAndUpdate(
      { email: profile.emails[0] },
      {
        name: profile.displayName || profile.username,
        email: profile.emails[0].value,
        photo: profile.photos[0].value
      },
      {
        upsert: true
      },
    done
  );
  } else {
    var noEmailError = new Error("Your email privacy settings prevent you from signing in.");
    done(noEmailError, null);
  }
}

passport.use(new FacebookStrategy({
  clientID: process.env.FACEBOOK_APP_ID,
  clientSecret: process.env.FACEBOOK_APP_SECRET,
  callbackURL: "http://localhost:3000/auth/facebook/return",
  profileFields: ['email', 'id', 'displayName', 'photos']
},
  generateOrFindUser)
);


//in order for passport to handle sessions you need to implement the two methods
//directly below
passport.serializeUser(function(user, done) {
  done(null, user._id);
});

passport.deserializeUser(function(userId, done) {
  User.findById(userId, function(err, done) {
    //done(err, user);
  });
});

This is my User Schema

var UserSchema = new mongoose.Schema({
  email: {
    type: String,
    required: true,
    trim: true,
    unique: true,
  },
  name: {
    type: String,
    required: true,
    trim: true,
  },
  favoriteBook: {
    type: String,
    required: false,
    trim: true
  },
  photo: {
    type: String,
    required: true,
    trim: true
  }
});

I hope this isn't a waste of your busy coder time. Any attempt to help is greatly appreciated.

Upvotes: 1

Views: 2241

Answers (2)

Dilip Kumar
Dilip Kumar

Reputation: 11

  1. Firstly, set your profileFields section.

    'facebookAuth' : {
       'clientID'      : 'your App ID',
       'clientSecret'  : 'your App Secret',
       'callbackURL'   : 'your Callback URL',
       'profileFields'   : ['emails']
    }
    
  2. Now, we need to pull these details wherever we configure our passport code.

    passport.use(new FacebookStrategy({
        // pull in our app id and secret from our auth.js file
        clientID        : configAuth.facebookAuth.clientID,
        clientSecret    : configAuth.facebookAuth.clientSecret,
        callbackURL     : configAuth.facebookAuth.callbackURL,
        profileFields   : configAuth.facebookAuth.profileFields
    }
    

Upvotes: 0

Shruggie
Shruggie

Reputation: 938

EDIT: better answer

I'm guessing it's the profile.emails object (can't tell based on line number because your code is a snippet). Before that function you should have code that looks like this.

You need to ensure two things:

1. When you call passport.authenticate, make sure to request the email scope, like this: app.route('/auth/facebook').get(passport.authenticate('facebook', { scope: ['email']}));

2.

passport.use(new FacebookStrategy({
  clientID: facebookConfig.clientID,
  clientSecret: facebookConfig.clientSecret,
  callbackURL: facebookConfig.callbackURL,
  profileFields   : ['id', 'name', 'email'],
  },
  function generateOrFindUser...

It's important that your profileFields array contains email.

Upvotes: 1

Related Questions