Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node - Passport Auth - Authed Post Route hangs on form submission

This is a weird one. Im Passport's 'Local Strategy' for my express app and i'm running into an odd issue.

Essentially, I have three routes. Each have an auth check in place.

app.get('/admin', authenticatedOrNot, adminRoute.index);
app.get('/admin/new', authenticatedOrNot, adminRoute.newpost);
app.post('/admin/new', authenticatedOrNot, adminRoute.create);

the authenticatedOrNot method is simply :

var authenticatedOrNot = function(req, res, next){
    if(req.isAuthenticated()){
        next();
    }else{
        res.redirect("/login");
    }
}

Works perfect for logging in to the admin area, and checking if a user is logged in, BUT when I submit a form to the '/admin/new' Post route, the browser hangs. Nothing happens in the console, even with console.log in place :

exports.create = function(req, res){
    console.log(req);
        // Database logic here
        res.redirect('/admin');
}

I cant seem to get it to work. It just hangs, and eventually fails. The browser console just says 'pending' in the network request.

Ive tried removing the 'authenticatedOrNot' method from the post route and same issue, but if I remove all three it works fine.

Im stumped.

Any help guys? Anyone else run into this?

like image 500
Warren Haskins Avatar asked Nov 12 '22 01:11

Warren Haskins


1 Answers

I had a problem very similar to this, so I'm posting this in case it helps out. The issue seemed to be that i had another function definition inside the passport function, and this was preventing the done handler from being called. I think that was the issue because when I changed the function argument names things started working.

In hindsight I think the error is obvious, but since I'm new to node I'm still a bit uncertain with functions, callbacks, closures, etc, etc. I also have the impression that the node convention is always to use these argument names (err, done, next) and that there is some magic associated with them. I guess not though. Feel free to educate me on this point.

Anyway, I was using a passport local strategy that I copied from a tutorial (at http://scotch.io/tutorials/javascript/easy-node-authentication-setup-and-local). The tutorial used mongo, but I decided to switch to postgresql. So I used the pg.js module from https://github.com/brianc/node-postgres-pure, and used the sample code provided.

Here's the relevant portion of the code, after I initially copied and pasted the pg.js sample code into the passport tutorial:

//Bad Code

passport.use('local', 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) { 
    pg.connect(configDB.connectionString, function(err, client, done) {
        if (err) {
            return console.error('could not connect to postgres', err);
        }
        client.query('select email, password_hash from admin_user where email = $1', [email], function(err, result) {

            // check password against db, and then try to call passports done callback
            return done(null, userModel); // this actually invokes the pg.connect done callback

        });
    });
}));

So when this ran, on the post back to /login, the call to done would invoke pg.connect done, not passport done.

// Good? working code

function(req, email, password, done) { 

    pg.connect(configDB.connectionString, function(err, client, connect_done) {
        if (err) {
            return console.error('could not connect to postgres', err);
        }
        client.query('select email, password_hash from admin_user where email = $1', [email], function(err, result) {
            connect_done() // free up postgres connection, which I should have been doing before
            // check password against db, and then
            return done(null, userModel); // invoke passport's done callback

        });
    });
}));

This code is now working for me (unless I mis-copied something).

like image 147
john Avatar answered Nov 15 '22 06:11

john