how to send json data under passport local strategy - node.js

This is my passport Login Handler.
Now I want to send JSON Data under every condition so that API can access the response and on behalf of this display anything on frontend.
//Login Handler
passport.use('local-user', new LocalStrategy(
function(username, password, done) {
User.getUserByUsername(username, function(err, user){
if(err) {
console.log('error')
logger.log('error', 'Error Generates on User.getUserByUsername Query on users.js file');
throw err;
}
if(!user){
//res.send('unknown user');
console.log('Unknown User');
return done(null, false, {message: 'Unknown User'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) {
logger.log('error', 'Error Generates on User.comparePassword Query on users.js file');
throw err;
}
if(isMatch){
return done(null, user);
}else{
return done(null, false, {message: 'Invalid Credential, please check carefully...!'})
}
});
});
}
));
Anyone have any idea for this? Thanks in advance

The local strategy will pass the user or error with done(), then you receive that with a callback and pack it with res.json()
Here is my implementation. May help?
passport.use(
new LocalStrategy(
{
usernameField: "email"
},
function(username, password, done) {
User.findOne({ email: username }, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, {
email: "Email not found"
});
}
if (!user.validPassword(password)) {
return done(null, false, {
password: "Password is wrong"
});
}
return done(null, user);
});
}
)
);
router.post("/login", function(req, res) {
passport.authenticate("local", function(err, user, info) {
if (err) {
res.status(404).json(err);
return;
}
if (user) {
const token = user.generateJwt();
res.status(200);
res.json({
userInfo: user,
token: token
});
} else {
res.status(401).json(info);
}
})(req, res);
});

Related

What is wrong with this ExpressJS + Passport signup route? It returns 400 Bad Request

I implemented a signup route below. It gets to "User saved..." but the request returns 404.
It doesn't seem to be executing the login strategy:
router.post("/signup", function(req, res, next) {
var email = req.body.email;
var password = req.body.password;
User.findOne({ email: email }, function(err, user) {
if (err) { return next(err); }
if (user) {
return res.status(409).send({message: "Duplicate user - already registered."});
}
var newUser = new User({
email: email,
password: password
});
newUser.save(next);
console.log("User saved...");
});
},
passport.authenticate("login"),
function(req, res) {
return res.status(200).send({
message: "Signup successful",
user: req.user
});
}
);
My Passport login strategy looks like this:
passport.use("login", new LocalStrategy(async (email, password, done) => {
console.log("login...");
User.findOne({ email: email }, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: "No user has that email!" });
}
user.checkPassword(password, function(err, isMatch) {
console.log("Checked password...");
console.log("Error? Match?");
console.log(err);
console.log(isMatch);
if (err) { return done(err); }
if (isMatch) {
console.log("Returning done...");
return done(null, user, { message: 'Logged in Successfully' });
} else {
return done(null, false, { message: "Invalid password." });
}
});
});
}));
Here's what I see in the logs:
User saved...
POST /signup 400 181.122 ms - -
Passport is likely throwing the 400 error because the username/password fields are not set.
Passport expects username and password and what you are passing are the email and password. So you can modify the code and let passport's LocalStrategy use the email as the username.
You can set the username and password as follows:
passport.use("login", new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
},async (usernameField, passwordField, done) => {
console.log("login...");
User.findOne({ email: usernameField }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: "No user has that email!" });
}
user.checkPassword(passwordField, function (err, isMatch) {
console.log("Checked password...");
console.log("Error? Match?");
console.log(err);
console.log(isMatch);
if (err) { return done(err); }
if (isMatch) {
console.log("Returning done...");
return done(null, user, { message: 'Logged in Successfully' });
} else {
return done(null, false, { message: "Invalid password." });
}
});
});
}));
You can check the line which was throwing the error from passport's source code here

Automatic failureRedirect in Passport

