After much research... I think that I have this working.
So for anyone who wants an ASP.NET Core RC2 website that uses the Identity stuff for login, and wants to host it on an Azure Web App, and wants to use the Deployment Slots to do updates via swapping, and doesn't want every user to get logged out every time the website is updated... read on!
** Usually, Azure gives you some magical default configuration that makes all of the instances in a single Web App work together. The issue with deployment slots is that it essentially acts like two completely separate Web Apps, so all the magic is gone.
You need to configure Data Protection correctly to make this work. It is a bit confusing because the documentation for .NET Core Identity makes no explicit mention of depending on or requiring that you configure Data Protection correctly, but it does. Data Protection is what it uses under the hood to encrypt the application login cookie.
The following code is needed in ConfigureServices:
services.AddDataProtection()
.SetApplicationName("myweb")
.ProtectKeysWithCertificate("thumbprint");
services.AddSingleton<IXmlRepository, CustomDataProtectionRepository>();
Explanation of each piece:
- Setting the application name lets you share the protected data across multiple applications that use this same application name. May not be required for all scenarios, but doesn't hurt for ours.
- You need to use a custom key encryption method that is consistent across both deployment slots. The default is specific to each deployment slot and can only be used within that slot. If you look at key encryption at rest, Azure uses Windows DPAPI by default. Not gonna work for our purposes. So I chose to use a certificate, just enter the thumbprint as seen in the Azure portal. NOTE: for those who hate certificates and all the jargon around it, the .NET Core documentation says you need a X.509 certificate that supports CAPI private keys or it won't work. blah blah blah blah use the SSL certificate you got for your website, it should work just fine.
- An aside: you have to do some extra googling to actually make using the certificate work. The Data Protection documentation kind of leaves you hanging in the case of Azure... just using the code above, you will likely get a 500 error when you deploy to Azure. Firstly, make sure you have uploaded your certificate in the "Custom domains and SSL" section of your Web App. Secondly, you need to add the WEBSITE_LOAD_CERTIFICATES Application Setting and add the thumbprint of your certificate to that in order to use it. See using certificates in azure websites.
- Once you set a certificate to encrypt the data... it blows away any default configuration about where to store the data -- Azure stores it in a shared folder that all of your instances can access by default (defaults described here data protection defaults). But different deployment slots are separate... so the built-in file system and registry options are no help. You have to write a custom implementation as described here: key storage providers. But oh wait... the section at the bottom on custom key repositories is a 1-liner with no link or explanation about how to hook it up... you really need to read here: key management, go to the IXmlRepository section. Unfortunately the IDataProtectionBuilder has handy extensions for everything except what you need to do here, thus the line where we register this custom IXmlRepository with the service provider. Despite the alarmingly generic name of that interface, it only impacts Data Protection and won't mess with your other stuff.
- Not shown is the implementation of CustomDataProtectionRepository. I used Azure blob storage. It is a pretty simple interface, make a comment if you need help with that though.
And OMG finally we have it working. Enjoy the 500% decrease in lost password customer service requests ;)