Invalid token in ConfirmEmail due to changed Securitystamp

Viewed 526

I've been banging my head against a wall for some time now about this:

I have an ASP.NET MVC 5.2.3 web application with ASP.NET Identity 2.2.1. I want to force users to

  1. validate their email-address and
  2. validate their mobile phone number.

So when a user registers for the application an emailVerification token is generated and sent to the user. After that the user is redirected to the VerifyPhoneNumber endpoint in the Manage controller. SMS-code is generated and gets send to the user. User is promted to enter the SMS-code. Code is verified. BUT if then the user receives the email with the email-verification-code and click the link the token cannot no longer be verified (Invalid Token).

As far as I understand, this happens because calling UserManager.ChangePhoneNumberAsync changes the user's SecurityStamp. Email-verification works well if phone verification is not active. To be more specific, when ChangePhoneNumberAsync is not called.

Any ideas on how to prevent the SecurityStamp from changing or allow both verifications on inital registration are greatly appreciated.

Ben

VerifyPhoneNumber

public async Task<ActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }
    var userId = User.Identity.GetUserId();
    var result = await UserManager.ChangePhoneNumberAsync(userId, model.PhoneNumber, model.Code);
    if (result.Succeeded)
    {
        var user = await UserManager.FindByIdAsync(userId);
        if (user != null)
        {
            await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
            return RedirectToAction("Index", "Home");
        }
        else
        {
            return RedirectToAction("Index", new { Message = ManageMessageId.AddPhoneSuccess });
        }
    }
    // If we got this far, something failed, redisplay form
    ModelState.AddModelError("", "Could not verify phone number.");
    return View(model);
}

ConfirmEmail

public async Task<ActionResult> ConfirmEmail(string userId, string code)
{

    if (userId == null || code == null)
    {
        return View("Error");
    }
    code = HttpUtility.UrlDecode(code);
    var result = await UserManager.ConfirmEmailAsync(userId, code);
    return View(result.Succeeded ? "ConfirmEmail" : "Error");
}
0 Answers
Related