PassportJS: serializeUser() Can't set headers after they are sent - javascript

I am simply trying to serialise the user in passportjs following the "normal" flow. However I keep getting the following error:
Error: Can't set headers after they are sent.
I don't understand where I could send the res since I am just using the middleware to send it. Here is how I call the authentication route:
routes.post('/signup', function(req, res, next) {
passport.authenticate('local-signup-sme', {
successRedirect : req.get('origin') + '/dashboard', // redirect to the secure profile section
failureRedirect : req.get('origin') + '/signupSME', // redirect back to the signup page if there is an error
failureFlash : true,
successFlash : 'User created !'
})(req, res, next)
});
and here is my local-signup-sme, i only call done() and I only call it once, or in a callback, I have checked if there was any if without an else but I can't find any...
What am I doing wrong ?
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.use('local-signup-sme', 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 (typeof _password === 'undefined' ){
return done(null, false, {message: 'Password field is missing'})
} else if( typeof _email === 'undefined'){
return done(null, false, {message: 'Email field is missing'})
} else {
var password = bcrypt.hashSync(_password, bcrypt.genSaltSync(10)); //encrypt password and store the hash...
var companySelected = JSON.parse(req.body.companySelected);
if (!req.user) {
checkCompanyRegistrationStatus(companySelected.company_number,
function(){
checkUserRegistrationStatus(_email,
function(){
checkPasswordStrength(_password,
function(){
maindb.MainDBInsert("INSERT INTO Uncomplete_Users_Registrations (first_name, last_name, password, email, company_registrat_number, company_name) OUTPUT Inserted.id VALUES (?, ?, ?, ?, ?, ?);",
[req.body.firstName, req.body.lastName, password, _email, companySelected.company_number, companySelected.title],
function(user, rowsCount){
return done(null, user[0]);
},
function(code, err){
return done(null, false, {message: err});
}
);
}, function (err) {
return done(null, false, {message: err});
})
}, function(err){
return done(null, false, {message: err})
}
)
}, function(err){
return done(null, false, {message: err})
}
)
}, function(err){
return done(null, false, {message: err})
}
)
} 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);
}
}
}));

Related

Passport.js BasicStratagy retuns unauthorized to logged in user in a Rest API

I am working on a Rest API with Passport.js. after I log in and use a secured endpoint, I get "unauthorized" as a response. what is more confusing is that after I call the log in function, I get a valid user. here is Passport config:
passport.use(new BasicStrategy({
usernameField: 'email',
passwordField: 'password'
},
function(email, password, done) {
console.log("Email: ", email)
console.log("password: ", password)
User.findOne({ email: email }, function (err, user) {
if (err) { return done(err) }
if (!user) { return done(null, false) }
if (!bcrypt.compare(password, user.password)) { return done(null, false) }
return done(null, user);
})
}
))
I used the following middle ware code to secure it: passport.authenticate('basic', {session: false})

passport authentication: user undefined after login

I am trying to authenticate user ,when i try to login user after successful verification using req.logIn but it doesn't worked
router.post('/login', function(req, res, next) {
passport.authenticate('login',function (cb,data) {
//user verfication success
if(data){
req.logIn({user:"shamon"},function(err,result){
console.log("result",result,err)
res.send('login success');
});
}
})(req,res,next);
});
this console.log("result",result,err) gives me undefined,undefined
when i log req.user after logged i got undefined error
UPDATE
var LocalStrategy = require('passport-local').Strategy
module.exports = function(passport){
passport.use('local',new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},function (username,password,done) {
console.log('inside passport');
return done(null,true);
}));
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null,user);
});
}
Just grab my implementation of password local-strategy. This is working for sure, but you will need to slightly modify it:
The strategy:
// Serialize
passport.serializeUser(function (user, done) {
done(null, user.id);
});
// Deserialize
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
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 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.findOne({ 'local.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)
return done(null, false, req.flash('loginError', 'No such user found.')); // req.flash is the way to set flashdata using connect-flash
// if the user is found but the password is wrong
if (!user.validPassword(password))
return done(null, false, req.flash('loginError', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashd
// all is well, return successful user
return done(null, user);
});
}
));
And the route:
router.post('/login', function(req, res, next) {
passport.authenticate('local-login', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.send({alert: req.flash('loginError')});
}
req.logIn(user, function(err) {
if (err) {
return next(err);
}
return res.send({redirect: '/'});
});
})(req, res, next);
});

