getting info about facebook user using passport - node.js

this are my first steps in node.js in general and passport in particular and i came across a really annoying issue. i am trying to get the events user attended to with hes Facebook profile but no matter what i tried it simply didn't work. So i thought "ok, lets and get other data" but except for the basic display name and profile pic any other attempt (birthday,events,friends list etc..) ends up with no data. i tried using Facebook's api alot in the last few days (for the first time) and simply couldnt figure it out...this is my last attempt:
passport.use(new FacebookStrategy({
clientID: config.fb.appID,
clientSecret: config.fb.appSecret,
callbackURL: config.fb.callbackURL,
profileFields: ['id', 'displayName', 'photos', 'birthday', 'events', 'profileUrl', 'emails', 'likes']
}, function(accessToken, refershToken, profile, done){
//Check if the user exists in our Mongo DB database
//if not, create one and return the profile
//if exists, return profile
userModel.findOne({'profileID':profile.id}, function(err, result){
if(result){
done(null,result);
} else {
// Create a new user in our mongoLab account
var newFbUSer = new userModel({
profileID: profile.id,
fullname: profile.displayName,
profilePic:profile.photos[0].value || '',
birthday:profile.birthday,
//friends:profile.user.friends[0],
profileUrl:profile.profileUrl
});
newFbUSer.save(function(err){
done(null,newFbUSer);
console.log(newFbUSer.displayName);
})
}
})
}))
any help with how can i get and use user's friends list/ events??

Maybe you haven't passed the details of information you need to facebook while calling the Facebook login. While calling the facebook login you need to specify what all information you need in the scope. For example if you need public_profile,email,user_friends following is the code which you will add in routes:
app.get('/auth/facebook', passport.authenticate('facebook', { scope : 'public_profile,email,user_friends' }));

Try this for the full name:
fullName: profile.name.givenName + ' ' + profile.name.familyName

Related

facebook id return by passportjs doesn't match with facebook user id

