Reputation: 9322
I am trying to make a Logged in or Signed In user to connect their account with facebook using passport.js facebook strategy, and save their profile photo, id, gender, timeline cover and token
according the userSchema (as made in user.js
model shown below.
I tried many combinations but still either getting 500
error from facebook, or if showing facebook auth, facebook can't return (the code combination, I tried) and save the object.
PS : I had entered correct callback URL in facebook
PPS: Please refer my UPDATED routes.js
and updated passport.js
below.
This is my routes.js
file:
app.get('/auth/connect/facebook', passport.authenticate('facebook-connect', { authType: 'rerequest', scope: ['id', 'cover', 'gender', 'photos'] }));
app.get('/auth/connect/facebook/callback',
passport.authenticate('facebook-connect', {
successRedirect: '/profile/configure',
failureRedirect: '/profile/congigure'
// failureFlash: true
}));
My passport.js
file of facebook-connect:
passport.use('facebook-connect', new FacebookStrategy({
clientID: configAuth.facebookAuth.clientID,
clientSecret: configAuth.facebookAuth.clientSecret,
callbackURL: configAuth.facebookAuth.callbackURL,
profileFields: ['id', 'cover', 'gender', 'photos'],
enableProof: true
},
function(token, refreshToken, profile, cb) {
process.nextTick(function() {
User.findOne({ 'local.facebook.id': profile.id }, function(err, user) {
if (err)
return cb(err);
if (user) {
return cb(null, false, req.flash('fbflash', 'This facebook user is already connected with an account at eBird.'));
} else {
user.local.facebook.id = profile.id;
user.local.facebook.token = token;
user.local.profile.gender = profile.gender;
user.local.profile.herobg = profile.cover;
user.local.profile.dp = user.local.profile.dp ? user.local.profile.dp : profile.photos[0].value;
if (user.local.profile.dp == '') {
if (user.local.profile.gender == 'male') {
user.local.profile.dp = 'http://res.cloudinary.com/pinterested222/image/upload/v1487659283/an-av-3_jxrhwc.png';
}
if (user.local.profile.gender == 'female') {
user.local.profile.dp = 'http://res.cloudinary.com/pinterested222/image/upload/v1487770814/female-avatar_vvyvtj.png';
}
}
user.save(function(err) {
if (err)
throw err;
return cb(null, user);
});
}
});
});
}));
My user.js
model:
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
var DateOnly = require('mongoose-dateonly')(mongoose);
var shortid = require('shortid');
var uniqueValidator = require('mongoose-unique-validator');
var userSchema = mongoose.Schema({
_id: {
type: String,
default: shortid.generate
},
local: {
email: String,
username: { type: String, unique: true },
firstname: String,
surname: String,
name: String,
role: { type: String, default: 'user' },
department: String,
pno: Number,
password: String,
verified: { type: Boolean, default: false },
profile: {
dp: String,
createdAt: { type: Date, default: Date.now },
herobg: String,
location: String,
website: String,
gender: String,
birthday: DateOnly,
lastlogin: { type: Date },
notifications: {
name: String,
namedp: String,
type: { type: String },
date: { type: Date, default: Date.now },
read: { type: Boolean, default: false }
}
},
facebook: {
id: String,
token: String
}
}
});
userSchema.plugin(uniqueValidator, { message: '{Path}:{VALUE} is already taken.' });
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
// userSchema.methods.bellTimesAgo = function(date);
module.exports = mongoose.model('User', userSchema);
The error, it's throwing me:
The www.facebook.com page isn’t working
www.facebook.com is currently unable to handle this request.
HTTP ERROR 500
Any help would be appreciated, Thanks.
UPDATE - 1
I read (& from passportjs docs) about passport.authorize()
and updated my passport.js
file accordig to passport.authorize() and also updated my routes, but still the same problem.
Here is my updated passport.js
:
// Facebook Strategy Updated using authorize
passport.use(new FacebookStrategy({
clientID: configAuth.facebookAuth.clientID,
clientSecret: configAuth.facebookAuth.clientSecret,
callbackURL: configAuth.facebookAuth.callbackURL,
// profileFields: ['id', 'cover', 'gender', 'photos'],
// enableProof: true,
passReqToCallback: true
},
function(req, accessToken, refreshToken, profile, done) {
process.nextTick(function() {
if (!req.user) {
User.findOne({ 'local.facebook.id': profile.id }, function(err, user) {
if (err)
return done(err);
if (user) {
return done(null, false, req.flash('fbflash', 'This facebook user is already connected with an account at eBird.'));
} else {
user.local.facebook.id = profile.id;
user.local.facebook.token = accessToken;
user.local.profile.gender = profile.gender;
user.local.profile.herobg = profile.cover;
user.local.profile.dp = user.local.profile.dp ? user.local.profile.dp : profile.photos[0].value;
if (user.local.profile.dp == '') {
if (user.local.profile.gender == 'male') {
user.local.profile.dp = 'http://res.cloudinary.com/pinterested222/image/upload/v1487659283/an-av-3_jxrhwc.png';
}
if (user.local.profile.gender == 'female') {
user.local.profile.dp = 'http://res.cloudinary.com/pinterested222/image/upload/v1487770814/female-avatar_vvyvtj.png';
}
}
user.save(function(err) {
if (err)
throw err;
return done(null, user);
});
}
});
} else {
var user = req.user;
user.local.facebook.id = profile.id;
user.local.facebook.token = accessToken;
user.local.profile.gender = profile.gender;
user.local.profile.herobg = profile.cover;
user.local.profile.dp = user.local.profile.dp ? user.local.profile.dp : profile.photos[0].value;
if (user.local.profile.dp == '') {
if (user.local.profile.gender == 'male') {
user.local.profile.dp = 'http://res.cloudinary.com/pinterested222/image/upload/v1487659283/an-av-3_jxrhwc.png';
}
if (user.local.profile.gender == 'female') {
user.local.profile.dp = 'http://res.cloudinary.com/pinterested222/image/upload/v1487770814/female-avatar_vvyvtj.png';
}
}
user.save(function(err) {
if (err)
throw err;
return done(null, user);
});
}
});
}));
Here is my updated routes.js
:
app.get('/auth/connect/facebook', passport.authorize('facebook', { authType: 'rerequest', scope: ['id', 'cover', 'gender', 'photos'] }));
app.get('/auth/connect/facebook/callback',
passport.authorize('facebook', {
successRedirect: '/profile/configure',
failureRedirect: '/profile/configure'
// failureFlash: true
})
);
Here is the snapshot of my app callback settings from Facebook:
Snapshot of the error, facebook keeps throwing in:
Upvotes: 2
Views: 2311
Reputation: 9322
Taking inspiration from @anton-novik, I fixed the bug.
The problem was in my routes.js
file. First have a look at my routes.js
file above, and then follow the code below:
app.get('/auth/connect/facebook', ensureLoggedIn('/login'), passport.authorize('facebook', { authType: 'rerequest' }));
app.get('/auth/connect/facebook/callback',
passport.authenticate('facebook', {
successRedirect: '/profile',
failureRedirect: '/profile/settings',
failureFlash: true
})
);
There was no need of scope
for the request I was making was already approved by Facebook for every app.
And then updated my passport.js
file to look like this:
// // Facebook Strategy
passport.use(new FacebookStrategy({
clientID: configAuth.facebookAuth.clientID,
clientSecret: configAuth.facebookAuth.clientSecret,
profileFields: ['id', 'picture.type(large)', 'gender', 'cover'],
callbackURL: configAuth.facebookAuth.callbackURL,
passReqToCallback: true
},
function(req, accessToken, refreshToken, profile, done) {
process.nextTick(function() {
// User is not logged in yet
if (!req.user) {
User.findOne({ 'local.facebook.id': profile.id }, function(err, user) {
if (err)
return done(err);
if (user) {
if (!user.facebook.token) {
user.facebook.token = accessToken;
user.facebook.name = profile.displayName;
user.facebook.email = profile.emails[0].value;
user.save(function(err) {
if (err) throw err;
return done(null, user);
});
}
return done(null, user);
} else {
// User should be created here
// and saved to mongoose
}
});
}
//else user is logged in and needs to be merged
else {
console.log(profile); //display the returned json from fb
// Connect the user and save the details, since the user already exsists
var user = req.user;
user.local.facebook.id = profile.id;
user.local.facebook.token = accessToken;
user.local.profile.gender = profile.gender;
user.local.profile.dp = profile.photos[0].value;
user.local.profile.herobg = profile._json.cover.source;
user.save(function(err) {
if (err)
throw err;
return done(null, user);
});
}
});
}));
Hope, it may help someone. :)
Upvotes: 0
Reputation: 1837
Passport.js documentation said:
Values for the
scope
option are provider-specific. Consult the provider's documentation for details regarding supported scopes.
If you check allowed permissions in Facebook documentation, you will not find such permissions as 'id', 'cover', 'gender', 'photos'
. These items are part of a person's public profile.
So, you should change scope
in routes.js
from:
scope: ['id', 'cover', 'gender', 'photos']
to:
scope: ['public_profile']
or don't specify scope, because public_profile
is default facebook permission.
P.S. I told about your "update 1" code version.
Upvotes: 4