Node.js Passport failed to deserilize user

My node.js app has two passport local strategies. One for back office users and another for guests. Both strategies query two different tables for authenticating their respective users.
Below is the passport.js code
var isOfficeUser = false;
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
if(isOfficeUser == true){
done(null, user.idSystemUser);
} else {
done(null, user.idGuests);
}
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
var userQuery;
if(isOfficeUser == true) {
userQuery = 'SELECT idSystemUser, Name, Email, Phone, (select IsGuest from SystemProfiles where idSystemProfile = ProfileId) as GuestFlag FROM SystemUsers WHERE idSystemUser = ? ';
} else {
userQuery = 'SELECT idGuests, Name, Email, RoomId, GuestsCount, Phone, RoomNo, ' +
'(select DATE_FORMAT(CheckInDT, \'%b %d %Y %h:%i %p\')) as CheckInDTString, ' +
'(select DATE_FORMAT(CheckOutDT, \'%b %d %Y %h:%i %p\')) as CheckOutDTString, ' +
'(select IsGuest from SystemProfiles where idSystemProfile = ProfileId) as GuestFlag ' +
'FROM Guests WHERE idGuests = ? ';
}
connectionPool.getConnection(function(err, connection){
if (err) {
winston.log('debug', '------------------------------------ Error: ' + err);
return;
}
connection.query(userQuery,[id],function(err, rows){
if(err) {
winston.info('info', '----------------------- ERROR: ' + err);
}
done(err, rows[0]);
connection.release();
});
});
});
//this stretegy is for guests
passport.use(
'guest',
new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'room',
passwordField : 'accesskey',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, room, accesskey, done) {
isOfficeUser = false;
connectionPool.getConnection(function(err, connection){
if(err) {
winston.log('debug', '------------------------------------ Error: ' + err);
return;
}
connection.query('SELECT idGuests, Name, Email, RoomId, RoomNo, GuestsCount, Phone FROM Guests WHERE RoomNo = ? and AccessKey = ?',[room, accesskey], function(err, rows){
connection.release();
if(err) {
return done(err);
}
if(!rows.length) {
return done(null, false, {message : {active : true, text : 'Incorrect Credentials'}});
}
// all is well, return successful user
return done(null, rows[0]);
});
});
})
);
//this stretegy is for office user
passport.use(
'office',
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) {
isOfficeUser = true;
connectionPool.getConnection(function(err, connection){
if(err) {
winston.log('debug', '------------------------------------ Error: ' + err);
return;
}
connection.query('SELECT idSystemUser, Name, Active, Email, ProfileId, Phone, Password FROM SystemUsers WHERE Email = ?',[email], function(err, rows){
connection.release();
if(err) {
return done(err);
}
if(!rows.length) {
return done(null, false, {message : {active : true, text : 'Incorrect Credentials'}});
}
//if the user access is revoked
if(rows[0].Active == 0) {
return done(null, false, {message : {active : true, text : 'Your administrator has revoked your access to portal. Please contact your Administrator to get this resolved.'}});
}
// if the user is found but the password is wrong
if(!bcrypt.compareSync(password, rows[0].Password)) {
return done(null, false, {message : {active : true, text : 'Incorrect Email or Password'}});
}
// all is well, return successful user
return done(null, rows[0]);
});
});
})
);
However, for some reason I get signed out of my session and it shows the error:
"failed to deserialize user out of session"
I have to refresh the browser and relogin but then after sometime it logs me off again.
What am I doing wrong here?

