8

I'm trying to build logging application in node JS. in here password authentication app do not work properly. when i enter username and password it occur following error and stop server.

this is the error.

enter image description here

Here is the code for authentication part

passport.use(new LocalStrategy(
function(username, password, done) {
    User.getUserByUsername(username, function(err, user){
       if(err) throw err;
       if (!user) {
           return done(null, false, {message: 'Unknown user'});
       } 

       User.comparePassword(password, user.password, function(err, isMatch){
           if(err) throw err;
           if (isMatch) {
               return done(null, user);
           } else {
               return done(null, false, {message: 'Invalid password'});
           }
       });
    });
}));

This code work for Unknown user. but it is not working for comparing username and password. i cannot see any bug in here. i want a help for solve this.

4
  • 3
    What are the values of password and user.password when you call .comparePassword()? It looks like it's complaining that user.password is undefined. Commented Jul 2, 2017 at 13:25
  • "password" is user input value for login. "user.password" is value that stored in database. according to the username it refers for password and compare with value that user entered. Commented Jul 2, 2017 at 13:57
  • OK. What is the value of user.password? Commented Jul 2, 2017 at 13:59
  • I found the problem. there are same username stored in the database. thats why it occur error. Because it will be a problem for authenticating and compare passwords. because it has to compare same username with many password. I should validate that also. thank you for your attention. Commented Jul 2, 2017 at 14:26

11 Answers 11

5

In my case i forgot to select the password because in database the password was ((select: false))

this code for app

const user = await User.findOne({email}).select("+password")

i forgot to append the ((.select("+password")))to the findOne

and I received this error ; Error: Illegal arguments: string, undefined

and this code for database

const User = new mongoose.Schema({
    username:{
        type:String,
        required: [true,"نام کاربری ضروری است"]
    },
    email:{
        type:String,
        required: [true,"رایانامه ضروری است"],
        unique: true,
        match:[
            /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{1,3})$/,
            "لطفا یک رایانامه صحیح وارد کنید"
        ]
    },
    password:{
        type:String,
        required:[true,"رمز ضروری است"],
        minlegth: 5,
        select: false
    }
})
Sign up to request clarification or add additional context in comments.

1 Comment

.select("+password") Work's for me, cuz in my model User i have password: select:false Thanks.
2

I found the problem in here. it is not things regarding the code.

The thing is i had registered two users with same user name and different password. then when i tried to login with the user name and one password it occurred this error and stop the server.

Because there is embarrassing situation with find password to username that user entered. because there are two password with same username.

1 Comment

How did you deal with that problem ?
1

In my case, I'm using social signin/signup. When the user is signing up using a social login option, the value of the password stored is "NULL".

So I just added this little check :

  comparePassword: function(password, user){
    if (!user.password)
      return false;
    return bcrypt.compareSync(password, user.password);
  }

Comments

1

In my case, I was using arrow function

userSchema.methods.comparePassword = async (enterdPassword) => {
  return await bcrypt.compare(enterdPassword, this.password);
};

which I converted to normal function

userSchema.methods.comparePassword = async function (enterdPassword) {
  return await bcrypt.compare(enterdPassword, this.password);
};

that solved the problem

Comments

0

At

"models/user.js"

Inside comparePassword

module.exports.comparePassword = (candidatePassword, hash, callback) => {...) 

Add this code:

bcrypt.hash(candidatePassword, 10, (err, hash) => {
    if(err) {
        throw err;
    }
    bcrypt.compare(candidatePassword, hash, (err, isMatch) => {
        if(err) {
            throw err;
        }
        callback(null, isMatch);
    });
});

Comments

0

Here We are grabbing username and password from the sign in page AND finding our user by the username from the database and then Matching its encrypted password with an entered password by the user

passport.use(new LocalStrategy(
    (username,password,done)=> {
        db.users.findOne({username: username},(err, user)=> {
            if(err) return done(err);

            if(!user) {
                return done(null,false,{message: 'Incorrect Username'});
            }
            bcrypt.compare(password, user.password,(err,isMatch)=> {
                if(err) return done(err);
                if(isMatch) {
                    return done(null, user);
                } else {
                    return done(null, false,{message: 'Incorrect Password'});
                }
            });
         });
      }
   ));

Comments

0

You need to apply await to your salt and password assignments too.

Like this,

const salt = await bcrypt.genSaltSync(10);
const password = await req.body.password;

Comments

0

You can write a code like this: After this.findOne({ select: [] ........}) ... I hope this is helpful

async validateUserPassword(loginDto: AuthLoginDto): Promise<User> {
    const { mobile, email, password } = loginDto;
    const user = await this.findOne({
      select: ['id', 'email', 'mobile', 'password', 'salt', 'status', 'logged_at'],
      where: [
        { mobile: mobile },
        { email: email }
      ]

    });

    if (user && await user.validatePassword(password)) {
      const logged_at = {
        logged_at: new Date()
      }
      await this.update({ id: user.id }, logged_at)
      return user;
    } else {
      return null;
    }
  }
  
  async validatePassword(password: string): Promise<boolean> {
    const hash = await bcrypt.hash(password, this.salt);
    return hash === this.password;
  }

Comments

0

In my own case , I just want to check if the old password matches the password in Db but got the error , here is my code below:

changePassword = asyncHandler (async (req: IGetUserAuthInfoRequest, res: Response) => {
  const user = await User.findById(req.user._id)
  const {oldPassword, password} = req.body

  if(!user) {
    res.status(400)
    throw new Error("User not found, please signup")
  }

  // Validate
  if(!oldPassword || !password) {
    res.status(400)
    throw new Error("Please add old and new password")
  }

  // Check if old password matches password in DB
  const passwordIsCorrect = await bcrypt.compare(oldPassword, user.password)

  // Save new password
  if(user && passwordIsCorrect) {
    user.password = password
    await user.save()
    res.status(200).send("Password change successful")
  } else {
    res.status(400)
    throw new Error("Old password is incorrect")
  }

});

2 Comments

If this is a question, please post it as a new one, instead of an answer to existing question. Cheers.
I fixed it , I added .select("+password") to where I got the user by id
0

for my case I havn't gave "await" keyword when I was writing code to connect to database and find the password, so I got the same error

router.post("/login", async function (req, res) {

  const userdata = req.body;
  const enteredEmail = userdata.email;
  const enteredPassword = userdata.password;

  const existingUser =await db
      .getDb()
      .collection("users")
      .findOne({ email: enteredEmail });

  if (!existingUser) {
    console.log('Could not log in!')
    return res.redirect('/login')
  }

  const passwordsAreEqual = await bcrypt.compare(enteredPassword, 
existingUser.password);

  if (!passwordsAreEqual) {
    console.log("Could not log in! Incorrect Password");
    return res.render('/login')

  }
  console.log('User is authenticated');
  res.redirect('/admin');
  });

Comments

0

Simple Solution:

1: Go to your model and check for, select property. If true or false.

2: If it is false, then you need to manually query it.

Example:

Suppose password field in our model look like this.

// using mongoose
const userShema = new mongoose.Schema({
// All other fields
password: {
    type: String,
    select: false, // By default not selected. Require manual query
  },
});

// Rest of the stuff

Now getting this password along with other data.

  // Find user by id and also select the password field in the result
  const user = await User.findById(req.user.id).select("+password");
  
 // log it
 console.log(user.password);

 // rest...

Note: User proper async await & try catch.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.