Unable to show flash message from Passport.js - node.js

I'm having problem with sending a flash if authentication fails. Except that everything is OK. When I'm copying example (https://github.com/jaredhanson/connect-flash) to my app flash messages are working fine...
Here is my code:
//routes
app.get('/login', function (req,res){
res.render('login', {
authMessage: req.flash('authMessage')
});
});
app.post('/login', passport.authenticate('local', {
failureRedirect: '/login',
failureFlash: true
}), function(req,res){
res.send('ok');
});
//local strategy
passport.use(new LocalStrategy(
function(username, password, authCheckDone) {
UserDetails.findOne({username : username}).then(
function(user){
if (!user) {
console.log('bad username');
return authCheckDone(null, false, {authMessage: 'Wrong name'});
}
if (user.password !== password) {
console.log('bad password');
return authCheckDone(null, false, {authMessage: 'Wrong password'});
}
return authCheckDone(null, user);
}),
function(error){
return authCheckDone(error);
};
}
));
//ejs
<% if (authMessage.length > 0) { %>
<p>test</p>
<%= authMessage %>
<% } %>
I've read somewhere this problem may be related with security and not using https, but if that would be the case example from github wouldn't work either...

If I am not wrong, the callback you pass to LocalStrategy should have as first parameter the request object. So your function would look like this:
function(req, username, password, authCheckDone) {
// your code
After that, according to an example that I have, you should return the result of authCheckDone in the following way:
return authCheckDone(null, false, req.flash('authMessage', "your message"));
But make sure you create the LocalStrategy object in the following way:
new LocalStrategy({
passReqToCallback: true // don't forget this
}, function(req, username, password, authCheckDone) {

Related

Passport.js change default error message

I'm using Passport.js for authentication in my node/express app, when input fields are empty passport displays default message "Missing credentials", how can i change that? to say something like please fill the form or something
here my local strategy for login:
passport.use('login', new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},
function(email, password, done) {
models.User.findOne({where: {email}}).then(user => {
if (!user)
return done(null, false, {message: 'Email not registered'});
user.checkPassword(password).then(res => {
if (!res)
return done(null, false, {message: 'Incorrect username or password'});
return done(null, user);
});
});
}));
login route:
router.post('/login', passport.authenticate('login', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
}));
I got it, looks like i can pass optional callback to authenticate function to override default functionality, thanks oneturkmen for reference.
here's modified route:
router.post('/signup', (req, res) => {
passport.authenticate('signup', (err, user, info) => {
const body = req.body;
if (req.body.username === '' || req.body.email === '' || req.body.password === '')
info.message = 'Please fill the form';
req.logIn(user, err => {
if (err) res.render('users/signup', info);
else res.redirect('/');
});
})(req, res);
});
An alternative is to add "badRequestMessage" to your code
Your code will look like this
router.post('/login', passport.authenticate('login', {
successRedirect: '/',
failureRedirect: '/login',
badRequestMessage : 'Please fill the form',
failureFlash: true
}));

Check if user exists in passport-local

I have an Express app with the passport-local strategy, using Mongoose for storing user Accounts. I had a freelancer write this part of the app for me because I couldn't make sense of how to build the login system from beginning to end (every single tutorial I found did it in a different way). The drawback of this is that I don't understand what each part does. This is in my app.js file:
const Account = require('./models/db/AccountsSchema');
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(Account.authenticate()));
passport.serializeUser(Account.serializeUser());
passport.deserializeUser(Account.deserializeUser());
and this is in routes/index.js:
router.post('/register', function(req, res) {
Account.register(new Account({
username: req.body.username,
name: req.body.name
}), req.body.password, function(err, account) {
if (err) {
console.log(err);
} else {
console.log(account);
passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login'
})(req, res, function(err, user) {
res.redirect('/');
});
}
});
});
along with:
router.post('/login',
passport.authenticate('local'),
function(req, res) {
res.redirect('/');
}
);
Now in the login POST request I want to have a check for whether a user with that particular username exists, so that if the password is wrong at least I can tell the user that the password is wrong. User enumeration is not a security concern here.
Where in my code can I incorporate a database check for whether an Account with the specified username exists?
In Account.authenticate() function. As it sets the LocalStrategy in your case.
setting your local strategy:
passport.use(new LocalStrategy(Account.authenticate()));
Sample Code:
function authenticate(username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}

How to handle thrid parameter of function "done" in passport.js?

