I want to make an Api endpoint to send password reset token via SMS.
When we use userManager.GeneratePasswordResetTokenAsync(user)
to generate a token, the token is a long string that is usually used in an Email message. This message embeds a link containing the token as parameter and is sent to user. User clicks the link and then can change password.
Now, I have this question:
UserManagerGeneratePasswordResetTokenAsync(...)
in SMS or is better to use another token provider to generate a short 6-digit-like string?Note that GeneratePasswordResetTokenAsync
, GenerateChangeEmailTokenAsync
and similar methods are using GenerateUserTokenAsync(user, provider, purpose)
with specified provider and purpose under the hood.
We can use GenerateUserTokenAsync(user, provider, purpose)
to generate a token the way we want. So this would be my endpoint:
[HttpPost("sendResetPasswordToken")]
[ServiceFilter(typeof(ModelValidationFilter))]
public async Task<IActionResult> SendChangePasswordToken([FromBody] SendChangePasswordTokenDto dto)
{
var user = await _userManager.FindByNameAsync(dto.UserName);
if (user is null)
return UnprocessableEntity("something went wrong, contact support to resolve the problem");
var token = await _userManager.GenerateUserTokenAsync(user, TokenOptions.DefaultPhoneProvider, "ResetPasswordPurpose");
_SMSManager.SendResetPasswordToken(token, user.PhoneNumber);
return NoContent();
}
We set provider param to TokenOptions.DefaultPhoneProvider
that is a default phone token provider and set purpose param to "ResetPasswordPurpose"
that is an string indicating the purpose of the token.
To verify this token we use VerifyUserTokenAsync(user, provider, purpose, token)
and provide proper params. So here is my ResetPassword endpoint:
[HttpPost("resetPassword")]
[ServiceFilter(typeof(ModelValidationFilter))]
public async Task<IActionResult> ResetPassword([FromBody] ResetPasswordDto dto)
{
var user = await _userManager.FindByNameAsync(dto.SSN);
if(user is null)
return UnprocessableEntity("invalid user token");//actually user not found
var tokenVerified = await _userManager.VerifyUserTokenAsync(user, TokenOptions.DefaultPhoneProvider, "ResetPasswordPurpose", dto.Token);
if (!tokenVerified)
return UnprocessableEntity("invalid user token");
var token = await _userManager.GeneratePasswordResetTokenAsync(user);//new token for reseting password
var result = await _userManager.ResetPasswordAsync(user, token, dto.NewPassword);
if (!result.Succeeded)
return UnprocessableEntity("weak password");
return NoContent();
}