I have a scheduled WebJob that runs on daily basis and checks the password expiry date for all users in my database. If the password expiry date is today, it will generate a password reset token and send it to the user via email. Then user clicks the url in the email and is brought to a website, where they input the new password.
I managed to generate a token in my WebJob and send it over via email. However, when resetting the password through my Asp.NET Website I get Invalid Token. I cannot figure out why. I assume it must have something to do with the token provider from my WebJob.
1) My Asp.NET website. The custom UserManager:
public class CustomUserManager : UserManager<ApplicationUser> {
public CustomUserManager(IUserStore<ApplicationUser> store) : base(store) { }
public static CustomUserManager Create(IdentityFactoryOptions<CustomUserManager> options, IOwinContext context) {
var db = context.Get<DataContext>();
var manager = new CustomUserManager(new UserStore<ApplicationUser>(db));
// [...]
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null) {
manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
// [...]
return manager;
}
}
Which is used like this:
userManager = HttpContext.GetOwinContext().Get<CustomUserManager>();
// [...]
await userManager.ResetPasswordAsync(model.Id, model.Token, model.ConfirmPassword); // token here is invalid (although the string looks like a proper token)
2) My WebJob function:
public static async void CheckPasswords([QueueTrigger("checkpasswords")] string message) {
using (var db = new DataContext())
using (var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db))) {
var provider = new DpapiDataProtectionProvider("MyApp");
userManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(provider.Create("PasswordReset"));
var users = await queryHandler.Run(new UserPasswordExpiryQuery());
foreach (var user in users) {
var days = new DateCalculations().DaysFromNow(user.PasswordExpiryDate);
// if password expired today
if (days == 0) {
var token = await userManager.GeneratePasswordResetTokenAsync(user.Id);
var url = string.Format("{0}/resetpass?user={1}&token={2}", settings.BaseUrl, user.Id, HttpUtility.UrlEncode(token));
// [...] send email logic here
}
}
}
}
LATER EDIT
I think I might have figured it out. I replaced the token provider in my Asp.NET app:
Old code:
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null) {
manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
New code:
var provider = new DpapiDataProtectionProvider("MyApp");
manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(provider.Create("ASP.NET Identity"));
Will do some further testing later on.