Identity: Existing "Email Confirmation" token invalidated if Two-Factor is enabled before verifying the account #32681
Labels
area-identity
Includes: Identity and providers
✔️ Resolution: Answered
Resolved because the question asked by the original author has been answered.
Status: Resolved
Milestone
Describe the bug
If I generate an Email Confirmation token (and send an appropriate email to the user containing a link with that token), but the user enables 2FA before clicking on the link, the Email Confirmation token subsequently fails validation.
When a new user registers, we send an out-of-band email to let the new user confirm their email address, by creating an email confirmation token using the standard
UserManager.GenerateEmailConfirmationTokenAsync
method and including that token in a link in said email.We automatically sign the user in immediately upon registering, without needing them to confirm their email first. This is not the same as the out-of-the-box Identity behaviour that comes with the templates, where you cannot login until you have verified your email.
It is pretty common for our users to go straight to account settings after registering, before verifying their email address, where they enable Two Factor authentication. They then try to click the link we sent them when they go look at their inbox, and the token cannot be verified.
This user flow certainly appears to be fairly normal from my perspective?
I've taken a look at the code, and what happens is:
GenerateEmailConfirmationTokenAsync
indirectly calls theDataProtectorTokenProvider
to generate a new email token.DataProtectorTokenProvider
embeds the user'sSecurityStamp
in the generated token.SecurityStamp
is updated.DataProtectorTokenProvider
checks the stamp in the token, which no longer matches the users newSecurityStamp
.To workaround this issue, I have created a new implementation of
IUserTwoFactorTokenProvider
that excludes theSecurityStamp
from the generated token, and used that for theEmailConfirmationTokenProvider
.Adding a custom provider may in fact be the recommended solution to this problem, but the default behaviour seemed unexpected enough that I thought I'd raise it. Seems risky for a number of people to reimplement the token provider for a relatively standard case?
To Reproduce
Further technical details
The text was updated successfully, but these errors were encountered: