0

i am currently building a React application with Nodejs/Express Backend and try to implement a Login Authentication.

i register Users with Name, email, password and hash the password with bcrypt:

router.post('/register', async (req, res) => {
  
  // Hashing
  const salt = await bcrypt.genSalt(10)
  const hashedPassword = await bcrypt.hash(req.body.regpassword, salt)

  // Validate
  const {error} = Joi.validate(req.body, schema)

  var data = {
      regname: req.body.regname,
      regemail: req.body.regemail,
      regpassword : hashedPassword
  }
  var sql ='INSERT INTO Users (regname, regemail, regpassword) VALUES (?,?,?)'
  var params =[data.regname, data.regemail, data.regpassword]
  db.run(sql, params, function (err, result) {
      if (error){
          res.status(400).send(error.details[0].message);
          return;
      }
      res.json({
          "answer": "Success",
      })
      res.status(200)
  });
})

this works fine. But my /login route doesnt work:

  router.post('/login', (req, res, next) => {
    let sql = `SELECT * FROM Users WHERE regname = "${req.body.regname}" AND regpassword = "${req.body.regpassword}"`;
    var x;

    db.all(sql, (err, rows) => {
     if (err) {
       next(err);
       return;
     }
     if (!rows) {
       res.status(400);
       res.send('Invalid username or password');
       return
     }
     rows.forEach( async (row) => {
       if (row.regname === req.body.regname && await bcrypt.compare(req.body.regpassword, row.regpassword) ) {
           x = 1;
       }
       else {
           x = 2;
           db.close();
       }
     })
     if (x === 1) {
      res.json({
        "answer":"Success",
     })
     }
     else { 
       res.json(
         {"answer":"Denied",
     }) 
     }
    })
  })
luk2302
  • 55,258
  • 23
  • 97
  • 137
Antihero
  • 21
  • 1

2 Answers2

0

The salt needs to be stored in the database as well.
The /login route must then retrieve the regpassword and the salt from the database based on the req.body.regname. It then needs to run a await bcrypt.hash(req.body.regpassword, salt) exactly identical to the /register route and then compare the result of that hashing operation with the regpassword from the database. If the two hashes match then the user provided the correct password and you can display some confirmation / issue some session token / ...

luk2302
  • 55,258
  • 23
  • 97
  • 137
0

i share my solution here, if someone needs it:

  router.post('/login', (req, res) => {
    const  regname  =  req.body.regname;
    const  regpassword  =  req.body.regpassword;
    const  findUserByName  = (regname, cb) => {
      return  db.get(`SELECT * FROM Users WHERE regname = ?`,[regname], (err, row) => {
              cb(err, row)
      });
  }
    findUserByName(regname, (err, user)=>{
        if (err) return  res.status(500).send('Server error!');
        if (!user) return  res.status(404).send('User not found!');
        const  result  =  bcrypt.compareSync(regpassword, user.regpassword);
        if(!result) return  res.status(401).send('Password not valid!');

        res.status(200)
        res.json({
          "answer":"Success",
        })

    });
});
Antihero
  • 21
  • 1
  • Where has the salting gone? That is a ***critical*** piece of password storage! How about you instead implement the solution from my answer. – luk2302 May 16 '21 at 19:33
  • @luk2302 bcrypt stores the salt as part of the token it generates, so it doesn't have to be stored separately in the database. Antihero is using bcrypt exactly as it was designed to be used. See this SO answer for a more detailed explanation: https://stackoverflow.com/a/6833165/1411506 – Siobhán Apr 29 '23 at 21:29