Search code examples
expresspassport-local

How to isolate or fix no-response (browser hang) after calling passport.authenticate as middleware


I'm trying to use passport.authenticate('local') as middleware with passport-local-mongoose but it doesn't seem to pass control to the subsequent middlewares in my route.

I'm assuming there's an error but the following (err, req, res, next) middleware isn't being called so I'm wondering if I've misunderstood something basic about passport-local in general.

I've spent a few hours trying various things, searching here but I can't find a way to isolate my problem any further or get a better log of where control is going wrong in my route.

I've posted a small reproducible example to GitHub.

This is how I'm setting up BEFORE my routes:

// Get connected
mongoose.connect('mongodb://localhost/pass');
mongoose.Promise = global.Promise;
mongoose.connection.on('error', (err) => { console.error(err.message) });

// Basic user schema using nickname field as username
const Schema = mongoose.Schema;
const userSchema = new Schema({});
userSchema.plugin(passportLocalMongoose, { usernameField: 'nickname' });
const User = mongoose.model('User', userSchema);

// Initialise passport before routes
passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser);
passport.deserializeUser(User.deserializeUser);
app.use(passport.initialize());

And this is the route with my passport.authenticate:

app.post('/login',
    (req, res, next) => {
        console.log('login posted ok');
        next();
    },
    passport.authenticate('local'),
    (req, res) =>  res.send('login successful'),
    (err, req, res, next) => {
        console.log(err);
        res.send('login unsuccessful');
    }
);

There are other routes with the pug views and registration.

Registration works fine, in mongo db.users.find() show a good looking entry for the new user.

But my /login post route doesn't get beyond passport.authenticate.

The console.log gets triggered, so I know the route is being called.

Based on my limited knowledge of express and passport, I'm expecting one of those two following middlewares to be triggered, one on success and one if it fails.

Neither is triggering.


Solution

  • Best way to isolate is covered in the authenticate docs under "Custom Callback", I just didn't understand it originally.

    NOTE: I've saved the following in the answer branch on my repo, as posted in the question.

    app.post('/login',
        (req, res, next) => {
            console.log('login posted ok');
            next();
        },
        (req, res, next) => {
            console.log('authenticating...')
            passport.authenticate('local', (err, user, info) => {
                console.log(req, res, err, user, info);
                next(err);
            }) (req, res, next);
        },
        (req, res) =>  res.send('login successful'),
        (err, req, res, next) => {
            console.log(err);
            res.send('login unsuccessful');
        }
    );
    

    What I realised

    • passport doesn't consider authentication FAIL as an err
    • it just leaves user null
    • basically you need to give it success and failure redirects if you want to use middleware form, don't do what I did and try to handle err etc.