I am setting-up a password reset functionality by sending an email with a reset link with asp.net core identity 3.
My first post generates the token and the email body and send the email.
1 [HttpPost("requestPasswordReset")]
2 [AllowAnonymous]
3 public async Task<IActionResult> requestPasswordReset(PasswordResetRequestDto passwordResetRequestDto)
4 {
5 var user = await _userManager.FindByNameAsync(passwordResetRequestDto.Username);
6
7 if (user == null)
8 return Unauthorized();
9
10 var code = await _userManager.GeneratePasswordResetTokenAsync(user);
11 code = System.Web.HttpUtility.UrlEncode(code);
12
13 // For test purpose: this works
14 var decodedCode = System.Web.HttpUtility.UrlDecode(code);
15 IdentityResult passwordChangeResult = await _userManager.ResetPasswordAsync(user, decodedCode, "password");
16 // End For test purpose
17
18 passwordResetRequestDto.EmailToSend.HtmlPart = passwordResetRequestDto.EmailToSend.HtmlPart.Replace("[resetLink]", passwordResetRequestDto.SpaUrl + "?token=" + code);
19
20 var jsonEmailToSend = JsonConvert.SerializeObject(passwordResetRequestDto.EmailToSend);
21 var data = new StringContent(jsonEmailToSend, Encoding.UTF8, "application/json");
22
23 var client = new HttpClient();
24
25 client.BaseAddress = new Uri(_config.GetSection("AppSettings:ApiUrl").Value + "email/sendmail");
26 var postEmail = client.PostAsync(client.BaseAddress, data);
27
28 return Ok();
29 }
Line 13 to 20 are for test only to check that the token can be used to reset the password. Line 18 builds the reset link to the angular client SPA.
New password is entered in SPA and send to the next post to reset password
1 [HttpPost("resetPassword")]
2 [AllowAnonymous]
3 public async Task<IActionResult> resetPassword(UserDto userDto)
4 {
5 var user = await _userManager.FindByNameAsync(userDto.Username);
6 var password = userDto.Password;
7 var token = userDto.Token;
8 token = System.Web.HttpUtility.UrlDecode(token);
9
10 IdentityResult passwordChangeResult = await _userManager.ResetPasswordAsync(user, token, userDto.Password);
11
12 if (passwordChangeResult.Succeeded)
13 return Ok();
14
15 return BadRequest();
16 }
Line 10 returns 'invalid token' I have checked that token in this line is the same that was generated by var code = await _userManager.GeneratePasswordResetTokenAsync(user); in first post.
Can someone help?