Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passport-local returns 400 error, never queries database

I'm trying to use passport.js in my node.js app to authenticate a user with MongoDB. I never hit success.

In the post, I send "email": "[email protected]", "password": "test"

var passport = require('passport')
   , LocalStrategy = require('passport-local').Strategy;


app.post('/login',
  passport.authenticate('local', { successRedirect: '/',
                               failureRedirect: '/fail' })
);

passport.use(new LocalStrategy({
      emailField: 'email',
      passwordField: 'passw',
   },
function (emailField, passwordField, done) {
   process.nextTick(function () {
      db.collection(users, function (error, collection) {
         if (!error) {
            collection.findOne({
               'email': emailField,
               'password': passwordField
            }, function (err, user) {
               if (err) {
                  return done(err);
               }
               if (!user) {
                  console.log('this email does not exist');
                  return done(null, false);
               }
                  return done(null, user);
            });
         } else {
            console.log(5, 'DB error');
         }
      });
   });
}));

In MongoDB 'users' collection:

{
    "_id": {
        "$oid": "533b5283e4b09d8a1148b4c4"
    },
    "email": "[email protected]",
    "password": "test"
}

Maybe I am not connecting to the database right, I'm not sure.

Also, when I log all throughout the function, I don't get ANY logs. I simply get

 POST /login 302 7ms - 39b  
 GET /fail 404 3ms

Any suggestions would be greatly appreciated. I think I may be missing something but I'm not sure exactly how to structure this. In the other function where I'm writing to the database I have to use:

var uristring = 
process.env.MONGOLAB_URI || 
process.env.MONGOHQ_URL || 
'mongodb://<myurlhere>';

mongo.connect(uristring, function (err, db) {

Here is the updated code

requiring these:

   , passport = require('passport')
   , LocalStrategy = require('passport-local').Strategy;

using these:

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(express.session({ secret: 'keyboard cat'}));
app.use(logfmt.requestLogger());
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);

// User authentication passport

passport.use(new LocalStrategy(
    {
        usernameField: 'email',
        passwordField: 'passw',
    },
    function (userId, password, done) {
        // removed process.nextTick
        console.log('Hey! no more 400 error!');
        db.collection(users, function (error, collection) {
            if (!error) {
                collection.findOne({
                    'email': userId,
                    'password': password
                }, function (err, user) {
                    if (err) {
                        return done(err);
                    }
                    if (!user) {
                        console.log('this email does not exist');
                        return done(null, false);
                    }
                    return done(null, user);
                });
            } else {
                console.log(5, 'DB error');
            }
        });
    } 
));

passport.serializeUser(function(user, done) {
  done(null, user);
});

passport.deserializeUser(function(user, done) {
  done(null, user);
});

app.post('/login', passport.authenticate('local'), function(req, res) {
   console.log('SUCCESS WOOOO');
   // If this function gets called, authentication was successful.
   // `req.user` contains the authenticated user.
   //res.redirect('/users/' + req.user.username);
  });

This code always gives me POST /login 400 10ms when posting to /login. All my other routes work fine.

like image 849
Joel Avatar asked Apr 02 '14 03:04

Joel


1 Answers

1) The dreaded HTTP 400 error

Passport throws an HTTP 400 error when the username and/or password are not set.

See the source around line 75 where Strategy.prototype.authenticate throws a 'missing credentials' error.

2) Diagnosing the cause

In your code, you have the block:

passport.use(new LocalStrategy({
      emailField: 'email',
      passwordField: 'passw',
   },

But emailField isn't recognized by passport. Back in the source code, we see that passport is looking for:

this._usernameField = options.usernameField || 'username';
this._passwordField = options.passwordField || 'password';

This is why the HTTP 400 is being thrown in this specific situation.

4) Fixing the problem

I've edited your original code to what I believe will work (better) than the original. I took some liberty when editing to remove the process.nextTick and renamed a few things. I hope you are a forgiving person. :)

passport.use(new LocalStrategy(
    {
        usernameField: 'email',
        passwordField: 'passw',
    },
    function (userId, password, done) {
        // removed process.nextTick
        console.log('Hey! no more 400 error!');
        db.collection(users, function (error, collection) {
            if (!error) {
                collection.findOne({
                    'email': userId,
                    'password': password
                }, function (err, user) {
                    if (err) {
                        return done(err);
                    }
                    if (!user) {
                        console.log('this email does not exist');
                        return done(null, false);
                    }
                    return done(null, user);
                });
            } else {
                console.log(5, 'DB error');
            }
        });
    } 
));

5) Some closing notes:

  • You could also edit the form input attributes to match passport's expected defaults. See the passport documentation for guidance.
  • I can't guarantee the MongoDB call will work, but this should get you past the HTTP 400. If the database call has issues, that's almost certainly a new question because a different set of code and modules are involved.
  • When using passport, it's worth visiting the project GitHub page and reading through the source. There are often comments in the source that (a) aren't in the other docs or (b) are close to the code they describe...so things are clarified for you even if you aren't a coding guru or whatever.
like image 173
Matthew Bakaitis Avatar answered Sep 24 '22 14:09

Matthew Bakaitis