Invalid token error on reset password email in ASP.NET Core 5 Identity

53 Views Asked by At

I am getting invalid token error while I am trying to reset my password by clicking reset password link via email.

I have been looking what problem would be and seen so many solution such as encode & decode, replacing "+" etc but none of them worked in my context.

My "forget password" code is as shown here:

public IActionResult ForgetPassword()
{
    return View();
}

[HttpPost]
public async Task<IActionResult> ForgetPassword(ForgetPasswordViewModel forgetPasswordView)
{
    var hasUser = await _userManager.FindByEmailAsync(forgetPasswordView.Email);

    if (hasUser == null)
    {
        ModelState.AddModelError(string.Empty, "Bu email adresine sahip bir kullanıcı bulunamamıştır.");
        return View();
    }

    string passwordResetToken = await _userManager.GeneratePasswordResetTokenAsync(hasUser);
    
    var passwordResetLink=Url.Action("ResetPassword", "Home", new { userId = hasUser.Id, Token = passwordResetToken }, HttpContext.Request.Scheme);

    await _emailService.SendResetPasswordEmail(passwordResetLink, hasUser.Email);

    TempData["SuccessMessages"] = "Şifre yenileme linki email adresinize gönderilmiştir.";

    return RedirectToAction(nameof(ForgetPassword));
}

My reset password code block is like this:

public IActionResult ResetPassword(string userId,string token)
{
    TempData["userId"] = userId;
    TempData["token"] = token;

    return View();
}

[HttpPost]
public async Task<IActionResult> ResetPassword(ResetPasswordViewModel request)
{
    var userId = TempData["userId"];
    var token = TempData["token"];

    if (userId == null || token == null)
    {
        throw new Exception("Bir hata meydana geldi.");
    }

    var hasUser = await _userManager.FindByIdAsync(userId.ToString()!);

    if (hasUser == null)
    {
        ModelState.AddModelError(String.Empty, "Kullanıcı bulunamamıştır.");
    }

    IdentityResult result = await _userManager.ResetPasswordAsync(hasUser, (string)token, request.Password);

    if (result.Succeeded)
    {
        TempData["SuccessMessages"] = "Şifreniz başarı ile değiştirilmiştir.";
    }
    else
    {
        ModelState.AddModelErrorList(result.Errors.Select(x => x.Description).ToList());
    }

    return View();
}

I checked all Stackoverflow related subjects and tried many of the solution which has been offered at these subjects but I still could not sort out that issue.

1

There are 1 best solutions below

0
Md Farid Uddin Kiron On

I am getting invalid token error while I am trying to reset my password by clicking reset password link via email.

I have been looking what problem would be and seen so many solution such as encode & decode, replacing "+" etc but none of them worked in my context

Well, based on your description and scenario you might be getting the error becuase the lack of proper encoding while sending the reset password link.

I cannot see how you are trying to send reset password link.

Asp.net core Identity has its own mechanism to handle it let not manually handle by yourself. Its always recommended to use framework provided way because it has its own tested way.

In order to troubleshot the actual issue, you should check if you are using proper WebEncoders.Base64UrlEncode other than, your token doesn't recognize the user credential accordingly.

Most importantly, use WebEncoders.Base64UrlEncode when generating and storing the token in the email link and also use WebEncoders.Base64UrlDecode to decode the token in the ResetPassword action. Avoid manual encoding/decoding Let the framework handle it for consistency.

In addition, check other confiuration like token expiration time or make sure you're awaiting asynchronous calls like _userManager.GeneratePasswordResetTokenAsync and _emailService.SendResetPasswordEmail.

So, in order to reset your password, you should follow 3 steps accordingly,

First of all get the user whose password need to reset, then generate password generation token by using GeneratePasswordResetTokenAsync and pass the user init. Finally, call ResetPasswordAsync and pass above parameters like this :

var resetPassResult = await UserManager.ResetPasswordAsync(user, token, "YourNewPass@OneSpecial!andNumber28");

You should implement that as following:

Reset Link:

                var userId = await _userManager.GetUserIdAsync(user);
                var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
                EmailConfirmationUrl = Url.Page(
                    "/Account/ConfirmEmail",
                    pageHandler: null,
                    values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
                    protocol: Request.Scheme);

Reset password:

      var user = await _userManager.FindByEmailAsync(resetPasswordModel.Email);
    if (user == null)
        RedirectToAction(nameof(ResetPasswordConfirmation));
    var resetPassResult = await _userManager.ResetPasswordAsync(user, resetPasswordModel.Token, resetPasswordModel.Password);
    if(!resetPassResult.Succeeded)
    {
        foreach (var error in resetPassResult.Errors)
        {
            ModelState.TryAddModelError(error.Code, error.Description);
        }
        return View();
    }

Note: Once again, please double check you have properly endcoded and decoded the token while sending token generation link. Please refer to this official document, if you need additional assistance.