ASP.NET Core error: Invalid token Error when implementing Forgot Password

1.1k views Asked by At

In my ASP.NET MVC Core 1.1.1 app with Individual User Accounts mode in VS2017 ver 15.3.3, I'm implementing Forgot Password functionality. The app is correctly sending the email with a generated link. I can open my email and can see the link generated as follows. Link correctly displays the ResetPassWord.cshtml view. But when I enter required user name, password, confirm password info and click on Submit button, I get the Invalid Token error. Question: How to resolve the issue?

NOTE:

A. The PasswordReset functionality works fine if I am logged in and want to reset my password to something else.

B. Not sure if it's relevant or not: I'm not using Email as a user name. Instead I've changed the Email attributes in the AccountCountroller from

[Required]
[EmailAddress]
public string Email { get; set; }

to

[Required]
public string UserName { get; set; }

etc., etc. and have extended user attributes in ApplicationUser.cs as follows:

ApplicationUser.cs

// Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
    public string UserFullName { get; set; }
    [Column(TypeName = "varchar(50)")]
    public string UserEmaill { get; set; } 
    [Column(TypeName = "varchar(15)")]
    public string UserCity{ get; set; }
}

Body of my Email that App sent:

Please reset your password by clicking here: <a href='http://localhost/HPF/Account/ResetPassword?userId=1db73091-8098-4427-9a1a-1897dcabea90&code=CfDJ8IgLyyEqB6dPkvwFmW%2BJlPrg%2Fpz%2FiNTD442K1KoBG7MSx3zp6TFSY5w0Xj49cG87P%2BkGSWalD6YbbRlrLP4qAEORuoaHZM%2BMe0G08Y9EeUycbhNxx%2FpEv2z3sJ%2BMr4ZccLBO08iwlbIxBnXkJ5gu%2Bsnoo5FHAKysp85%2FrLdbS47smj%2Bt9kaaFA5DDBkzmR%2Bb0HTV2FL8CyjH2M1wCjLgcSC2Jg6BIcDAVUd7jEwxB8V9upAVh%2FR3FJCk2OAJU4w4Fg%3D%3D'>link</a>

Controller:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = await _userManager.FindByNameAsync(model.UserName);
        string sUserEmail = user.UserEmail; //I Added this. Note the email is not the user name in my app
        if (user == null)
        {
            // Don't reveal that the user does not exist or is not confirmed
            return View("ForgotPasswordConfirmation");
        }

        // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713
        // Send an email with this link
        var code = await _userManager.GeneratePasswordResetTokenAsync(user);
        var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
        await _emailSender.SendEmailAsync(sUserEmail, "Reset Password", $"Please reset your password by clicking here: <a href='{callbackUrl}'>link</a>");
        return View("ForgotPasswordConfirmation");
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }
    var user = await _userManager.FindByNameAsync(model.UserName);
    if (user == null)
    {
        // Don't reveal that the user does not exist
        return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
    }
    var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password);
    if (result.Succeeded)
    {
        return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
    }
    AddErrors(result);
    return View();
}

UPDATE

  1. I tried code = System.Net.WebUtility.UrlEncode(code); after the line var code = await _userManager.GeneratePasswordResetTokenAsync(user); inside ForgotPassword(...) POST method; but still the same error. I then also tried var code = System.Net.WebUtility.UrlDecode(model.Code); before the line var result = await _userManager.ResetPasswordAsync(user, code, model.Password); inside ResetPassword(...) POST method; same error again.
0

There are 0 answers