I saw the example code at http://passportjs.org/docs that we can pass third parameter for done function of passport
Code:
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
In this case they are passing { message: 'Incorrect username.' }.
My question is how to handle this third parameter.
EDIT:
This is my routing code:
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
});
I want to know how to use message that send from passport like
res.render('myjade', {'message': **THAT MESSAGE**})
something like this
From the docs:
Redirects are often combined with flash messages in order to display status information to the user.
Setting the failureFlash option to true instructs Passport to flash an error message using the message given by the strategy's verify callback, if any.
Note: Using flash messages requires a req.flash() function. Express 2.x provided this functionality, however it was removed from Express 3.x. Use of connect-flash middleware is recommended to provide this functionality when using Express 3.x.
So modify your call to authenticate to be:
passport.authenticate('local', {
failureRedirect: '/login',
failureFlash: true
}),
and then either use the connect-flash middleware or define your own middleware to provide the req.flash() function.

Node.js Passport Authentification through Apache-Redirect Proxy

I'm building a node.js application with an integrated passport-account system. Since I'm hosted on uberspace.de, I need to configure my .htaccess in the main web-root like so:
RewriteEngine On
RewriteRule ^(.*) http://localhost:34457/$1 [P]
My express-route for login is: (Accessible at /api/auth/login)
router.post('/login', passport.authenticate('login', {
successRedirect: '/account',
failureRedirect: '/login?error=true'
}));
As how I understand Passport, if a successful login was performed, I should be redirected to /account and if not, to /login?error=true.
But if I perform a POST by using
url --data "email=foo#bar.com&password=test" http://[domain]/api/auth/login
the result is:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>502 Proxy Error</title>
</head><body>
<h1>Proxy Error</h1>
<p>The proxy server received an invalid
response from an upstream server.<br />
The proxy server could not handle the request <em>POST /api/auth/login</em>.<p>
Reason: <strong>Error reading from remote server</strong></p></p>
<hr>
<address>Apache/2.2.15 (CentOS) Server at [domain] Port 80</address>
</body></html>
And if I execute the same query by a html-form (Method: POST, Action: /api/auth/login) in Chrome, I get redirected to /api/auth/login%5E (which obivously returns a 404).
Simple redirects like this one work:
router.post('/redirectToHome', function(req, res, next) {
res.redirect(302, '/');
});
But even if I perform this function when calling /api/auth/login
router.post('/login', function(req, res, next) {
passport.authenticate('login', function(err, user, info) {
if (err) return next(err);
if (!user) {
console.log(info);
return res.json(401, {success: false});
} else {
console.log(info);
return res.json(200, {success: true});
}
})(req, res, next);
});
I will still get redirected to /api/auth/login%5E.
My authentification-strategy for login is implemented as:
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({
usernameField: 'email',
passReqToCallback : true
}, function(req, email, password, done) {
// check in mongo if a user with username exists or not
User.findOne({ 'email' : email },
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 email '+email);
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);
}
}
Even if the login-router is written as follows:
router.post('/login', function(req, res, next) {
passport.authenticate('login', function(err, user, info) {
if (err) return next(err);
if (!user) {
console.log(info);
return res.json(401, {success: false});
} else {
console.log(info);
return res.json(200, {success: true});
}
})(req, res, next);
});
I still get redirected to /api/auth/login%5E.
My passport login-strategy is implemented like so:
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({
usernameField: 'email',
passReqToCallback : true
}, function(req, email, password, done) {
// check in mongo if a user with username exists or not
User.findOne({ 'email' : email },
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 email '+email);
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);
}
}
What is the problem?
Actually, my problem was some invisible character, that redirected me to some other page, which then made a bunch of other things go wrong.

Node.js passport pass postdata on to failureRedirect

This is driving me crazy!
I'm using Express 4, passport and local-passport to authenticate login and signup.
I'm using this example:
https://github.com/tutsplus/passport-mongo
Problem:
When the signup form does not validate (say you forgot one of the fields) and we redirect to the failureRedirect (which is the same signup page), all the entered values are gone. Not a very good user experience that you have to fill out the entire form because you messed up a single field.
How do I pass the already entered data on the the form?
I got these two routes handing the GET and POST of the form:
app.get('/signup', function(req, res){
res.render('signup', {
message: req.flash('message'),
});
});
app.post('/signup', passport.authenticate('signup', {
successRedirect: '/signup-complete',
failureRedirect: '/signup', // need to pass the entered values (if any) back to the signup page
failureFlash : true
}));
I have a nagging suspicion that the values are already there - I just don't know how to grab them.
I'm using Swig for the views btw.
Did you add connect-flash middleware to your app?
var flash = require('connect-flash');
app.use(flash());
Update:
When you define your local strategy, you should return the flash messages in the third parameter of the done function. Example:
passport.use(new LocalStrategy(
function(username, password, done) {
findByUsername(username, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false, { message: 'Unknown user ' + username }); }
if (user.password != password) { return done(null, false, { message: 'Invalid password' }); }
return done(null, user);
})
});
}
));

Resources