SulTan
SulTan

Reputation: 201

TypeError: done is not a function

I'm using passport.js for the authentication and handling of sessions in my project.

I use email to authenticate from passport but when the done is called on verification, I get the error done is not a function.

at Promise.<anonymous> (/Users/sultan/Desktop/too2/controllers/users.js:39:28)
at Promise.<anonymous> (/Users/sultan/Desktop/too2/node_modules/mongoose/lib/promise.js:120:8) 

Code

  // LOCAL LOGIN =============================================================
passport.use('local-login', new LocalStrategy({
    usernameField : 'email',
    passwordField : 'password'
    //passReqToCallback : true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function( email, password, done) {
    if (email)
        email = email.toString().toLowerCase();

    // asynchronous
    process.nextTick(function() {
        User.findOne({ email:  email }, function(err, user) {
            // if there are any errors, return the error
            if (err)
                return done(err);

            // if no user is found, return the message
            if (!user)
        //(/Users/sultan/Desktop/too2/controllers/users.js:39:28)
                return done(null, false, {message: 'No user found.'});

            if (!user.validPassword(password))
                return done(null, false, {message: 'Oops! Wrong Password'});

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

}));

What is the cause of this error and how do I resolve it?

Upvotes: 3

Views: 22500

Answers (3)

SulTan
SulTan

Reputation: 201

this worked for me

passport.use('login', new LocalStrategy({
        // by default, local strategy uses username
        usernameField : 'email',
        passwordField : 'password',
        passReqToCallback : true
    },
    function(req, email, password, done) {
        if (email) email = email.toLowerCase();

        // asynchronous
        process.nextTick(function() {
            User.findOne({ 'email' :  email }, function(err, user) {
                // if there are any errors, return the error
                if (err)
                    return done(err);

                // if no user is found, return the message
                if (!user)
                    return done(null, false, req.flash('loginMessage', 'No user found.'));

                if (!user.validPassword(password))
                    return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));

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

    }));

Upvotes: 2

Boris
Boris

Reputation: 1291

It might come from you wrapping your code into process.nextTick()

If you want to have an asynchronous call to verify your user you could use promises instead like @Damien Gold answer. I can't test it but something like the below might work.

If Users.findOne() is not thenable you could use deferred promise or promisification (let me know I can adjust my answer with sample code)

let promise = require('bluebird'); // or any other promise library

passport.use('local-login', new LocalStrategy({
    usernameField : 'email',
    passwordField : 'password'
    //passReqToCallback : true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function( email, password, done) {
    if (email)
        email = email.toString().toLowerCase();

        // not sure which db driver you are using but most implement promises now

        Let defer = promise.defer();

        User.findOne({ email:  email }, function(err, user) {
            if (err) { return defer.reject(err); }

             return defer.resolve(user);
        });

        defer.promise
        .then(function(user) {
            // if no user is found, return the message
            if (!user)
                return done(null, false, {message: 'No user found.'});

            if (!user.validPassword(password))
                return done(null, false, {message: 'Oops! Wrong Password'});

            // all is well, return user
            else
                return done(null, user);
        }).catch(function(err) {
            // if there are any errors, return the error
            return done(err);
        });
    });
}));

Upvotes: 0

Damien
Damien

Reputation: 1610

I am currently working on a node.js project that requires user authentication. Below is the code in my passport.js file. It should work for you. In case, you don't want to use the node package connect-flash, you can replace req.flash with {message:...}.

 var bCrypt = require('bcrypt-nodejs');
 var db = require("../models");
 module.exports = function(passport) {
   var user = db.User;
   var User = user;
   var LocalStrategy = require('passport-local').Strategy;


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


   // used to deserialize the user
   passport.deserializeUser(function(id, done) {
     User.findById(id).then(function(user) {
       if (user) {
         done(null, user.get());
       } else {
         done(user.errors, null);
       }
     });

   });


   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, email, password, done) {


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

       User.findOne({
         where: {
           email: email
         }
       }).then(function(user) {

         if (user) {
           return done(null, false, req.flash('signupMessage', 'That email is already taken'));

         } else {
           var userPassword = generateHash(password);
           var data = {
             email: email,
             password: userPassword,
             firstname: req.body.firstname,
             lastname: req.body.lastname
           };


           User.create(data).then(function(newUser, created) {
             if (!newUser) {
               return done(null, false, req.flash('userExist', 'You are already registered. Please sign in!'));
             }

             if (newUser) {
               return done(null, newUser, req.flash('userCreated', 'You are now registered and logged in!'));
             }

           });
         }

       });

     }

   ));

   //LOCAL SIGNIN
   passport.use('local-signin', 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) {

       var User = user;

       var isValidPassword = function(userpass, password) {
         return bCrypt.compareSync(password, userpass);
       }

       User.findOne({
         where: {
           email: email
         }
       }).then(function(user) {

         if (!user) {
           return done(null, false, req.flash('signinError', 'Email does not exist'));
         }

         if (!isValidPassword(user.password, password)) {

           return done(null, false, req.flash('passwordError', 'Incorrect password.'));
         }

         var userinfo = user.get();

         return done(null, userinfo);

       }).catch(function(err) {

         console.log("Error:", err);

         return done(null, false, req.flash('genError', 'Something went wrong with your Signin'));

       });

     }
   ));
 }

Upvotes: 1

Related Questions