Verification email with token in passport.js

I just looking for solution which makes verification email with token for my local autentification in passport.js
Is there some plugin or component for node which can make me verification easyer? Or I have to do it myself?
My controller
exports.postSignup = function(req, res, next) {
req.assert('email', 'Email is not valid').isEmail();
req.assert('password', 'Password must be at least 4 characters long').len(4);
req.assert('confirmPassword', 'Passwords do not match').equals(req.body.password);
var errors = req.validationErrors();
if (errors) {
req.flash('errors', errors);
return res.redirect('/signup');
}
var user = User.build({
email: req.body.email,
password: req.body.password,
});
User
.find({ where: { email: req.body.email } })
.then(function(existingUser){
if (existingUser) {
req.flash('errors', { msg: 'Account with that email address already exists.' });
return res.redirect('/signup');
}
user
.save()
.complete(function(err){
if (err) return next(err);
req.logIn(user, function(err){
if (err) return next(err);
res.redirect('/');
});
});
}).catch(function(err){
return next(err);
});
};
Thanks for any opinion!
Implementing this yourself is pretty straightforward.
The pseudocode:
//A user registers
//User is stored along with a random token string and a variable set to false
//User is sent a verification email
//Verification email has a link with the random token and a unique ID for that user
//Link goes to a route that takes the token as a parameter
//Match the user and the random token
//If they match - change a variable to verified
The package I use to generage the random string is:
https://www.npmjs.com/package/randomstring
Local signup strategy
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) {
console.log('that email exists');
return done(null, false, req.flash('signupMessage', email + ' is already in use. '));
} else {
User.findOne({'local.username': req.body.username}, function (err, user) {
if (user) {
console.log('That username exists');
return done(null, false, req.flash('signupMessage', 'That username is already taken.'));
}
if (req.body.password != req.body.confirm_password) {
console.log('Passwords do not match');
return done(null, false, req.flash('signupMessage', 'Your passwords do not match'));
}
else {
// create the user
var newUser = new User();
var permalink = req.body.username.toLowerCase().replace(' ', '').replace(/[^\w\s]/gi, '').trim();
var verification_token = randomstring.generate({
length: 64
});
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
newUser.local.permalink = permalink;
//Verified will get turned to true when they verify email address
newUser.local.verified = false;
newUser.local.verify_token = verification_token;
try {
newUser.save(function (err) {
if (err) {
throw err;
} else {
VerifyEmail.sendverification(email, verification_token, permalink);
return done(null, newUser);
}
});
} catch (err) {
}
}
});
}
});
});
}));
I use a combination of /permalink/random-token for the verification URL
The route should look like this:
app.get('/verify/:permaink/:token', function (req, res) {
var permalink = req.params.permaink;
var token = req.params.token;
User.findOne({'local.permalink': permalink}, function (err, user) {
if (user.local.verify_token == token) {
console.log('that token is correct! Verify the user');
User.findOneAndUpdate({'local.permalink': permalink}, {'local.verified': true}, function (err, resp) {
console.log('The user has been verified!');
});
res.redirect('/login');
} else {
console.log('The token is wrong! Reject the user. token should be: ' + user.local.verify_token);
}
});
});

passport js check for error in req

I am logging in a user with passport local:
// route to log in
app.post('/login', passport.authenticate('local-login'), function(req, res) {
res.send(req.user);
});
This will only work in the case of success, i.e. when req.user is defined. How do I check for an error in the request? Essentially I want to take the error that was pulled from my passport authentication code in the done() call and send that back to the client to display the proper error message:
passport.use('local-login', new LocalStrategy({
username : 'email',
password : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
console.log('logging in user: ' + email);
// 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
Landlord.findOne({ 'local.email' : email }, function(err, user) {
if (err) return done(err);
if (!user) return done(null, false, { message: 'Incorrect username.' });
if (!user.validPassword(password)) {
console.log('wrong pw');
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}));

Categories

Resources