I am facing a problem with the passport-facebook-token library. My node app.js looks like:
var passport = require('passport');
var FacebookTokenStrategy = require('passport-facebook-token');
app.use(passport.initialize());
app.use(passport.session());
passport.use(new FacebookTokenStrategy({
clientID: "myclientid",
clientSecret: "myclientsecret"
},
function(accessToken, refreshToken, profile, done) {
logger.info(JSON.stringify(accessToken));
logger.info(JSON.stringify(refreshToken));
logger.info(JSON.stringify(profile));
logger.info(JSON.stringify(done));
return done(null, user);
}
));
and prints:
info: "EAAH7GGhOLX4BAFY1cUQuTEUUtdAZAgAZAQr3S..."
info: undefined
info: {"provider":"facebook","id":"10153779813157657","displayName":"..."}}
info: undefined
In my auth.route.js:
var passport = require('passport');
//var strategy = require('passport-facebook-token');
router.post('/fabookauth', passport.authenticate('facebook-token'), function(req, res) {
// never called because the error occur into passport.authenticate
logger.info(JSON.stringify(req.body));
res.json({
email: req.body.email
});
});
when I call this endpoint, an undefined error prints on console.
Looking in passport-facebook-token source code, I think I found the problem:
https://github.com/drudge/passport-facebook-token/blob/master/src/index.js
_createClass(FacebookTokenStrategy, [{
key: 'authenticate',
value: function authenticate(req, options) {
var _this2 = this;
var accessToken = this.lookup(req, this._accessTokenField);
var refreshToken = this.lookup(req, this._refreshTokenField);
if (!accessToken) return this.fail({ message: 'You should provide ' + this._accessTokenField });
this._loadUserProfile(accessToken, function (error, profile) {
if (error) return _this2.error(error);
var verified = function verified(error, user, info) {
if (error) return _this2.error(error);
if (!user) return _this2.fail(info);
return _this2.success(user, info);
};
if (_this2._passReqToCallback) {
_this2._verify(req, accessToken, refreshToken, profile, verified);
} else {
_this2._verify(accessToken, refreshToken, profile, verified);
}
});
}
}
the function verified is always undefined.
I looked to many examples to do this job but I could not figure out the problem, am I doing something wrong? Is that a library bug?
Related
I have a sails app. I was trying to implement Facebook Login. When I click on the Login with facebook button i am getting this error:
error: A server error occurred in a request:
error: FacebookTokenError: This authorization code has been used.
Full error log looks like this:
error: A server error occurred in a request:
error: FacebookTokenError: This authorization code has been used.
at Strategy.parseErrorResponse (/home/node_modules/passport-facebook/lib/strategy.js:198:12)
at Strategy.OAuth2Strategy._createOAuthError (/home/node_modules/passport-facebook/node_modules/passport-oauth2/lib/strategy.js:341:16)
at /home/node_modules/passport-facebook/node_modules/passport-oauth2/lib/strategy.js:166:45
at /home/node_modules/passport-facebook/node_modules/passport-oauth2/node_modules/oauth/lib/oauth2.js:177:18
at passBackControl (/home/node_modules/passport-facebook/node_modules/passport-oauth2/node_modules/oauth/lib/oauth2.js:123:9)
at IncomingMessage.<anonymous> (/home/node_modules/passport-facebook/node_modules/passport-oauth2/node_modules/oauth/lib/oauth2.js:143:7)
at IncomingMessage.emit (events.js:117:20)
at _stream_readable.js:944:16
at process._tickDomainCallback (node.js:492:13) { [FacebookTokenError: This authorization code has been used.]
name: 'FacebookTokenError',
message: 'This authorization code has been used.',
type: 'OAuthException',
code: 100,
subcode: undefined,
status: 500 }
Middleware code looks like this:
var passport = require('passport')
, FacebookStrategy = require('passport-facebook').Strategy
, moment= require('moment')
, momentTimeZone=require('moment-timezone')
, inflection = require('inflection')
, markdown = require('markdown').markdown
, URL =require('url')
, LocalStrategy=require('passport-local').Strategy
, config= require('./local')
, device = require('express-device')
var createUser = function (token, tokenSecret, profile, done) {
process.nextTick(function () {
User.findOne({
or: [
{uid: parseInt(profile.id)},
{uid: profile.id}
]
}
).exec(function (err, user) {
if (user) {
return done(null, user);
} else {
var data = {
provider: profile.provider,
uid: profile.id,
name: profile.displayName,
email: profile.email
};
if(profile.emails && profile.emails[0] && profile.emails[0].value) {
data.email = profile.emails[0].value;
}
if(profile.name && profile.name.givenName) {
data.firstname = profile.name.givenName;
}
if(profile.name && profile.name.familyName) {
data.lastname = profile.name.familyName;
}
User.create(data).exec(function (err, user) {
sails.log.info("Error",JSON.stringify(err))
return done(err, user);
});
}
});
});
};
module.exports = {
passport.use(new FacebookStrategy({
clientID: config.facebook.clientID,
clientSecret: config.facebook.clientSecret,
callbackURL: config.facebook.callbackURL,
profileFields: ['name', 'emails' ],
enableProof: true
},
function (accessToken, refreshToken, email, done)
{
//console.log("Auth done");
//done(null, email);
createUser
}
//createUser
//}
))
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
/*app.get("/auth/facebook", passport.authenticate("facebook", { scope: ['email', 'public_profile'] }));*/
app.get('/auth/facebook',
passport.authenticate('facebook', { scope: ['email', 'public_profile'] }));
app.get("/auth/facebook/callback",
passport.authenticate("facebook", {
successRedirect: "/",
failureRedirect: "/login"
}),
function(req, res) {
res.redirect('/');
});
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/login')
}
app.use(passport.initialize());
app.use(passport.session());
app.use(device.capture());
device.enableDeviceHelpers(app)
}
}
};
Can anyone suggest why I am getting this error and any possible solution.
This error occurs when you logged using facebook login, after that delete the user record in your database. You must delete your APP in your facebook account and try again.
Another posibility is that you already are logged in, and your middleware is trying to login again. In your code, you are not checking if the user is already logged in before send the request to "auth/facebook. There is a simple way to prove this: Open a Chrome window in private mode, so no cookie is used, and try again your facebook login. Good Luck!
Probabily not exist some attributes of profile data. Try:
console.log(profile)
For verify all attributes of profile. In my case:
{ id: 'nnnnnnnn',
username: undefined,
displayName: 'My Name',
name:
{ familyName: undefined,
givenName: undefined,
middleName: undefined },
gender: undefined,
profileUrl: undefined,
provider: 'facebook',
_raw: '{"name":"My name","id":"nnnnnnnn"}',
_json: { name: 'My name', id: 'nnnnnnnn' } }
Not exist any attribute "email" or similar, this generate the error and not complete the cicle life of the authenticate:
error: FacebookTokenError: This authorization code has been used.
The attribute email not get because I hidden this in my account Facebook.
In your code:
...
var data = {
provider: profile.provider,
uid: profile.id,
name: profile.displayName,
email: profile.email
};
...
The line:
email: profile.email
You are already assuming that the attribute email is already exist.
Try:
email: (profile.emails && profile.emails[0]) ? profile.emails[0].value : ''
My problem is that I'm getting the error "Error: Failed to serialize user into session". I'm confused, because I've set a serializeUser function, but it doesn't appear to be called (my console.log isn't being printed).
This is while I'm following the feathers passport tutorial: http://feathersjs.com/learn/authorization/
Note: my suspicion is that feathers-passport uses a different "passport" object than my own library. Unfortunately I have no idea how I would rememdy such an issue. It seems to me it's just horrendous design by Passport to not work by passing around instances, and instead attaching things to itsself directly.
I'm setting up passport for serialization and authentication using the following:
var LocalStrategy = require('passport-local').Strategy;
function GetPassport(userService, Passport) {
console.log('passport has been prepared.\n');
Passport.serializeUser(function(user, done) {
console.log('user: ', user);
done(null, user._id);
});
Passport.deserializeUser(function(id, done) {
userService.get(id, {}, done);
});
Passport.use(new LocalStrategy(function(username, password, done) {
userService.authenticate(username, password, done);
}));
return Passport;
}
module.exports = GetPassport;
Then I'm using:
var userService = UserService(config.db);
var passport = GetPassport(userService);
app.post('/login', passport.authenticate('local'));
If you need more details here is UserService:
var MongoDB = require('feathers-mongodb');
var Crypto = require('crypto');
var UserService = function(database) {
return MongoDB({
db: database,
collection: '_users',
}).extend({
authenticate: function(username, password, callback) {
this.find({query: {username: username}}, function(error, users) {
if(error)
callback(error);
var user = users[0];
if(!user)
return callback(new Error('No User Found'));
if(user.password !== hash(password, user.salt))
return callback(new Error('Password Is Incorrect'));
//success, return the authenticated user
return callback(null, user);
});
},
setup: function() {
this.before({
create: function(hook, next) {
//Create the salt
var salt = Crypto.randomBytes(128).toString('base64');
hook.data.salt = salt;
hook.data.password = hash(hook.data.password, hook.data.salt);
next();
},
});
},
});
};
module.exports = UserService;
function hash(string, salt) {
var shasum = Crypto.createHash('sha256');
shasum.update(string + salt);
return shasum.digest('hex');
}
The error trace:
Error: Failed to serialize user into session
at pass (/Users/funk/Development/Projects/generic_rest_server/node_modules/feathers-passport/node_modules/passport/lib/authenticator.js:277:19)
at Authenticator.serializeUser (/Users/funk/Development/Projects/generic_rest_server/node_modules/feathers-passport/node_modules/passport/lib/authenticator.js:295:5)
at IncomingMessage.req.login.req.logIn (/Users/funk/Development/Projects/generic_rest_server/node_modules/passport/lib/http/request.js:48:29)
at Strategy.strategy.success (/Users/funk/Development/Projects/generic_rest_server/node_modules/passport/lib/middleware/authenticate.js:228:13)
at verified (/Users/funk/Development/Projects/generic_rest_server/node_modules/passport-local/lib/strategy.js:83:10)
at /Users/funk/Development/Projects/generic_rest_server/user-service.js:22:24
at /Users/funk/Development/Projects/generic_rest_server/node_modules/feathers-mongodb/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/cursor.js:158:16
at commandHandler (/Users/funk/Development/Projects/generic_rest_server/node_modules/feathers-mongodb/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/cursor.js:651:16)
at /Users/funk/Development/Projects/generic_rest_server/node_modules/feathers-mongodb/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/db.js:1670:9
at Server.Base._callHandler (/Users/funk/Development/Projects/generic_rest_server/node_modules/feathers-mongodb/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/connection/base.js:382:41)
The answer was in my note.
This should be helpful for anyone else who gets stuck following:
"http://feathersjs.com/learn/authorization/"
You must provide the FeathersPassport call with the passport option. If not, feathers-passport well use a different version of passport, than the one you add serializeUser to:
app.configure(FeathersPassport(function(result) {
// MongoStore needs the session function
var MongoStore = ConnectMongo(result.createSession);
result.secret = 'noymysecret';
result.store = new MongoStore({
db: config.db,
});
result.resave = false;
result.saveUninitialized = false;
//*HERE*//
result.passport = passport;
//**//
return result;
}));
I blame Passport inexplicably being a singleton, for not noticing this sooner.
I am trying to make a node.js web application that tells the user to sign in using their gmail.
So I tried to use the instructions over here: http://passportjs.org/guide/google/. I changed the url www.example.com to localhost, then ran the application. It tells me that it can't find User. Here is the whole log: User.findOrCreate({openID: identifier }, function(err, user) {(and then on the next line) ReferenceError: User is not defined.
You need to define "User" by calling it from a model. Create a User model (if you haven't already) and import it as a variable. E.g.
var User = require('/path/to/User');
Sometimes I find it helpful for debugging to log the callback to the console, to see if the desired output is being spit out.
I just implemented one maybe this will help , I'm using Express the routes section is on the bottom.. Remember to set your host in the Google Key, my App has de full url of the AWS Server
var passport = require('passport');
// ====== Passport and OAuth2 API
var GoogleStretegy = require('passport-google-oauth').OAuth2Strategy;
passport.serializeUser(function (user, done) {
done(null, user);});
passport.deserializeUser(function (obj, done){
done(null, obj);});
// Set Passport Initialize and Sessions
app.use(passport.initialize());
app.use(passport.session());
passport.use(new GoogleStretegy({
clientID: CREDENTIALS.google.GOOGLE_CLIENT_ID,
clientSecret: CREDENTIALS.google.GOOGLE_CLIENT_SECRET,
callbackURL:"<host>/oauth2callback"
},
function (req, accessToken, refreshToken, profile, done) {
process.nextTick(function () {
console.log(JSON.stringify(profile));
console.log(req);
var username= profile.emails[0].value.split('#');
User.findOne({email: profile.emails[0].value,username:username[0]}).exec(function (err,user) {
if(!user){
var user = new User({username: username[0]});
user.set('email',profile.emails[0].value);
user.set('FullName',profile.DisplayName);
user.save(function (err) {
if(err){
console.log(err);
profile=null;
return done(null,profile);
}else {
return done(null, profile);
}
});
}else {
return done(null, profile);
}
});
// return done(null, profile);
});
}
));
/// ROUTES !
router.get('/logout', function (req, res) {
req.session.destroy(function () {
// Google log out
req.logout();
res.redirect('/login');
});
});
//Google OAuth2
router.get('/auth/google',passport.authenticate('google', { scope: ['https://www.googleapis.com/auth/userinfo.profile','https://www.googleapis.com/auth/userinfo.email'] }));
router.get('/oauth2callback', passport.authenticate('google', { failureRedirect: '/login' }), function (req, res) {
res.redirect('/');
});
I'm trying to test my local-login. I've implemented with passport.js, following its guide and following this MEAN skeleton.
I'm pretty sure that the implementation is fine, but there is something wrong with the test that always fails authentication.
If authentication fails it should be redirect to "/signin"if authentication is correct it should be go to "/"
But when I test, the authentication always fails.
This is routes.js:
module.exports = function(app, passport, auth) {
var users = require('../app/controllers/users');
app.get('/signin', users.signin);
app.post('/users/session', passport.authenticate('local', {
failureRedirect: '/signin',
failureFlash: 'Invalid email or password.'
}), users.session);
var index = require('../app/controllers/index');
app.get('/', index.render);
passport.js:
var mongoose = require('mongoose'),
LocalStrategy = require('passport-local').Strategy,
User = mongoose.model('User'),
config = require('./config');
module.exports = function(passport) {
//Serialize sessions
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findOne({
_id: id
}, '-salt -hashed_password', function(err, user) {
done(err, user);
});
});
//Use local strategy
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: 'Unknown user'
});
}
if (!user.authenticate(password)) {
return done(null, false, {
message: 'Invalid password'
});
}
return done(null, user);
});
}
));
}
and test: api.js:
var User, app, mongoose, request, server, should, user;
should = require("should");
app = require("../server");
mongoose = require("mongoose");
User = mongoose.model("User");
request = require("supertest");
server = request.agent("http://localhost:3000");
describe("<Unit Test>", function() {
return describe("API User:", function() {
before(function(done) {
user = new User({
email : "user#user.com",
firstName: "Full Name",
lastName : "Last Name",
password : "pass11"
});
user.save();
return done();
});
describe("Authentication", function() {
return it("Local login", function(done) {
return server.post("/users/session").send({
email : "user#user.com",
password: "pass11"
}).end(function(err, res) {
res.headers.location.should.have.equal("/");
return done();
});
});
});
return after(function(done) {
User.remove().exec();
return done();
});
});
});
This is what the terminal displays:
<Unit Test>
API User:
Authentication
1) Local login
0 passing (24ms)
1 failing
1) <Unit Test> API User: Authentication Local login:
actual expected
/signin
I'm trying using this code and work as expected
var User, app, mongoose, request, server, should, user, agent;
should = require("should");
app = require("../server");
mongoose = require("mongoose");
User = mongoose.model("User");
request = require("supertest");
agent = request.agent(app)
describe('User', function () {
before(function(done) {
user = new User({
email : "user#user.com",
firstName: "Full Name",
lastName : "Last Name",
password : "pass11"
});
user.save(done)
});
describe('Login test', function () {
it('should redirect to /', function (done) {
agent
.post('/users/session')
.field('email', 'user#user.com')
.field('password', 'pass11')
.expect('Location','/')
.end(done)
})
after(function(done) {
User.remove().exec();
return done();
});
})
})
for more reference check this test-user
here my screenshot
I am using passportjs for facebook authentication. Here is my facebook strategy:
passport.use(new FacebookStrategy({
clientID: config.facebook.clientID,
clientSecret: config.facebook.clientSecret,
callbackURL: config.facebook.callbackURL
}, function(accessToken, refreshToken, profile, done) {
User.findOne({ 'facebook.id': profile.id }, function (err, user) {
if (err) { return done(err); }
if (!user) {
user = new User({
name: profile.displayName,
email: profile.emails[0].value,
username: profile.username,
provider: 'facebook',
facebook: profile._json
});
user.save(function (err) {
if (err) {
console.log(err);
}
return done(err, user);
});
} else {
return done(err, user);
}
});
}));
I added the following routes:
app.get('/facebook/auth', passport.authenticate('facebook', { scope: [ 'email', 'user_about_me', 'publish_actions']}), function(req, res) { });
// I need the following fix due to this: http://stackoverflow.com/a/17015836/289246
app.get('/facebook/auth/callback', function(req, res, next) {
if (req.query && !req.query.error && req.query.error_code) {
req.query.error = true;
}
next();
},
passport.authenticate('facebook', { failureRedirect: '/facebook-auth-failure', successRedirect: '/auth-success', failureFlash: true })
);
app.get('/facebook-auth-failure', users.authFailure);
app.get('/auth-success', users.authSuccess);
My users.authFailure method is:
exports.authFailure = function (req, res) {
var error = ???
// How can I get here the error message??
res.render('auth-failure', {
error: error || 'An error has accured'
});
};
In case of facebook authentication failure, how can I get the error message (I want to display it to the user)?
Since you're using failureFlash, this should do it:
var error = req.flash('error');
I experienced many many problems and bugs and configurations issues during working with Passport. My solution was to move to Everyauth.
I don't know if this will be any use to you but I got access to flash messages this way.
When you are defining the FacebookStrategy use the passReqToCallback parameter.
passport.use(new FacebookStrategy({
clientID: facebook.getClientID(),
clientSecret: facebook.getClientSecret(),
callbackURL: facebook.getCallback(),
passReqToCallback: true
this will allow you to add the req.flash() as a parameter to the done() like so
return done(false, user, reg.flash('success', 'Sign in successfull'));
Hope that sheds some light on the situation for you or anybody else looking for help