Razmi
Razmi

Reputation: 209

Resetting password via email

sorry for the long post, I'm trying to reset password via email, until now I managed to send the reset link to the email, right now I tried this in the backend:

userRouter.get('/reset', expressAsyncHandler(async (req, res) => {
  const user = await User.findOne({
    where: {
      resetPasswordToken: req.query.resetPasswordToken,
      resetPasswordExpires: {
        $gt: Date.now(),
      },
    },
  });
  if (user) {
    console.log('token matched')
    res.status(200).send({
      message: 'password reset link ok'
    })
  } else {
    console.log('password reset link is invalid or has expired');
    res.json('password reset link is invalid or has expired');
  }
})
);

In the forgot password I did something like this for updating the two field:

user.update({
        resetPasswordToken: token,
        resetPasswordExpires: Date.now() + 360000,
      });

My user Model is:

    name: { type: String, required: true },
    email: { type: String, required: true, unique: true },
    password: { type: String, required: true },
    isAdmin: { type: Boolean, default: false, required: true }

When I'm trying to use the where clause to check the resetPasswordToken is returning all my users, which is wrong. I'm thinking that I need to declare the resetPasswordToken and resetPasswordExpires in the model for it two work? Or it is enough? Another question would be, what would I have to send to the frontend so it will work?

In react-redux, I have the following function, but I'm 100%, that I'm sending the wrong data:

export const checktoken = (email) => async (dispatch) => {
  dispatch({ type: USER_RESET_PASSWORD_REQUEST, payload: { email } });
  try {
    const { data } = await Axios.get('/api/users/reset');
    dispatch({ type: USER_RESET_PASSWORD_SUCCESS, payload: data });;
    localStorage.setItem('userInfo', JSON.stringify(data));
  } catch (error) {
    dispatch({
      type: USER_RESET_PASSWORD_FAIL,
      payload:
        error.response && error.response.data.message
          ? error.response.data.message
          : error.message,
    });
  }
};

Upvotes: 0

Views: 1033

Answers (1)

Someone Special
Someone Special

Reputation: 13588

Firstly, Your model doesn't have the field resetPasswordToken and resetPasswordExpires. Which means your update will not work. I'm assuming you are using mongoose, and mongoose will not update fields that do not exist in model.

Add the entries as follows.

name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
isAdmin: { type: Boolean, default: false, required: true },
resetPasswordToken: { type: String },
resetPasswordExpires: { type: Number }

Secondly, your query is wrong. The query should be like...

  const user = await User.findOne({
      resetPasswordToken: req.query.resetPasswordToken,
      resetPasswordExpires: {
        $gt: Date.now(), 
      },
  });

Note: Always check your database to see if your update entries are indeed updated.

Frontend

Upon verifying that the user + token exist, you can res.status(200).send() to your web app.

In your webapp, you will then request the user for the new password. Once user entered the new password, you will send the new password AND the token (again) to the backend.

This time, you will need to verify the token again before u update the password into user model. This will ensure the reset password is from a valid source.

you will probably want to delete resetPasswordToken and resetPasswordExpires from the document once password is updated since it's no longer needed.

Upvotes: 1

Related Questions