I have a windows service, a MVC application and a Webforms web application in the same solution. From Webforms I am trying to send a password confirm e-mail to a user. The Webforms app sends a message through MSMQ to the Windows Service (message consumers). The Windows Service then creates a user, their confirmation token and sends the e-mail.
The user when clicking the link then confirms their e-mail on the MVC application. All this works fine on me development machine.
Whenever I deploy on production I start getting invalid token issues.
Some relevant code in my setup:
In the Windows Service:
Autofac config
builder.Register(c => new UserManager<User, long>(new UserStore(new DbEntities()))).InstancePerLifetimeScope();
Inside the method that creates the token and e-mail
Constructor
private readonly UserManager<User, long> _usermanager;
private readonly IUnitOfWork _uow;
public ConfiguratorUserService(IUnitOfWork uow)
{
_uow = uow;
_usermanager = new UserManager<User, long>(new UserStore((DeronEntities)_uow.Context));
var provider = new DpapiDataProtectionProvider("DeronConfigurator");
_usermanager.UserTokenProvider = new DataProtectorTokenProvider<User, long>(provider.Create("Passwords"));
}
Method
var user = new User
{
... more props setting
UserName = contact.Emailadres,
};
_usermanager.Create(user);
var provider = new DpapiDataProtectionProvider("Configurator");
_usermanager.UserTokenProvider = new DataProtectorTokenProvider<User, long>(provider.Create("Passwords"));
var token = _usermanager.GenerateEmailConfirmationToken(user.Id);
var data = Encoding.UTF8.GetBytes(token);
var base64EncodedToken = System.Convert.ToBase64String(data);
// And sending the e-mail here
Then on the MVC side I have
Autofac
builder.Register(c => new UserManager<User, long>(new UserStore(new DeronEntities()))).InstancePerLifetimeScope();
Auth setup (startup)
var provider = new DpapiDataProtectionProvider("Configurator");
app.CreatePerOwinContext(() => new UserManager(new UserStore(new DeronEntities()))
{
UserTokenProvider = new DataProtectorTokenProvider<User, long>(provider.Create("Passwords"))
});
AccountController
var data = Convert.FromBase64String(code);
var base64Decoded = Encoding.UTF8.GetString(data);
var result = await UserManager.ConfirmEmailAsync(userId, base64Decoded);
What I have tried and found out":
- It is working fine on localhost (dev environment)
- I have tried many suggestions from So and other resource listed below
- The token itself is fine when I log on the Windows Service and AccountController. They match when logging them
- I checked naming of DataProtectionProvider AppName and Purposes
- I am base 64 encoding tokens, so no issue with url encoding etc there, as stated on many SO answers
- The only true difference I can see for now is that production runs on SSL and localhost doesn't
- Production environment has all apps on the same machine, no load balancer setup or things like that
Tried solutions: http://www.gunaatita.com/blog/Invalid-Token-Error-on-Email-Confirmation-in-Aspnet-Identity/1056
MachineKeyDataProtector - Invalid link when confirmation email sent through background job
I am unsure how to setup machine key usage for the Windows Service