skip to Main Content

I am trying to create a login functionality for my Reactjs Webiste using Nodejs express backend.

I want to set a JWT token when the user tries to log in and update that token in my mongoDB database and then verify the token on the frontend and save it to localStorage.

However, when the user tries to log in after registration, it returns back the result without the token, and thus not allowing the user to log in, unless he clicks the login button again, then my code would generate and update the user with the JWT token.

Why is this behavior happening? Why is the first response only returning the found user from the findOne() operation when i am resolving the result from the findOneAndUpdate operation?

Here is my code:

Auth Controller:

login(params) {
    params.email = params.email.toLowerCase();

    return new Promise((resolve, reject) => {
      db.collection("Users").findOne({ email: params.email }).then((response) => {

          console.log(response)
          if(response) {
            bcrypt.compare(params.password, response.password, (err, success) => {
              if(success) {
                let token = jwt.sign({
                  name: response.name,
                  id: response._id
                }, proccess.env.JWT_SECRET);

                db.collection("Users").findOneAndUpdate({
                  email: params.email
                }, {
                  $set: { token: token, lastLogin: new Date() },
                }, function (e, s) {
                  if(e) {
                    console.log(e)
                    reject(e)
                  } else {
                    console.log("updated")
                    resolve(s)
                  }
                })
              } else {
                reject({msg: 'Incorrect email or password.'})
              }
            })
          } else {
  
            reject({msg: 'cannot log in user'});
          }

      })
    })
  }

Auth Router:

router.post('/login', (req, res) => {

    let User = new models.User()
    let processes = [];
    processes.push(function (callback) {
        User.login(req.body).then(function (response) {
           
                callback(null, response);
        }, function (error) {
            console.log(error)
            callback(error);
        });
    });

    async.waterfall(processes, function (error, data) {
        if (!error) {
            return res.json({
                statusCode: 200,
                msg: 'User logged in successfully.',
                result: data
            });
        } else {
            return res.json({
                statusCode: 401,
                msg: 'Cannot login user.',
                error: error
            });
        }
    });

})

React Login.js:

const login = () => {
    axios.post('/login', data).then(async (response) => {
      console.log(response)
      if(response && response.data.result.value.token ) {
        localStorage.setItem("authUser", JSON.stringify(response.data.result.value.token))
        history.push("/")
        console.log(response.data.result)
      } else {
        console.log("ERROR")
      }
    })
  }

2

Answers


  1. MongoDBs method findOneAndUpdate does return the old document by default.
    In order to return the updated document pass returnNewDocument: true as option:
    https://www.mongodb.com/docs/manual/reference/method/db.collection.findOneAndUpdate/

    In your case:

    db.collection("Users").findOneAndUpdate({
       email: params.email
     }, {
       $set: { token: token, lastLogin: new Date() },
     }, {
       returnNewDocument: true
     }, function (e, s) {
       if(e) {
         console.log(e)
         reject(e)
       } else {
         console.log("updated")
         resolve(s)
       }
     })
    

    PS: You might should use async functions with await. This could make your code way more readable (at least within the User Model) 🙂

    Login or Signup to reply.
  2. This can help you.

    In your model

    async login(params) {
        params.email = params.email.toLowerCase();
    
        try {
            const user = await db.collection("Users").findOne({ email: params.email });
    
            if(!user) {
                throw {message: "Incorrect email"}
            }
    
            const vaild = await bcrypt.compare(params.password, user.password);
            
            if(!valid) {
                throw {msg: 'Incorrect email or password.'}
            }
    
            let token = jwt.sign({
                name: user.name,
                id: user._id
            }, proccess.env.JWT_SECRET);
    
            return db.collection("Users").findOneAndUpdate({
                email: params.email
            }, {
                $set: { token: token, lastLogin: new Date() },
            }, {new: true}); //FOR THE RETRIEVE NEW UPDATEs FROM MONGODB
        
        } catch(e) {
            throw e
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search