Search code examples
c#asp.net-coreblazorasp.net-identityazure-ad-b2c

Caching User Single Sign On using Distributed Cache


I'm currently implementing a blazor server application with Azure B2C single sign on enabled. The sign on functionality works perfectly, except that the users state is lost when the application is restarted. I'm looking to find a way for this state to persist through application restarts. Constantly asking a user to re-sign in isn't ideal.

The blazor documentation on state management isn't particularly helpful in this regard as they only make vague references to server storage with no meaningful links to examples.

Based on my research I've arrived that I'd need to capture the user state somewhere external to my application. All research I've done has pointed to the use of a distributed token cache.

What I've done thus far

  • Added the token distributed cache option after defining my azure b2c details in my service registration
.AddMicrosoftIdentityWebApp(options => configuration.Bind("AzureAdB2C", options))
.EnableTokenAcquisitionToCallDownstreamApi(
   new List<string>() { <scopes> })
.AddDistributedTokenCaches()

I'm using the sql server caching option (just for ease of use and local tests). I have

  • Booted up a mysql server

  • Installed Microsoft.Extensions.Caching.SqlServer as per the docs

  • Created the relevant table structure dotnet sql-cache create "<ConnectionString>" dbo Session as per the docs. I've confirmed that the table structures are created as per the docs.

  • Used the .AddSession() method to register relevant services

  • Defined my sql server cache as follows

.AddDistributedSqlServerCache(options =>
  {
      options.ConnectionString = "<ConnectionString>"
      options.SchemaName = "dbo";
      options.TableName = "Session";
  })

this lines up perfectly to what I can see in the db schema and table wise.

  • Defined app.UseSession(); directly after app.UseRouting() in my Program.cs

What I'm seeing

Nothing is being written to the table on user sign in - I see no logs in blazor indicating a service hasn't been registered or the connection to the database can't be established.

Conclusion

Am I missing something obvious? Is there some way to achieve persisting state through application restarts? I've consulted the microsoft identity examples as well and haven't seen an example that uses this approach.

Many thanks for any and all help!


Solution

  • The issue ended up being that

    • The cookie expiration was set to the session. This was fixed by updating the cookie settings.
    .AddMicrosoftIdentityWebApp(
        options => configuration.Bind("AzureAdB2C", options),
        cookieOptions =>
        {
            cookieOptions.Cookie.MaxAge = TimeSpan.FromDays(<INSERT DAYS>);
            cookieOptions.ExpireTimeSpan = TimeSpan.FromDays(<INSERT DAYS>);
        }
    )
    
    • Cookies are also encrypted by the server. This key is lost each time the server is restarted so the encryption key needs to be persisted external to the server. This can be achieved using the Data Protection features of aspnet core