Steven Klinger
Steven Klinger

Reputation: 284

Res.json is not a function (passport.js)

Today i'm coming with a brand new problem ! First, I have two important files :

passport.js local signup part

passport.use('local-signup', new LocalStrategy({
        usernameField: 'email',
        passwordField: 'password',
        passReqToCallback: true // allows us to pass back the entire request to the callback
    },

    function(req, res) {
        var password = req.body.password;
        var email = req.body.email;

        var generateHash = function(password) {
            return bCrypt.hashSync(password, bCrypt.genSaltSync(8), null);
        };

        User.find({
            where: {
                email: email
            }
        }).then(function(user) {
            if (user) {
                return res.json('That email is already taken');

            } else {
                var userPassword = generateHash(password);
                var data = {
                    username: req.body.username,
                    name: req.body.name,
                    firstname: req.body.firstname,
                    email: req.body.email,
                    location: req.body.location,
                    type: req.body.type,
                    password: userPassword
                };

                db.users.create({
                    username: data.username,
                    name: data.name,
                    firstname: data.firstname,
                    email: data.email,
                    location: data.location,
                    type: data.type,
                    password: data.password
                }).then(newUser => {
                    return res.json(newUser)
                });
            }
        });
    }
));

I'm doing an authentification part. First, I want to create an account and to use passport for it : the signup.

I'm also using Sequelize to manage my datamodels. But when i'm calling this localStrategy with a POST request (with my body all ok in postman) I have this error :

Unhandled rejection TypeError: res.json is not a function on the line return res.json(newUser)

Somebody can help me please? Note that done() is not working because of passReqToCallback (but I need this to get my password and email)

Upvotes: 0

Views: 855

Answers (3)

Osama Bari
Osama Bari

Reputation: 598

you are passing a string in req.json. you need to use req.send for string. Example:

replace this line:

 return res.json('That email is already taken');

to

return res.send('That email is already taken');

if you want to sen JSON then use this one.

return res.json({msg:'That email is already taken'});

or use this condition

if (req.xhr) { return res.json({msg:'That email is already taken'}) }

Upvotes: 1

Md Ashiqur Rahman
Md Ashiqur Rahman

Reputation: 464

You can be a little confused but passport doesn't implement signup methods. It's just authorisation library. So you must handle that use-case on your own.

First of all, create route that will be responsible for sign-up and your checks:

app.post('/signup', (req, res) => {

    User.findOne({ $or: [{'local.email': req.body.email},{'local.username': req.body.username}]}, function(err, user){
        if(err){
            return res.send(err);
        }
        if(user){
            if(user.local.email == req.body.email){
                return res.send("This email is already taken.")
            }
            return res.send("This username is already taken.")

        }
        else{
            var userData = new User();

            userData.local.name = req.body.name;
            userData.local.email = req.body.email;
            userData.local.username = req.body.username;
            userData.local.password = req.body.password;

            userData.save()
                .then(item => {
                    res.send("item saved to database")
                    // `req.user` contains the authenticated user.
                    //res.redirect('/profile/' + req.body.username);
                })
                .catch(err => {
                    console.log(err);
                    res.status(400).send("unable to save to database");
                })

                }
            })

})  

The example above is based on express framework, but you can fit it with no problems to your own case.

Next step is include passport local strategy. // load all the things we need var LocalStrategy = require('passport-local').Strategy;

// load up the user model var User = require('../models/user');

// expose this function to our app using module.exports module.exports = function(passport) {

// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and unserialize users out of session

// used to serialize the user for the session
passport.serializeUser(function(user, done) {
    done(null, user.id);
});

// used to deserialize the user
passport.deserializeUser(function(id, done) {
    User.findById(id, function(err, user) {
        done(err, user);
    });
});


// =========================================================================
// LOCAL LOGIN =============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'

passport.use('local-login', 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) { // callback with email and password from our form

    // find a user whose email is the same as the forms email
    // we are checking to see if the user trying to login already exists
    User.findOne({ 'local.email' :  email }, function(err, user) {
        // if there are any errors, return the error before anything else
        if (err)
            return done(err);

        // if no user is found, return the message
        if (!user)
            return done(null, false, {message: 'User not found.'}); // req.flash is the way to set flashdata using connect-flash
        // if the user is found but the password is wrong
        if (!user.validPassword(password))
            return done(null, false, {message: 'Incorrect password.'}); // create the loginMessage and save it to session as flashdata

        // all is well, return successful user
        return done(null, user);
    });

}));

};

We have only signin task now. It's simple.

app.post('/login', function(req, res, next) {
    passport.authenticate('local-login', function(err, user, info) {
      if (err) { return next(err); }
      if (!user) { return res.send(info.message); }
      req.logIn(user, function(err) {
        if (err) { return next(err); }
        return res.send(user.local.username);
      });
    })(req, res, next);
  });

Upvotes: 2

Aritra Chakraborty
Aritra Chakraborty

Reputation: 12542

Passport localStrategy doesn't have res in the callback. It's req, username, password and done. Here is an example.

passport.use('local-signup', new LocalStrategy({
    usernameField : 'email',
    passwordField : 'password',
    passReqToCallback : true
},
function(req, email, password, done) {
    // request object is now first argument
    // ...
  }
));

Upvotes: 1

Related Questions