Warren Haskins
Warren Haskins

Reputation: 67

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?

Upvotes: 5

Views: 1525

Answers (2)

john
john

Reputation: 11

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).

Upvotes: 1

zelibobla
zelibobla

Reputation: 1508

Diagnostic of such a trouble become much more easy when you split more and more and more... Best approach is to use some sniffer (built in Chrome, Firefox, Opera or standalone) and get exactly the headers you sent on to your server. This is very useful since you can localize trouble to frontend app (<form acton="/admin/new" – mistype for example) or backend.

Lets apologize your headers are okay and you send exactly POST at /admin/new route. Since your console.log( req ); does not take effect obviously application does not come to this point. This could be because authenticatedOrNot hangs or because adminRoute.create is not instantiated correctly.

authenticatedOrNot could hang on /login redirection as I see, since you did not provide the way how you handle this route.

adminRoute.create could cause some troubles depending on the way you attached it into your app.

So in resume I need to see more of your code to establish the trouble.

Upvotes: 0

Related Questions