starleaf1
starleaf1

Reputation: 2872

Display flash messages with Passport.js

I'm having trouble displaying flash messages while using Passport.js in Express 4. The Passport.js local strategy documentation shows how to set the flash message, but not much about how to actually display it.

Here's how I've been doing it.

passport.use(new auth(function (username, password, done) {
    con.query(query.login, [username], function(err, rows) {
        if (err) {
            done(err);
        }
        if (rows.length != 1) {
            console.log('Login attempted for ' + username);
            return done(null, false, {message: "Wrong username/password"});
        }
        user = rows[0];
        bcrypt.compare(password, user.passwordHash, function (err, correct) {
            delete user.passwordHash;
            if (correct) {
                return done(null, user);
            } else {
                console.log('Login attempted for ' + username);
                return done(null, false, {message: "Wrong username/password"});
            }
        })
    });
}));

app.get('/login', function(req, res) {
    var pageParameters = {};
    var flash = req.flash('message');
    // console.log(flash);
    if (flash != null && flash != '') {
        pageParameters.message = flash;
    }
    res.render('login', pageParameters);
});

app.post('/login', passport.authenticate('local', {
    failureRedirect: '/login',
    failureFlash: true
}), function (req, res) {
    req.session.user = req.user;
    if (typeof req.session.redirect !== 'undefined') {
        res.redirect(req.session.redirect);
        delete req.session.redirect;
    } else {
        res.redirect('/');
    }
});

There's no error, the console isn't telling me anything about the flash being undefined. console.log(flash) shows nothing. How do display the flash?

Upvotes: 3

Views: 4070

Answers (2)

z2lai
z2lai

Reputation: 61

Yeah, passport's documentation on its interaction with connect-flash definitely needs an update because it's misleading (I'm not sure how to go about making a suggestion to them).

When you pass the object with the message to the strategy's verify callback like this: return done(null, false, {message: "Wrong username/password"}); Passport is actually setting the 'error' message in connect-flash instead of the 'message' message - in other words, passport probably executes this in the background: req.flash('error', info.message) where info is {message: "Wrong username/password"}. So you should be doing var flash = req.flash('error') instead to retrieve the message.

Note: If the username or password passed to your local strategy is null, passport will internally set the 'error' message in connect-flash with the message, "Missing Credentials". So, IMO, it's a good idea for you to also set messages on the same 'error' property of connect-flash to keep it consistent with passport's built-in behaviour. However, if you wanted to set messages in your local strategy on a different property like 'message', you can explicitly set it using the connect-flash setter like so: req.flash('message', yourMessage).

How I found this out was simply logging the session object to view the flash object and all its messages after passport authentication because setting a flash message (with req.flash()) also creates a flash object on the session object (assuming you have properly set up sessions with express and passport). So console.log(req.session) will show you the flash object and all the messages it contains.

Note: Once you use the getter to retrieve the flash messages like so: req.flash('error'), the flash object is removed from the session object, so make sure to console log the session object before retrieving the flash messages.

Side note: You can set as many flash 'error' messages as you want and it will just append it to the 'error' array:

req.flash('error', 'Error #1')
req.flash('error', 'Error #2')
console.log(req.flash('error')) // returns ['Error #1', 'Error #2']

Upvotes: 3

ArkadiBernov
ArkadiBernov

Reputation: 578

Working project see hire

var express = require('express');
var router = express.Router();

var isAuthenticated = function (req, res, next) {
    // if user is authenticated in the session, call the next() to call the next request handler 
    // Passport adds this method to request object. A middleware is allowed to add properties to
    // request and response objects
    if (req.isAuthenticated())
        return next();
    // if the user is not authenticated then redirect him to the login page
    res.redirect('/');
}

module.exports = function(passport){

    /* GET login page. */
    router.get('/', function(req, res) {
        // Display the Login page with any flash message, if any
        res.render('index', { message: req.flash('message') });
    });

    /* Handle Login POST */
    router.post('/login', passport.authenticate('login', {
        successRedirect: '/home',
        failureRedirect: '/',
        failureFlash : true  
    }));

    /* GET Registration Page */
    router.get('/signup', function(req, res){
        res.render('register',{message: req.flash('message')});
    });

    /* Handle Registration POST */
    router.post('/signup', passport.authenticate('signup', {
        successRedirect: '/home',
        failureRedirect: '/signup',
        failureFlash : true  
    }));

    /* GET Home Page */
    router.get('/home*', isAuthenticated, function(req, res){
//      console.log("get home :" + req.session.cookie.name);
        res.render('home', { user: req.user });
    });

    /* Handle Logout */
    router.get('/signout', function(req, res) {
        req.logout();
        res.redirect('/');
    });

    return router;
}

Upvotes: 1

Related Questions