Passport local returns error 400 bad request with Angular

All we need is an easy explanation of the problem, so here it is.

I am trying to integrate passport to my code’s login form. Client side calling server side works as it should until i call passport.authenticate in the request, 400 Bad Request was returned. What am I missing here.

HTML

        <div>
            <div class="row">
                <div class="input-field col s12">
                    <input id="user-email" type="text" ng-model="user.email">
                    <label for="user-email">Your email address</label>
                </div>
            </div>
            <div class="row">
                <div class="input-field col s12">
                    <input id="user-password" type="password" ng-model="user.password">
                    <label for="user-password">Your password</label>
                </div>
            </div>
            <div id="login-button-panel" class="center-align">
                <button class="btn" id="login-btn" ng-click="vm.login(user);">Login</button> 
            </div>
            <div class="section center">
                <a class="modal-trigger">Forgot password?</a>
            </div>
        </div>

JS

$http.post('/api/login',user).success(function(result){
    console.log(result)
})

server.js

passport.use(new LocalStrategy(
    function(username, password, done) {
        return done(null, false, {message:'Unable to login'})
    }
));
passport.serializeUser(function(user,done){
    done(null,user);
});

passport.deserializeUser(function(user,done){
    done(null,user);
});
app.post('/api/login', passport.authenticate('local'), function(req,res){
    res.json(req.user)
});

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Bad Request was thrown by passport for missing access on username and password.

It is checking body and URL query for fields username and password. If either is falsy the request is rejected with status 400.

On creating your LocalStrategy you may pass set of options in additional argument to constructor choosing differently named fields using options usernameField and/or passwordField. In your particular case this would look like this:

passport.use(new LocalStrategy(
    {usernameField:"user-email", passwordField:"user-password"},
    function(username, password, done) {
        return done(null, false, {message:'Unable to login'})
    }
));

Method 2

In my case (Express 4.0), I wasn’t using body-parser

Method 3

This error also comes from trying to access the request payload without using body-parser

Use –

var parser = require('body-parser');
var urlencodedParser = parser.urlencoded({extended : false});


    app.post("/authenticate", urlencodedParser, passport.authenticate('local'), function (request, response)
    {           
        response.redirect('/');                      
    });

Method 4

passport.use(new LocalStrategy(
    {
        usernameField: 'email',
        passwordField: 'password'
    },
    function (email, password, done) {
        db.collection('User').findOne({ email: email }, async function (err, user) {
            console.log('user requested password caught in passport', password);
            if (err) { return done(err); }
            if (!user) { return done(null, false); }
            const matchPassword = await comparePassword(password, user.password);
            if (!matchPassword) { return done(null, false); }
            return done(null, user);
        });
    }
));

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply