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);
});
Related
So I am trying to create a signup/login logic for my website using passport and bcrypt-nodejs for password hashing. I am successful at registering a user, but then on login I always get into the 'false' branch for password authentication and am getting my console message for 'Wrong Password' Here is my login passport code:
passport.use('user-local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
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.findOne({ 'email' : email }, function(err, user) {
// if there are any errors, return the error before anything else
if (err)
return done(err);
// if no user is found, return the message
if (!user) {
console.log('No user found.');
return done(null, false, req.flash('loginMessage', 'No user found.')); // req.flash is the way to set flashdata using connect-flash
}
bcrypt.compare(password, user.password, function(err, res) {
if (err)
throw err;
if(!res) {
console.log('Ooops!. Wrong Pass!');
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata
}
return done(null, user);
});
});
}));
And here is my signup logic
passport.use('user-local-signup', new LocalStrategy({
usernameField : 'email',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function (req, email, password, done) {
// asynch
// User.findOne will not fire unless data is sent back
process.nextTick(function() {
User.findOne({'email' : email}, function (err, user) {
if(err)
return done(err);
if(user) {
console.log('That email is already taken');
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else {
// checks for password and repeat_password match
if (password != req.body.repeat_password) {
console.log('Passwords do not match.');
return done(null, false, req.flash('signupMessage', 'Passwords do not match.'));
}
var newUser = new User();
newUser.email = email;
bcrypt.hash(password, null, null, function(err,hash){
if (err)
throw err;
else {
newUser.password = hash;
}
});
newUser.save(function(err) {
if(err)
throw err;
return done(null, newUser);
});
console.log('New user was created: ' + email);
}
});
});
}));
I've been searching stackoverflow for reasons why my node.js (express) app hangs on some posts with passport.js.
I've been looking at theese two questions:
More Passport.js woes - hangs on form submission
Passport (local) is hanging on Authentication
My code for creating a user works fine, and looks like this:
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) {
if (email)
email = email.toLowerCase(); // Use lower-case e-mails to avoid case-sensitive e-mail matching
// asynchronous
process.nextTick(function() {
// if the user is not already logged in:
if (!req.user) {
User.findOne({
where: {
local_email: email
}
}).then(function(user) {
if (user){
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
}else{
// create the user
User
.build({
local_email: email,
local_password: generateHash(password),
id: 1 //Normal activated user
})
.save()
.then(newUser => {
//Our newly crated user
return done(null, newUser);
})
.catch(error =>{
//Woops something went wrong
return done(error);
})
//var newUser = new User();
//newUser.localemail = email;
//newUser.localpassword = generateHash(password);
//User.create(newUser).then(function(newUser, created) {
// if (!newUser) {
// return done(err);
// }
// if (newUser) {
// return done(null, newUser);
// }
//});
}
});
// if the user is logged in but has no local account...
} else if ( !req.user.local.email ) {
// ...presumably they're trying to connect a local account
// BUT let's check if the email used to connect a local account is being used by another user
User.findOne({
where: {
localemail: email
}
}).then(function(user) {
if (err)
return done(err);
if (user){
return done(null, false, req.flash('loginMessage', 'That email is already taken.'));
// Using 'loginMessage instead of signupMessage because it's used by /connect/local'
} else {
// create the user
var newUser = new User();
newUser.local.email = email;
newUser.local.password = generateHash(password);
User.create(newUser).then(function(newUser, created) {
if (!newUser) {
return done(err);
}
if (newUser) {
return done(null, newUser);
}
});
}
});
} else {
// user is logged in and already has a local account. Ignore signup. (You should log out before trying to create a new account, user!)
return done(null, req.user);
}
});
}));
In my routs file the post to that function looks like this:
// 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
}));
My code for signing in however dosen't work that well. The function in passport.js looks like this:
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) {
if (email)
email = email.toLowerCase(); // Use lower-case e-mails to avoid case-sensitive e-mail matching
// asynchronous
process.nextTick(function() {
User.findOne({
where: {
local_email: email
}
}).then(function(user){
console.log("TEST: "+user);
// if no user is found, return the message
if (!user){
console.log("no user with the following email: " +email);
return done(null, false, req.flash('loginMessage', 'No user found.'));
}else if(!validPassword(password,user.local_password)){
console.log("wrong password");
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
// all is well, return user
}else{
return done(null, user);
return;
}
}).catch(function(err){
console.log("woops der skete en fejl: "+err);
console.log("email is: "+email);
console.log("password is: "+password);
return done(err);
});
});
}));
The corresponding route looks like this:
// process the login form
app.post('/login', passport.authenticate('local-login', {
successRedirect : '/', // redirect to the secure profile section
failureRedirect : '/login', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
The above code hangs when the form is being submitted. If I changes the code to:
app.post('/login', function(req, res, next) {
passport.authenticate('local-login', function(err, user, info) {
if (err) { return next(err); }
if (!user) {
return res.render('/login', {
pageTitle: 'Sign in',
form: req.body
});
}
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/');
});
})(req, res, next);
});
I receive an 500.
Any ideas why this isen't working?
Updated with console output:
Executing (default): SELECT `id`, `role`, `local_email`, `local_password`, `facebook_id`, `facebook_token`, `facebook_email`, `facebook_name`, `twitter_id`, `twitter_token`, `twitter_displayname`, `twitter_username`, `google_id`, `google_token`, `google_email`, `google_name`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`local_email` = 'test#local' LIMIT 1;
TEST: [object SequelizeInstance:users]
POST /login 302 87.021 ms - 46
Executing (default): SELECT `id`, `role`, `local_email`, `local_password`, `facebook_id`, `facebook_token`, `facebook_email`, `facebook_name`, `twitter_id`, `twitter_token`, `twitter_displayname`, `twitter_username`, `google_id`, `google_token`, `google_email`, `google_name`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`id` = 1;
Updated with changed passport.deserializeUser
passport.deserializeUser(function(id, done) {
/*User.findById(id, function(err, user) {
done(err, user);
});*/
User.findById(id).then(user => {
if (!user){
done(null);
}else{
done(user);
}
})
});
Your passport.deserializeUser isn't correct. As with all Node.js callbacks, the first argument is reserved for errors, and should be null (or another falsy value) if there aren't any errors. In your case, you're passing user as first argument, which makes Passport think there was an error.
Try this:
passport.deserializeUser(function(id, done) {
User.findById(id)
.then(user => done(null, user))
.catch(done);
});
I currently have a login up and running using Passport in my Node and Express project. Right now I have a users collection that gets the username and password and logs in fine. However, I have 2 separate user types (nurse and doctor) all which have similar fields with the exception of about 4 fields that are different. I'm not sure how to approach implementing 2 different users with the login. Is it best to just have all under users collection with different fields or should I have a separate collection for both users? and if so how would I implement this?
I'm not sure what code to post that can help other than my login code for passport
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user');
var bCrypt = require('bcrypt-nodejs');
module.exports = function(passport){
passport.use('login', new LocalStrategy({
passReqToCallback : true
},
function(req, username, password, done) {
// check in mongo if a user with username exists or not
User.findOne({ 'username' : username },
function(err, user) {
// In case of any error, return using the done method
if (err)
return done(err);
// Username does not exist, log the error and redirect back
if (!user){
console.log('User Not Found with username '+username);
return done(null, false, req.flash('message', 'User Not found.'));
}
// User exists but wrong password, log the error
if (!isValidPassword(user, password)){
console.log('Invalid Password');
return done(null, false, req.flash('message', 'Invalid Password')); // redirect back to login page
}
// User and password both match, return user from done method
// which will be treated like success
return done(null, user);
}
);
})
);
var isValidPassword = function(user, password){
return bCrypt.compareSync(password, user.password);
}
}
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);
}));
};
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