I am having the "done is not a function" error. I tried to remove the passReqToCallback parameter but it still doesn't work. I am not sure why please help.
It's on the line: return done(null, false, req.flash('signupMessage', 'That username is already taken.'));
// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
emailField : 'email',
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, username, password, done) {
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.find({ 'local.email' : email, 'local.username' : username }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if theres already a user with that email
//if user found.
if (user.length!=0) {
if(user[0].username){
return done(null, false, req.flash('signupMessage', 'That username is already taken.'));
}else{
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
}
return done(err);
}
else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.local.email = email;
newUser.local.username = username;
newUser.local.password = newUser.generateHash(password);
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, true);
});
}
});
});
}));
// =========================================================================
// LOCAL LOGIN =============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'userIdentityField',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) { // callback with email and password from our form
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.isValidUserPassword(email, password, done);
}));
};
Related
I'm getting this error when trying to login to my app:
Error: Failed to serialize user into session
The problem is that it is reading parameter user.id as undefined. If I change it to the id value the user has in the database login works.
passport.serializeUser(function(user, done) {
done(null, user.id);
});
Any ideas on why am I getting my user value as undefined?
pasport local login:
// =========================================================================
// LOCAL LOGIN =============================================================
// =========================================================================
passport.use(
'local-login',
new LocalStrategy({
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) {
if(username == "" || password == ""){
return done(null, false, req.flash('loginMessage', 'Please fill in all blank fields to login.'));
}else{
query.login(req, username, password, done);
}
})
);
login query:
login: function(req, username, password, done) {
connection.query("SELECT * FROM users WHERE username = ?",[username], function(err, rows){
if (err)
return done(err);
if (!rows.length)
return done(null, false, req.flash('loginMessage', 'Sorry, username/password do not match.')); // req.flash is the way to set flashdata using connect-flash
// if the user is found but the password is wrong
if (!bcrypt.compareSync(password, rows[0].password))
return done(null, false, req.flash('loginMessage', 'Sorry, username/password do not match.')); // create the loginMessage and save it to session as flashdata
// all is well, return successful user
return done(null, rows[0]);
});
}
Login was working until I changed some field names on my database but I updated all my queries with the new names of the fields so I do not know whats happening.
I found out the problem. Since I changed the field name of id to id_users on my database the serializeUser function goes like this:
passport.serializeUser(function(user, done) {
done(null, user.id_users);
});
I am using Passport and Express in a NodeJs project.
I have a User model with fields: id, password, and email. When I try to signup it throws this error:
[object Object]
into the form and it doesn't post user data in the database. In the console, it shows
POST /signup 302 -58.
Here's whole passport.js file:
var LocalStrategy = require('passport-local').Strategy;
// load up the user model
var configDB = require('./database.js');
var Sequelize = require('sequelize');
var sequelize = new Sequelize(configDB.url);
var User = sequelize.import('../app/models/users');
User.sync();
// load the auth variables
var configAuth = require('./auth'); // use this one for testing
module.exports = function(passport) {
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id).then(function(user){
done(null, user);
}).catch(function(e){
done(e, false);
});
});
=========================================================================
// LOCAL LOGIN =============================================================
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function(req, email, password, done) {
User.findOne({ where: { email: email }})
.then(function(user) {
if (!user) {
done(null, false, req.flash('loginMessage', 'Unknown user'));
} else if (!user.validPassword(password)) {
done(null, false, req.flash('loginMessage', 'Wrong password'));
} else {
done(null, user);
}
})
.catch(function(e) {
done(null, false, req.flash('loginMessage',e.name + " " + e.message));
});
}));
=========================================================================
// LOCAL SIGNUP ============================================================
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function(req, email, password, done) {
// Whether we're signing up or connecting an account, we'll need
// to know if the email address is in use.
User.findOne({ where: { email: email }})
.then(function(existingUser) {
// check to see if there's already a user with that email
if (existingUser)
return done(null, false, req.flash('error', 'That email is already taken.'));
// If we're logged in, we're connecting a new local account.
if(req.user) {
var user = req.user;
user.email = email;
user.password = User.generateHash(password);
user.save().catch(function (err) {
throw err;
}).then (function() {
done(null, user);
});
}
// We're not logged in, so we're creating a brand new user.
else {
// create the user
var newUser = User.build ({email: email, password: User.generateHash(password)});
newUser.save().then(function() {done (null, newUser);}).catch(function(err) { done(null, false, req.flash('error', err));});
}
})
.catch(function (e) {
done(null, false, req.flash('loginMessage',e.name + " " + e.message));
})
}));
And in routes.js
// locally --------------------------------
// LOGIN ===============================
// show the login form
app.get('/login', function(req, res) {
res.render('login.ejs', { message: req.flash('loginMessage') });
});
// process the login form
app.post('/login', passport.authenticate('local-login', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/login', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
// SIGNUP =================================
// show the signup form
app.get('/signup', function(req, res) {
res.render('signup.ejs', { message: req.flash('loginMessage') });
});
// process the signup form
app.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/signup', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
Thanks in advance.
I found the solution!!! It was simpler than I thought, just a carelessness.
In user model I defined password field:
password: {
type: DataTypes.STRING(25),
allowNull: true,
defaultValue: ''
},
And after encryption, this field length was too small to storage the value. So I changed it for 255.
I have an issue with Facebook Strategy failing after successfully logging into Facebook. I'm using Passport Local and Passport Facebook, but independent of each other, here are the code what I have shared.
passport.use(new FacebookStrategy({
clientID: 'XYZId',
clientSecret: 'XYZSecret',
callbackURL: "/auth/facebook/callback"
},
function(accessToken, refreshToken, profile, done) {
console.log(profile);
userDetails = profile;
return done();
}
));
app.get('/auth/facebook', passport.authenticate('facebook'));
app.get('/auth/facebook/callback',
passport.authenticate('facebook', {
failureRedirect: '/login' }),
function(req, res) {
console.log("req");
console.log(userDetails);
console.log("End of Req");
res.redirect('/');
});
Is there anything wrong in this code? Also, for local strategy I have modified a bit which is working perfectly fine.
// config/passport.js
// load all the things we need
var LocalStrategy = require('passport-local').Strategy;
// load up the user model
var mysql = require('mysql');
var bcrypt = require('bcrypt-nodejs');
var dbconfig = require('./database');
var connection = mysql.createConnection(dbconfig.connection);
connection.query('USE ' + dbconfig.database);
// expose this function to our app using module.exports
module.exports = function(passport) {
// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and unserialize users out of session
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
connection.query("SELECT * FROM users WHERE id = ? ",[id], function(err, rows){
done(err, rows[0]);
});
});
// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use(
'local-signup',
new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
connection.query("SELECT * FROM users WHERE username = ?",[username], function(err, rows) {
if (err)
return done(err);
if (rows.length) {
return done(null, false, req.flash('signupMessage', 'That username is already taken.'));
} else {
// if there is no user with that username
// create the user
console.log(req.body);
var newUserMysql = {
uname: req.body.uname,
username: username,
userphone: req.body.userphone,
password: bcrypt.hashSync(password, null, null) // use the generateHash function in our user model
};
var insertQuery = "INSERT INTO users ( uname, username, password, userphone ) values (?,?,?,?)";
console.log(insertQuery);
connection.query(insertQuery,[newUserMysql.uname, newUserMysql.username, newUserMysql.password, newUserMysql.userphone],function(err, rows) {
newUserMysql.id = rows.insertId;
return done(null, newUserMysql);
});
}
});
})
);
// =========================================================================
// LOCAL LOGIN =============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use(
'local-login',
new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) { // callback with email and password from our form
connection.query("SELECT * FROM users WHERE username = ?",[username], function(err, rows){
if (err)
return done(err);
if (!rows.length) {
return done(null, false, req.flash('loginMessage', 'No user found.')); // req.flash is the way to set flashdata using connect-flash
}
// if the user is found but the password is wrong
if (!bcrypt.compareSync(password, rows[0].password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata
// all is well, return successful user
return done(null, rows[0]);
});
})
);
};
Console Log :
You didn't store authorized facebook user in session. You just call function done() without parameters in the implementation of FacebookStrategy. First, you should store fb user in your database or select if exist then call function done (receives first param as error, second as user object). here's docs
I've incorporated the authentication code from this tutorial into my application and everything is working. Now I'm going back to make the database error handling more robust. In the code below (from the tutorial), why do they throw the error if they hit a snag with the save()? Is there a reason not to handle more gracefully? Perhaps something like:
if (err)
return done(err, false, req.flash('signupMessage', 'Encountered database error.'));
From the tutorial:
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'local.email' : email }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if theres already a user with that email
if (user) {
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
solution is simple:
newUser.save(function(err) {
if (err) {
return done(err);
}
return done(null, newUser);
});
even in mongoose documentation saving is done without throwing exception.
solution that You're reading is too old: Dec 04, 2013. Why not to read latest documentation from it's pure source?
Read this: http://passportjs.org/docs/configure
BONUS: I would recommend to shorten Your code by using plugin mongoose findOrCreate
I'm new to Nodejs and looking for a user credential management, I see that Passport a good option.
But in Passport's registration strategy, I only see that user information saved is email and password.
I need more user information like full name, job, registration time, last activity time, etc.
So how can I do this in Passport?
Inside of your Passport.js signup/register strategy you should be able to just pass the request object in as the first parameter of that function and Passport will take care of passing your request into your function for you.
So you should be able to use the req.body object, get the data from your form that way and store that to your database.
Below is a more detailed example of how this would work.
passport.use('signup', new LocalStrategy({
passReqToCallback : true
},
function(req, username, password, done) {
findOrCreateUser = function(){
// find a user in Mongo with provided username
User.findOne({'username':username},function(err, user) {
// In case of any error return
if (err){
console.log('Error in Signup: ' + err);
return done(err);
}
// already exists
if (user) {
console.log('User already exists');
return done(null, false,
req.flash('message','User Already Exists'));
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.username = username;
newUser.password = createHash(password);
newUser.firstName = req.body.firstName;
newUser.lastName = req.body.lastName;
// save the user
newUser.save(function(err) {
if (err){
console.log('Error in Saving user: '+err);
throw err;
}
console.log('User Registration succesful');
return done(null, newUser);
});
}
});
};
// Delay the execution of findOrCreateUser and execute
// the method in the next tick of the event loop
process.nextTick(findOrCreateUser);
});
);
Here is a tutorial that covers it in a bit more detail. I did change the firstName and lastName parameters from params to variables in the body. But you can either use params or body to get that data into your local strategy.
when making a request for the newUser args other params should be requested from the form body like so
newUser.local.fname = req.body.fname
I found that this worked better. It seemed to be key that the done be after the req, username, password but before the other variables your desired to pass into the function. If done was placed at the end then:
events.js:160 throw er; // Unhandled 'error' event TypeError: done is not a function
would be returned.
// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done, fname, lname, email, security_question, security_answer) {
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'local.username' : username }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if theres already a user with that email
if (user) {
return done(null, false, req.flash('signupMessage', 'That username is already taken.'));
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.local.fname = fname;
newUser.local.lname = lname;
newUser.local.username = username;
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
newUser.local.security_question = security_question;
newUser.local.security_answer = newUser.generateHash(security_answer);
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));