I used passportjs facebook strategy, to fetch user information. But the user id return by passportjs doesn't match with actual facebook user id and facebook username is undefined. How to fetch actual facebook user id and username?
passport.use(new FacebookStrategy({
clientID: config.get('facebook.clientID'),
clientSecret: config.get('facebook.clientSecret'),
callbackURL: config.get('facebook.callbackURL'),
passReqToCallback: true,
// profileFields: ['id', 'email', 'first_name', 'last_name']
},
function(req, accessToken, refreshToken, profile, done) {
console.log(profile);...........
........................................
//output of console.log(profile)
_json:Object {name: "Tareq Ahamed", id: "1720360918026935"}
_raw:"{"name":"Tareq Ahamed","id":"1720360918026935"}"
displayName:"Tareq Ahamed"
gender:undefined
id:"1720360918026935"
name:Object {familyName: undefined, givenName: undefined, middleName: undefined}
profileUrl:undefined
provider:"facebook"
username:undefined
// but the actual facebook user id is 100001591295237
There is no way to get the "real" ID of a user, or his username. You do not need them anyway, you can identify returning users with the ID you get - it´s called "App Scoped ID" and it will stay the same per App.
If you want additional data in a request and not just id and name, you have to use the fields parameter as documented: https://developers.facebook.com/docs/graph-api/using-graph-api#fields

Handling authentication in Nodejs with passport-facebook-token, request coming from frontend Facebook SDK

I am working on a Unity App. For login, there are two methods, one using Email and another using Facebook. In case of login separately, I do not have any problem. Registration and Login with Email works perfectly. And Login with Facebook works perfectly as well. Here's the workflow, I created just to make you clear.
tl;dr [read update]
There's another schema for account, which is used for login.
var Account = new Schema({
email: String,
password: String,
facebookId: String
});
Things to know about the backend API.
Passport is used for Authentication
Successful login returns email and token to the client through API.
On client, token is most to play game and use the overall features.
As I said, I have already covered the part when if a client registers and login using email, then client can use the app. But my confusion is handling the logins with Facebook. Facebook SDK is already integrated with the Unity App, and Login is success.
Now, how can I use the Facebook login information that is generated by the Facebook SDK onto my back end, so that I can authorize the user throughout the system, as done in email login.
Going through other questions in SO and Google, I came across passport-facebook-token, I also tried using the plugin but could not came up with the logic and flow for handling the data from SDK into the Nodejs API. Can someone me help understand how it is done?
Update 1: Using passport-facebook-token
Strategy on index.js
passport.use(new FacebookTokenStrategy({
clientID: FACEBOOK_APP_ID,
clientSecret: FACEBOOK_APP_SECRET
}, function(accessToken, refreshToken, profile, done) {
Account.findOrCreate({facebookId: profile.id}, function (error, user) {
return done(error, user);
});
}
));
Controller API
api.post('/auth/facebook/token',
passport.authenticate('facebook-token'),
function (req, res) {
console.log(req.user);
// do something with req.user
res.sendStatus(req.user? 200 : 401);
}
);
Now, there is no error shown, but the data is not inserted into Account Schema, I have this findOrCreate() function in Model.
Account.statics.findOrCreate = function findOrCreate(profile, cb){
var userObj = new this();
this.findOne({facebookId : profile.id},function(err,result){
if(!result){
userObj.facebookId = profile.id;
//....
userObj.save(cb);
}else{
cb(err,result);
}
});
};
you can use facebook-passport for that, you can check the documentation here: https://github.com/jaredhanson/passport-facebook but basically, after you have already set up your developer account and got your keys from the developer site of facebook you can implement a FacebookStrategy object like following where you have to specify your credential and also a callback that in the documentation example is an http request to another resource of an express server where you can then save the data to mongo
passport.use(new FacebookStrategy({
clientID: FACEBOOK_APP_ID,
clientSecret: FACEBOOK_APP_SECRET,
callbackURL: "http://localhost:3000/auth/facebook/callback"
},
function(accessToken, refreshToken, profile, cb) {
User.findOrCreate({ facebookId: profile.id }, function (err, user) {
return cb(err, user);
});
}
));

using passport module to get facebook profile events

i am trying to get future events user attended to using passport module but im clearly missing something. i followed the Facebook API and got the permission i needed like so :
router.get('/auth/facebook', passport.authenticate('facebook', { scope: [ 'public_profile', 'user_events' ] }));
router.get('/auth/facebook/callback', passport.authenticate('facebook', {
successRedirect:'/welcome',
failureRedirect:'/'
}))
but when i am trying to print an event like this:
passport.use(new FacebookStrategy({
clientID: config.fb.appID,
clientSecret: config.fb.appSecret,
callbackURL: config.fb.callbackURL,
profileFields: ['id', 'displayName', 'photos', 'birthday', 'events', 'profileUrl', 'emails', 'likes']
}, function(accessToken, refershToken, profile, done){
//Check if the user exists in our Mongo DB database
//if not, create one and return the profile
//if exists, return profile
userModel.findOne({'profileID':profile.id}, function(err, result){
if(result){
done(null,result);
} else {
// Create a new user in our mongoLab account
var newFbUSer = new userModel({
profileID: profile.id,
fullname: profile.displayName,
profilePic:profile.photos[0].value || '',
birthday:profile.birthday,
events:profile.events[0].name,
profileUrl:profile.profileUrl,
});
console.log(newFbUSer.profilePic);
newFbUSer.save(function(err){
done(null,newFbUSer);
})
}
})
i get this error:
events:profile.events[0].name,
^
TypeError: Cannot read property '0' of undefined
i tried to replace name with value, as it is working perfectly fine with the photos, and i tried many other ways but i simply can't get this one to work...any help please?

Facebook OAuth2 does not provide user email

This has been asked many times but it seems like there's no known work-around for it so I'm posting this question in the hope that someone does have a work-around for it.
I'm using NodeJS, PassportJS-Facebook.
app.get("/auth/facebook",
passport.authenticate("facebook", {
scope : [ "email" ]
}),
function (req, res) {
});
At first I thought it's a PassportJS issue but I certainly eliminated this option.
The Facebook user account I'm using clearly states:
This app needs:
Your basic info
Your email address (xyz#example.com)
Some links to this known issue (yet unsolved!):
https://developers.facebook.com/bugs/298946933534016
https://developers.facebook.com/bugs/429653750464521
https://developers.facebook.com/bugs/482815835078469
So, do you use Facebook's OAuth service? If so, do you get the user's email? How? The "straight" way? A work-around?
The Facebook strategy in passportjs, expects a profileFields field in the options. Try passing "email" in the options.
strategyOptions.profileFields = ['emails', 'first_name', 'last_name'];
Alternatively, you can override the profileUrl in the options and send:
strategyOptions.profileURL = 'https://graph.facebook.com/me?fields=location,first_name,last_name,middle_name,name,link,username,work,education,gender,timezone,locale,verified,picture,about,address,age_range,bio,birthday,cover,currency,devices,email,favorite_athletes,id,hometown,favorite_teams,inspirational_people,install_type,installed,interested_in,languages,meeting_for,name_format,political,quotes,relationship_status,religion,significant_other,sports,updated_time,website';
Facebook will ignore fields that you don't have a permission to (like email).
This should go here:
passport.use(new FacebookStrategy({
clientID: FACEBOOK_APP_ID,
clientSecret: FACEBOOK_APP_SECRET,
callbackURL: "http://localhost:3000/auth/facebook/callback",
profileUrl: " ..... ",
//or
profileFields: [ ... ];
},
function(accessToken, refreshToken, profile, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
// To keep the example simple, the user's Facebook profile is returned to
// represent the logged-in user. In a typical application, you would want
// to associate the Facebook account with a user record in your database,
// and return that user instead.
return done(null, profile);
});
}
));
```
You must provide field 'scope' in settings object:
new FacebookStrategy({
clientID: FACEBOOK_APP_ID,
clientSecret: FACEBOOK_APP_SECRET,
callbackURL: "http://localhost:3000/auth/facebook/callback",
profileUrl: " ..... ",
scope: "email",
//or
profileFields: [ ... ];
}
try to look sources.

For Passport-Local with Node.js, is it possible to authenticate with email rather than username?

I'm using passport-local to provide local authentication on my node app. However, I would like to change this to authenticate with an email address rather than a username. Is there a way to do this?
Thank you.
You must first change the default username field to email with { usernameField: 'email' } you can then run a database search based on the email and check the password:
passport.use(new LocalStrategy({ usernameField: 'email' }, function(email, password, done) {
UserModel.findOne({ email: email }, function(err, user) {
// Check password functionality
})
})
Since you have to implement the validation yourself (in the LocalStrategy verifier callback), you can pass it anything you like:
passport.use(new LocalStrategy(function(email, password, done) {
// search your database, or whatever, for the e-mail address
// and check the password...
});
You can query the database for the email-id from request params like below:
passport.use('signup', new LocalStrategy({
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) {
//console.log(email);
console.log(req.param('email'));
findOrCreateUser = function(){
// find a user in Mongo with provided username
User.findOne({ 'email' : req.param('email') }, function(err, user) {
});
}))

Resources