Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to show custom error messages using passport and express

I check if the email already exist when registering a user. If a user already exist I pass the error message "email already exists". But in the front end it shows "Unauthorized" error 401. I want to pass the error message which I pass to the front end from the back end but it pass the default message. below is how I check if a user already exist and send the error message,

exports.register = new LocalStrategy({
    usernameField: 'email',
    passReqToCallback: true
}, function(req, email, password, done,res) {
    var newUser = new User({
        email: email,
        password: password,
        name: req.body.fname
    });
    var searchUser = {
        email: email
    };
    User.findOne(searchUser, function(err, user) {
        if (err) return done(err);
        console.log("err "+err);

        if (user) {
            return done(null, false, {
                message: "email already exists"
            });
        }
        newUser.save(function(err) {
        console.log("newUser "+newUser);
            done(null, newUser);
        })
    });
});

I use passport for authentication,

authRouter.post('/signup', passport.authenticate('local-register'),function(req, res) {
    createSendToken(req.user, res);
});

The error message is not the one I pass to the front end. It shows unauthorized error, which is the default error. When I print the error message in the console in front end it shows,

Object {data: "Unauthorized", status: 401, config: Object, statusText: "Unauthorized"}
like image 373
shamila Avatar asked Feb 17 '16 09:02

shamila


People also ask

How do I pass additional parameters to passport authenticate?

You can use the request itself to transfer some additional parameters from and to the strategy function. In the following example the two parameters _toParam and _fromParam are used for this concern. app. get('/auth/facebook/:appId', function(req,res,next){ req.

How do you use failureFlash?

failureFlash: true In this case when you call done(null, false, {type: 'info', message: 'my message'}) passport will take the type and message and use it to call req. flash(type, message) , if you don't specify a type then passport will default to the error flash.

What is passport strategy?

Passport's local strategy is a Node. js module that allows you to implement a username/password authentication mechanism. You'll need to install it like any other module and configure it to use your User Mongoose model.


3 Answers

You are not saying what output you want in your front end, but I'm guessing you want to have data to be the message that you set in your LocalStrategy.

Here is one way to do that:

authRouter.post('/signup', function(req, res, next) {
  passport.authenticate('local-register', function(err, user, info) {
    if (err) { return next(err); }
    if (!user) { 
        res.status(401);
        res.end(info.message);
        return;
    }
    createSendToken(req.user, res);
  })(req, res, next);
});
like image 151
bolav Avatar answered Oct 25 '22 05:10

bolav


You can take advantage of passReqToCallback: true in passport.

With this option enabled, req will be passed as the first argument to the verify callback.

Also by taking advantage of flash messages.

Here is basic example of how you use it,

// your strategy
passport.use(new LocalStrategy({
    passReqToCallback: true
  },
    (req, username, password, done) => {
      User.findOne({ username: username }, (err, user) => {
        if (err) done(err)
        if (!user) {
          console.log('user does not exists')
          return done(null, false, req.flash('message', 'User does not exist' ))
        } else {
          console.log('user exists')
          return done(null, user, req.flash('message', 'User exist'))
        }
      })
    }
  ))

// your GET login
router.get("/login", (req, res) => {
  var message = req.flash('message')
  res.render("pages/login", { message })
})
like image 43
Hasan Sefa Ozalp Avatar answered Oct 25 '22 06:10

Hasan Sefa Ozalp


As mentioned in other answers you can manually check the info parameter and then return your own message based on that:

// ❌ MESSY ❌
authRouter.post('/signup', function(req, res, next) {
    passport.authenticate('local-register', function(err, user, info) {
        if(info.name === 'UserExistsError' ) {
            return done(null, false, {
                message: "Email already exists"
            });
        } else if (info.name === 'IncorrectUsernameError') {
          return done(null, false, {
              message: "Email does not exist"
          });
        } else if(....

But A MUCH cleaner way is to just specify custom error messages when you create the Account Mongoose model:

var Account = new Schema({
    ...
});

var options = {
    errorMessages: {
        UserExistsError: 'Email already exists',
        IncorrectUsernameError: 'Email does not exist',
        IncorrectPasswordError: ...
    }
};

Account.plugin(passportLocalMongoose, options);

Then in your signup route you can simply return the info.message to the user.

// ✨ CLEAN ✨
authRouter.post('/signup', function(req, res, next) {
    passport.authenticate('local-register', function(err, user, info) {
        return done(null, false, {
            message: info.message
        });
    });
});
like image 1
toinetoine Avatar answered Oct 25 '22 04:10

toinetoine