Implementing always signed in with ASP.NET Core and Azure
While migrating the elmah.io app to ASP.NET Core, I had to re-implement the always signed in feature available to elmah.io users. It's a toggle that the user can set and as a result, he/she won't be automatically logged out of the application. In this post, I'll share how I implemented this and the findings I discovered on the way. For a general introduction to how authentication is implemented on the elmah.io app, check out Cookie authentication with social providers in ASP.NET Core.
We use cookie-based authentication on the elmah.io app. As shown in the linked blog post, signing in users happens by calling the SignInAsync
method on the HttpContext
:
await HttpContext.SignInAsync(principal);
To implement always signed in you will need to tell ASP.NET Core to generate a non-expiring cookie. To do this, use the overload of the SignInAsync
method, accepting custom authentication properties.
await HttpContext.SignInAsync(principal, authProperties);
The authProperties
object is of type AuthenticationProperties
and contains a range of properties for controlling authentication. To make the generated cookie persistent and never expiring, use properties like shown here:
var authProperties = new AuthenticationProperties
{
ExpiresUtc = DateTime.UtcNow.AddYears(100),
IsPersistent = true,
};
That's it. The cookie won't expire for 100 years, which is probably long enough for most websites.
If you are hosting on a single server on Azure or an IIS server hosted elsewhere you are good to go. In our case, we host on multiple servers and have deployment slots for different environments like Production and Staging. The challenge when running on a set up like this is that the encryption keys used to generate the authentication token is specific to the machine the website is hosted on. This means that swapping deployment slots, will invalidate all of the cookie tokens, even though we marked them as persistent and never expiring.
To fix this you need to enable data protection and share encryption keys between servers. When running on Azure, this is most easily achieved using built-in support for Azure Blob Storage.
Start by creating a new storage account on Azure. For this example, I have selected a locally-redundant general purpose v1 storage account. Whether you want local or geo-redundant storage depends on your set up and company policies. As for the storage version, v1 is cheaper than v2 and you won't need any of the features available on v2 for this account.
In your newly created storage account, create a new container and name it something valid:
Time to update the ASP.NET Core application. Include the following code in the ConfigureServices
method:
var storageUri = new Uri("SAS_TOKEN");
var blobClient = new CloudBlobClient(storageUri);
var container = blobClient.GetContainerReference("data-protection-container-name");
container.CreateIfNotExists();
services
.AddDataProtection()
.SetApplicationName("YOUR_APP_NAME")
.PersistKeysToAzureBlobStorage(container, "data-protection-blob-name");
You will need to replace a couple of values in the code. SAS_TOKEN
should be replaced with a valid SAS token URL. Check out Grant limited access to Azure Storage resources using shared access signatures (SAS) for details on how to generate this. YOUR_APP_NAME
should be replaced with an application name of your choice.Your application now supports always signed in and won't log out users when hitting different servers and/or deployment slots on Azure.
elmah.io: Error logging and Uptime Monitoring for your web apps
This blog post is brought to you by elmah.io. elmah.io is error logging, uptime monitoring, deployment tracking, and service heartbeats for your .NET and JavaScript applications. Stop relying on your users to notify you when something is wrong or dig through hundreds of megabytes of log files spread across servers. With elmah.io, we store all of your log messages, notify you through popular channels like email, Slack, and Microsoft Teams, and help you fix errors fast.
See how we can help you monitor your website for crashes Monitor your website