Reputation: 19814
I'm trying to figure out why my users are getting frequent invalid tokens when confirming their email. I can't reproduce the issue.
Here's the setup:
userManager.UserTokenProvider = new EmailTokenProvider<User>();
Here's how the token is generated:
var code = await userManager.GenerateEmailConfirmationTokenAsync(user.Id);
Here's how it's verified:
var result = await userManager.ConfirmEmailAsync(user.Id, code);
I understand that the EmailTokenProvider
uses security stamp for invalidation. My understanding is that this stamp only changes when significant changes to the User entity are made like changing password or username. However I'm getting invalid tokens way more frequently for this to be the only explanation.
I'm looking for any pointer that would help me shed some light into why this is occurring.
Edit:
I dug around the source code (documentation is very poor) and as @trailmax pointed out below EmailTokenProvider
is wrong for this use-case. It is based on TotpSecurityStampBasedTokenProvider
which has hard-coded timeout on tokens to 3 minutes!
Upvotes: 5
Views: 1605
Reputation: 35106
EmailTokenProvider
generates very short-lived token and looks like 6 digits. This token is aimed to be a 2FA and only valid for short period of time (something like 10-15 minutes, don't know the actual value).
The best you can do is to use Identity-provided DataProtectorTokenProvider
and that's a bit tricky, because it is not simple to rip it out of OWIN's hands.
The way I go around it is assign static variable in my Start.Auth.cs
and then reuse it in UserManager:
public class AuthConfig
{
public static IDataProtectionProvider DataProtectionProvider { get; set; }
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
public void ConfigureAuth(IAppBuilder app)
{
DataProtectionProvider = app.GetDataProtectionProvider();
// do other configuration
}
}
And in then re-assign it in constructor of UserManager:
var dataProtectorProvider = AuthConfig.DataProtectionProvider;
var dataProtector = dataProtectorProvider.Create("My Asp.Net Identity");
this.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser, Guid>(dataProtector)
{
TokenLifespan = TimeSpan.FromHours(24),
};
This way you get very long email token that lasts for 24 hours.
I've done the same mistake as you did, but had to correct pretty soon as users complained.
Upvotes: 8