September 25, 2018
You might think: how hard can it be to modify the expiration time of the token, which OWIN issues to verify e.g. the validity of a reset password e-mail? It sounds very simple, indeed.
Even though that’s the case, it is a question I’ve received a few times when being in the context of Optimizely.
What is this token?
Let me start with an explanation of what I am looking to achieve with this post. When a user of your website requests to reset his/her password, your Optimizely system should be implemented to send out an e-mail with a link for a secure reset-password flow. In order to make that link secure, we often leverage the built-in token issuing service in ASP.NET Identity to generate a public key, which we then validate when the actual reset password action comes in for persistence.
Looking at Quicksilver, the link we end up building with that key can look like this:
https://www.hostname.com/en/my-pages/reset-password/ResetPassword/?userId=9A80C5B4-6630-4C5B-919C-7FDF510D1D41&code=4hWbo9vIVOlzJTsPXcx73DSQXeocpQQBHq%252f0VLIDfCzZj8ViZf%252bcqrcb78nas%252bH0thstAAFvSLCSh0NW6AxYuiIykSSmLjGIPzqWlQ3GBBLRURkJbJMtJyVJU%252fhs%252f8By6wegUDs6KIYwoirGKUmqFtEbWgUy%252fZcgywmYnYNTukeQogreVBbgS6MwfGRcJkESgqcU5ClOVIfcogwCc5poxg%253d%253d
How this token get’s generated is something we can control, incl. for how long it stays valid. By default, the expiration is set to 24h.
How to adjust the expiration of it
It is in plain ASP.NET Identity fairly simple to set, through your Startup (via OWIN). Optimizely has though not made it as obvious, due to the introduction of non-configurable AddCmsAspNetIdentity middleware.
We though have a simple solution for how to navigate around that configuration limitation.
//Standard Optimizely initialization of the ASP.NET Identity system for the CMS.
app.AddCmsAspNetIdentity<SiteUser>(new ApplicationOptions
{
ConnectionStringName = _connectionStringHandler.Commerce.Name
});
//We're creating a new User Token Provider, and adjusting the TokenLifeSpan as part of the initialization
DataProtectorTokenProvider<SiteUser> dataProtectionProvider = new DataProtectorTokenProvider<SiteUser>(app.GetDataProtectionProvider().Create("OptimizelyAspNetIdentity"))
{
TokenLifespan = TimeSpan.FromDays(5) //Set expiration to 5 days
};
//Then we tell OWIN to replace the existing ApplicationUserManager with an enriched version. Only the UserTokenProvider has been replaced.
app.CreatePerOwinContext<ApplicationUserManager<SiteUser>>((o, c) =>
{
var u = c.Get<ApplicationUserManager<SiteUser>>();
u.UserTokenProvider = dataProtectionProvider;
return u;
});
After the AddCmsAspNetIdentity middleware has been initialized in your Startup.cs, we go in and overwrite OWINs instance of Optimizely’s ApplicationUserManager. It enables us to carry a new and refined version of the User Token Provider, with an expiration of 5 days.
Please note that the code presented above is taken out of the context, which means the continued initialization of e.g. UseCookieAuthentication still needs to happen.