I have a problem with my code. When I am trying to login without insert username and password
POST /user/login 302 1.289 ms - 32
GET /user/hehehehehe 404 6.310 ms - 1272
If i try to login with only login it's the same result
If i try to login with username and password correct or incorrect
500 Internal Server Error
Can someone tell me, where the mistake is?? That is first load failureRedirect. What is first thing I should check after trying to login??
router.post('/create', function (req, res, next) {
var newUser = {
username: req.body.username,
password: req.body.password
}
console.log(req.body)
req.checkBody('username', 'Login is required').notEmpty();
req.checkBody('password', 'Password is required').notEmpty();
var errors = req.validationErrors();
if (errors) {
console.log(errors)
res.send(errors);
} else {
bcrypt.hash(newUser.password, saltRounds, function (err, hash) {
if (err) {
console.log(err)
} else {
newUser.password = hash;
var user = new User(newUser);
user.save()
.then(function (User) {
res.send(User);
})
}
});
req.flash('success_msg', 'You are registered and can now login');
//res.redirect('/');
}
});
passport.use(new LocalStrategy(
function(username, password, done) {
User.getUserByUsername(username, function(err, user){
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown User'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
passport.serializeUser( function(user, done) {
console.log('eheheheheh');
done(null, user.id);
});
passport.deserializeUser( function(id, done) {
User.getUserById(id, function(err, user) {
console.log('eheheheheh');
done(err, user);
});
});
router.post('/login',
passport.authenticate('local', { successRedirect:'hahahha', failureRedirect:'hehehehehe', failureFlash: true }),
function(req, res) {
console.log('yyy'),
res.redirect('dydydydy');
});
IMPORTANT
Which functions are loaded first?
1 - /login
Then this code?
passport.use(new LocalStrategy(
function(username, password, done) {
User.getUserByUsername(username, function(err, user){
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown User'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
What mistakes might be here??

Serialize different types of users in PassportJS

I have two local strategies for two different types of users: Students and Teachers. I am having trouble trying to login because my serialization is not working properly.
I have two models, Student and Teacher. Both have their separate collections, student and teacher with similar schema. Both have similar functions:
module.exports.getStudentByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
}
module.exports.getStudentById = function(id, callback){
User.findById(id, callback);
}
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
if(err) throw err;
callback(null, isMatch);
});
}
My two local strategies are:
passport.use('student-local', new LocalStrategy(
function(username, password, done) {
Student.getStudentByUsername(username, function(err, student){
if(err) throw err;
if(!student){
return done(null, false, {message: 'Unknown Student'});
}
Student.comparePassword(password, student.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, student);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
passport.use('teacher-local', new LocalStrategy(
function(username, password, done) {
Teacher.getTeacherByUsername(username, function(err, teacher){
if(err) throw err;
if(!teacher){
return done(null, false, {message: 'Unknown Teacher'});
}
Teacher.comparePassword(password, teacher.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, teacher);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
My two logins are:
router.post('/loginStudent',
passport.authenticate('student-local', {successRedirect:'/users/student', failureRedirect:'/login',failureFlash: true}),
function(req, res) {
res.redirect('/');
});
router.post('/loginTeacher',
passport.authenticate('teacher-local', {successRedirect:'/users/teacher', failureRedirect:'/login',failureFlash: true}),
function(req, res) {
res.redirect('/');
});
My serialization and deserialization are:
passport.serializeUser(function(user, done) {
if(Student.findOne({username: user.username}).length != 0) {
done(null, user.id);
} else if(Teacher.findOne({username: user.username}).length != 0) {
done(null, user.id);
}
});
passport.deserializeUser(function(id, done) {
if(Student.getStudentById(id)){
Student.getTeacherById(id, function(err, user) {
done(err, user);
});
} else {
Teacher.getTeacherById(id, function(err, user) {
done(err, user);
});
}
});
I know my serialization is wrong and that is why I am not being able to get this to work. When I tried with only one type of user and with the simpler serialization I found in the passport documents, my login was working fine.I am new with node and passport so any help would be highly appreciated.
I believe your serialization doesn't work, because the query for finding the teacher / student is actually async and you are treating it as sync.
passport.serializeUser(function(user, done) {
Student.findOne( { username: user.username }, function( err, student ) {
if ( student ) {
// user is student
done( null, user.id );
} else {
Teacher.findOne( { username: user.username }, function( err, teacher ) {
if ( teacher ) {
// user is teacher
done( null, user.id );
}
} );
}
} )
} );
This should work, although I'm not sure why you are doing to lookup for the type of user. You can just do :
passport.serializeUser(function(user, done) {
done(null, user.id);
} );

Passport local authentication is not working

I am building app using MEAN STACK. I want to use passport-local authentication for my login form. But a the time of form submission i am getting POST http://localhost/login 404 (Not Found) please have a look of my code below This is my controller:
lyfee.controller('loginCtrl', ['$scope', '$http', function($scope, $http) {
$scope.user = {};
$scope.login = function() {
// var data = {User: $scope.user }
//console.log($scope.user);
console.log("login function call");
$http.post('/login', $scope.user);
console.log("login request send");
}
}]);
and this is my server.js :
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.getUserByusername(username, function(err, user) {
if (err) throw err;
if (!user) {
return done(null, false, {
message: 'Unknown USER'
});
}
User.comparePassword(password, user.password, function(err, isMatch) {
if () throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, {
message: 'Invalid password'
});
}
});
});
}));
app.post('/login',
passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
}),
function(req, res) {
res.redirect('/');
});
in which file should i write getUserByusername and comparePassword function ? and what is mistake i am doing please correct it and give me some suggestion.
In your model suppose that User.js write functions like this:
/**
* Check the user's password
*/
dbSchema.methods.comparePassword = function(candidatePassword, cb) {
var status = this.password.localeCompare(candidatePassword.trim());
if (status != 0) {
return cb(err);
}
cb(null, true);
};
then use the function like this
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({
username: username
}, function(err, user) {
if (err) throw err;
if (!user) {
return done(null, false, {
message: 'Unknown USER'
});
}
/**
* Check the user's password
*/
User.comparePassword(password, user.password, function(err, isMatch) {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, {
message: 'Invalid password'
});
}
});
});
}));

Passport Authentication: chaining strategies

How do I run two or more passport strategies sequentially, meaning if one strategy comes up empty then run another one?
I tried doing this:
app.post('/', function (req,res,next){
passport.authenticate('strategy1', function (err, result1) {
if (err) { return next(err); }
if (!result1) {
passport.authenticate('strategy2', function (err,result2){
if (err) { return next(err); }
if(!result2){
return res.redirect('/');}
req.login(result2, function (err){
if(err){return next(err)}
res.render('result2');
})
});
}
req.login(result1, function (err){
if (err){return next(err)}
console.log('admin login found');
res.render('result');
});
})(req, res, next);
});
But am getting this error:
Error: Failed to serialize user into session
I have implemented:
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
I suspect the user was serialised in the first passport.authentication call and then it tried to serialise it again with the second one, and what I need to do is deserialise it again before running the second strategy.
Appreciate the help!
I ended up sticking to just one strategy but added logic to allow it to check several collections, as recommended in this answer.
passport.use('local', new LocalStrategy({
passReqToCallback : true
}, function(req, username, password, done) {
process.nextTick(function() {
collection1.findOne({'username': username}, function(err, collectionresult) {
if (err) {
return done(err);
}
if (!collectionresult) {
collection2.findOne({'username': username}, function(err, collection2result){
if (err) {
return done(err);
}
if (!collection2result) {
return done(null, false,req.flash('adminmessage','Invalid username or password'));
}
if (!collection2.validPassword(password)) {
return done(null, false,req.flash('adminmessage','Invalid username or password'));
}
console.log('local strategy has authenticated employee username and password! Returning employee');
return done(null, employee);
})
}
if (collection2result){
if (collection2result.password!=password) {
return done(null, false, req.flash('adminmessage','Invalid username or password' ));
}
else{
console.log('Local strategy has found an admin. Returning admin');
return done(null, collection2result)
}
}
});
}
);
}));

Resources