Search code examples
asp.netasp.net-mvcdependency-injectionasp.net-mvc-5asp.net-identity-2

Invalid Token when using ASP.NET MVC 5 and Dependency Injection with Unity


I am building an ASP.NET MVC 5 website and am using Unity for dependency injection. I get an Invalid Token exception when some time has passed (more than an hour, less than a day) between the token generation and the token validation.

I have the following code in my Startup.cs:

internal static IDataProtectionProvider DataProtectionProvider { get; private set; }

public void Configuration(IAppBuilder app)
{
   DataProtectionProvider = app.GetDataProtectionProvider();
   ConfigureAuth(app);
}

I have the following code in the conctructor of my ApplicationUserManager class (timespan is set to 7 days now just to make sure that is not the issue):

var dataProtectionProvider = Startup.DataProtectionProvider;
if (dataProtectionProvider != null)
{
    this.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser> (dataProtectionProvider.Create("ASP.NET Identity")) {
        TokenLifespan = TimeSpan.FromDays(7)
    };
}

In Startup.Auth.cs, I have the following line of code in the ConfigureAuth method:

app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>());

In UnityConfig.cs, I have set up dependency injection:

container.RegisterType<ApplicationDbContext>();
container.RegisterType<ApplicationSignInManager>();
container.RegisterType<ApplicationUserManager>();
container.RegisterType<ApplicationRoleManager>();
container.RegisterType<IAuthenticationManager>(
    new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication)
    );
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(
    new InjectionConstructor(typeof(ApplicationDbContext))
);
container.RegisterType<IRoleStore<IdentityRole, string>, RoleStore<IdentityRole>>(
    new InjectionConstructor(typeof(ApplicationDbContext))
);

I have to add that one of my scenarios allows for the creation of a Contact with an associated user account. The Contact and associated user account are created in the ContactController, while the ConfirmEmail method is in the AccountController. Both take ApplicationUserManager as a constructor parameter, which means the ApplicationUserManager is injected into the controllers.

That does not appear to be the issue, since everything works fine if I confirm right after receiving the confirmation email. However, if I wait an hour or so, and then try to confirm, I get the Invalid Token exception.

I have already verified that I am not accidentally mixing different token types, both generation and verification are for email confirmation. I have also verified that I am url encoding (and decoding) the token.

I am currently testing on an Azure virtual machine with a static IP that is running its own IIS, the production environment will most likely be on a non-Azure VPS, als running its own IIS. I am not an Azure expert, but to my knowledge, I didn't select any options that are related to load balancing.

I would really appreciate your help, as I have already tried any possible solutions I was able to find here and on other websites.


Solution

  • The Invalid token issue has been solved. Since it only happened after some time had passed, I figured it might have something to do with my application recycling.

    I managed to get rid of the problem by setting a fixed MachineKey in my web.config. You can use IIS Manager to generate it, as described here: https://blogs.msdn.microsoft.com/vijaysk/2009/05/13/iis-7-tip-10-you-can-generate-machine-keys-from-the-iis-manager/

    Please note: for some reason, IIS adds the IsolateApps when it generates a machine key. However, this results in ASP.NET throwing an exception. After you manually remove the IsolateApps and save, it should work as expected.