I had similar problems when creating both the Email and SMS messages right after user account creation. Email verification would fail if Phone was verified first. However if E-mail was verified first, the SMS verification still worked in my case.
What I ended up doing (which makes more sense from an account security standpoint) was to not send the e-mail verification until the phone code was verified. This way anytime someone changes their phone number, I force re-verification of e-mail as this will both notify user of changes (in case of a sim attack, they get an e-mail) and keeps a second communication method validated.
I put the E-mail creation into the SMS verification method:
protected void Code_Click(object sender, EventArgs e)
{
if (!ModelState.IsValid)
{
ModelState.AddModelError("", "Invalid code");
return;
}
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signInManager = Context.GetOwinContext().Get<ApplicationSignInManager>();
var result = manager.ChangePhoneNumber(User.Identity.GetUserId(), PhoneNumber.Value, Code.Text);
if (result.Succeeded)
{
var userInfo = manager.FindById(User.Identity.GetUserId());
if (userInfo != null)
{
signInManager.SignIn(userInfo, isPersistent: false, rememberBrowser: false);
// force 2FA login with successful phone number
manager.SetTwoFactorEnabled(User.Identity.GetUserId(), true);
// force new cell phone changes to un-confirm & re-verify email for security reasons
userInfo.EmailConfirmed = false;
var EmCode = manager.GenerateEmailConfirmationToken(User.Identity.GetUserId());
var callbackUrl = IdentityHelper.GetUserConfirmationRedirectUrl(EmCode, User.Identity.GetUserId(), Request);
manager.SendEmail(User.Identity.GetUserId(), "Confirm your account", "A phone number has been added to your account. For security reasons, please confirm your email by clicking <a href=\"" + callbackUrl + "\">here</a>.");
Response.Redirect("/Account/Manage?m=AddPhoneNumberSuccess");
}
}
ModelState.AddModelError("", "Failed to verify phone");
}
You could also do the opposite and place SMS code sending in the e-mail verification method if email verification was more important than SMS, but wanted both. In my case phone number was more important than e-mail, so it got priority in the registration process.
Now that I look back on it, I'm glad it didn't work the way I originally planned, as this method is more straightforward and the user is less likely to forget to do one or the other. This solution walks them through it instead of bombarding a user with tasks.