Sakib
Sakib

Reputation: 1543

Validating captcha along with passport.js

Is it possible to verify if google recaptcha succeeded before calling passport.js authenticate function?

I'm getting stuck between choosing one or the other because both use asynchronous callbacks to verify and I can't next them within each other.

    function verifyRecaptcha(key, rq, rs, pa, callback) {
    https.get('https://www.google.com/recaptcha/api/siteverify?secret=' + SECRET + '&response=' + key, function (res) {
        var data = '';
        res.on('data', function (chunk) {
            data += chunk.toString();
        });
        res.on('end', function () {
            try {
                var parsedData = JSON.parse(data);
//                    return true;
                callback(parsedData.success, rq, rs, pa);
            } catch (e) {
//                    return false;
                callback(false, rq, rs, pa);
            }
        });
    });
}

    app.post('/auth/signin', can_access.if_not_logged_in(), passport.setupLocalStrategy(),
    function (req, res) {
        console.log('HERE');

        verifyRecaptcha(req.body['g-recaptcha-response'], function (success) {
            if (success) {
                // find a way to signal captcha succeeded.
                return true;
            } else {
                res.end('Captcha failed, sorry.');
                // TODO: take them back to the previous page
                // and for the love of everyone, restore their inputs
                return false;
            }
        });
    },
    passport.authenticate('local', {
        successRedirect: '/',
        failureRedirect: 'auth/signin',
        failureFlash: true
    }));

I want to do authentication after captcha has succeeded

Upvotes: 1

Views: 2217

Answers (1)

laggingreflex
laggingreflex

Reputation: 34667

The way Express middlewares or route handlers work is that they are executed in succession, one after another, as long as the previous one called next()

So you just need to call next() from your captcha verifying middleware so that your passport.authenticate middleware which comes next can be executed.

Also, if you call next(err) (i.e. passing it an Error) it will skip all the middlewares and go straight to the next middleware that has the 4 argument signature (err, req, res, next), which is usually the main error handler placed at or near the end in your routes/middlewares.

So simply try changing your code to this:

app.post('/auth/signin', can_access.if_not_logged_in(), passport.setupLocalStrategy(),
function (req, res, next) { // <<-- 1. have next passed here
    console.log('HERE');

    verifyRecaptcha(req.body['g-recaptcha-response'], function (success) {
        if (success) {
            // find a way to signal captcha succeeded.
            return next(); // <<-- 2. call next(); 
        } else {
            res.end('Captcha failed, sorry.');
            // TODO: take them back to the previous page
            // and for the love of everyone, restore their inputs
            return false;
        }
    });
},
// this will only be invoked if next() was called from previous middleware 
passport.authenticate('local', {
    successRedirect: '/',
    failureRedirect: 'auth/signin',
    failureFlash: true
}));

Upvotes: 3

Related Questions