I'm trying to implement a invitation system where newly created accounts received a confirmation token by email using UserManager.GenerateEmailConfirmationToken and UserManager.ConfirmEmail. However the ConfirmEmail method is always returning false.
As per suggestion in this post I implemented my MachineKeyDataProtector and registered in Unity like this:
container.RegisterType<IUserTokenProvider<User, Guid>,
DataProtectorTokenProvider<User, Guid>>(new InjectionConstructor(new MachineKeyDataProtector("ASP.NET Identity")));
My UserManager is injected with the IUserTokenProvider like this:
public UserManager(IUserStore<User, Guid> store, IUserTokenProvider<User, Guid> userTokenProvider)
: base(store)
{
// Configure validation logic for passwords
this.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = false,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
this.UserTokenProvider = userTokenProvider;
}
I then encapsulated the GenerateEmailConfirmationToken method in a extension method:
public static string GenerateUrlForEmailConfirmationToken(this UserManager<User, Guid> userManager, UrlHelper urlHelper, Guid userId)
{
var verificationCode = userManager.GenerateEmailConfirmationToken(userId);
var url = urlHelper.Link(string.Empty, new
{
controller = "Account",
action = "Verify",
userId = userId,
verificationCode = verificationCode
});
return url;
}
And I'm using it:
var url = UserManager.GenerateUrlForEmailConfirmationToken(Url, targetUser.Id);
//injects the url in a ready made html template
NotificationService.NotifyNewUser(targetUser, url);
Debugging GenerateUrlForEmailConfirmationToken I saw that MachineKeyDataProtector's protect method is being called, however MachineKeyDataProtector's unprotect is never called by UserManager's ConfirmEmail.
If I change the DI configuration to register the IUserTokenProvider per request
container.RegisterType<IUserTokenProvider<User, Guid>,
DataProtectorTokenProvider<User, Guid>>(new PerRequestLifetimeManager(),
new InjectionConstructor(new MachineKeyDataProtector("ASP.NET Identity")));
Then the MachineKeyDataProtector's unprotect is called but it trows a CryptographicException with the following message "Error occurred during a cryptographic operation.".
Could this be the reason why the validation is always false? If so, how to ensure that the unprotect method is called? By looking at the objects in both situations the UserManager seems to be using the correct IDataProtector.
Any help is appreciated!