본문 바로가기

express

When we forgot password/ using registered email. [Express, Node]

We change password by using the registered email. when we dont know password.

Let's take a look at how this process works.

 

//api/routes/auth.js
router.post('/forgotpasswrod', forgotPassword);  [ 1 ]
router.put('/resetpassword/:resettoken', resetPassword);  [ 2 ]

[ 1 ] forgotPassword() method

When we got request POST 'api/v1/forgotpassword', call forgotPassword() method

forgotPassword() method do these.

- Got 'email' from client input 'request.body.email'.

- Find email equals to 'request.body.email', if cant occur Error.

const user = await User.findOne({ email: req.body.email });

if (!user) {
  return next(new ErrorResponse('There is no user with that email', 404));
}

 

- Issue resetToken (we already defined getResetPasswordToken() method in User model.) shoud check only send resetToken(it isn't hashed) not ResetPasswordToken(it is hashed).

// Get reset token using 'bcryto' 
 const resetToken = user.getResetPasswordToken();

!! Should check getResetPasswordToken() method return resettoken(not hashed)

!! But save resetPasswordToken(hashed) to this.model document.

 

- Send email with resetUrl which have resetToken.

const resetUrl = `${req.protocol}://${req.get('host')}/api/v1/auth/resetpassword/${resetToken}`;

const message = `Plase make a PUT request to: ${resetUrl}`;

try {
  await sendEmail({
    email: user.email,
    subject: 'Password reset token',
    message
  });
  
  res.status(200).json({ success: true, data: 'Email sent'});
} catch (err) {
  console.log(err);
  user.resetPasswordToken = undefined;
  user.resetPasswordExpire = undefiend;
  
  return next(new ErrorResponse('Email could not be sent', 500));
}

 

Full forgotPassword() method

exports.forgotPassword = asyncHandler(async (req, res, next) => {
  // get email which is equal to req.body.email/user input
  const user = await User.findOne({ email: req.body.email });  

  // Error cant find equal eamil
  if (!user) {
    return next(new ErrorResponse('There is no user with that email', 404));
  }

  // Get reset token using "bcryto" (make random number and hash that number)
  const resetToken = user.getResetPasswordToken();

  await user.save({ validateBeforeSave: false });

  // Create reset url
  const resetUrl = `${req.protocol}://${req.get(
    'host'
  )}/api/v1/auth/resetpassword/${resetToken}`;

  const message = `You are receiving this email because you (or someone else) has requested the reset of a password. Please make a PUT request to: \n\n ${resetUrl}`;

  // Send email with resetUrl message in that message there's link you can change password.
  try {
    await sendEmail({
      email: user.email,
      subject: 'Password reset token',
      message
    });

    res.status(200).json({ success: true, data: 'Email sent' });
  } catch (err) {
    console.log(err);
    user.resetPasswordToken = undefined;
    user.resetPasswordExpire = undefined;

    await user.save({ validateBeforeSave: false });

    return next(new ErrorResponse('Email could not be sent', 500));
  }
});

[ 2 ] resetPassword() method

- Only from reigstered email, user can accesses resetPassword form.

- Input newPassword and submit

- Hash 'resettoken' and then finds user document matching resetPasswordToken. and also resetPasswordExpire is greater than Date.now(). [ Validation ]

const resetPasswordToken = crypto
  .createHash('sha256')
  .update(req.params.resettoken)
  .digest('hex');
  
const user = await User.findOne({
  resetPasswordToken,
  resetPasswordExpire: { $gt: Date.now() }
});

if (!user) {
  return next(new ErrorResponse('Invalid token', 400));
}

- If valid, update user data. and delete token(by referencing 'undefined') 

// Set new password
user.password = req.body.password;
user.resetPasswordToken = undefined;
user.resetPasswordExpire = undefined;
await user.save();

- sendTokenResponse

sendTokenResponse(user, 200, res);

 

Full resetPassword() method

exports.resetPassword = asyncHandler(async (req, res, next) => {
  // Get hashed token
  // Check User.getResetToken() just pass resettoken but save hashed token to this.model
  // only registered email can get resetUrl so can get reset token.
  const resetPasswordToken = crypto
    .createHash('sha256')
    .update(req.params.resettoken)
    .digest('hex');

  const user = await User.findOne({
    resetPasswordToken,
    resetPasswordExpire: { $gt: Date.now() } // Should be greater than Date.now, it
  });

  if (!user) {
    return next(new ErrorResponse('Invalid token', 400));
  }

  // Set new password
  user.password = req.body.password;
  user.resetPasswordToken = undefined;
  user.resetPasswordExpire = undefined;
  await user.save();

  sendTokenResponse(user, 200, res);
});

'express' 카테고리의 다른 글

How to show joined models [mongoose]  (0) 2020.05.21
Permission check on user's actions [Express, Node]  (0) 2020.05.21
Query mongoose  (0) 2020.05.21
So what do I do with Token?  (0) 2020.05.19
TOKEN authentication  (0) 2020.05.19