On a previous blog post we examined the steps necessary to add authentication to a Blazor Server app using the latest Microsoft.Identity.Web library. Everything worked as expected and we were able to authenticate against Azure AD, acquire an access token and retrieve data from Microsoft Graph. However, there is one small issue with the current implementation of our code. Our token cache is configured to run in memory. This is great for quickly testing the app but presents a few issues once we decide to deploy and run the app in production. The app can’t scale as the token cache is only available to the local instance and if, for whatever reason, the app restarts, all tokens in cache will be wiped out along with our cache.
Prerequisites
You need to have the following installed or available to you
- An Azure AD tenant
- .NET Core 3.1 or later
- An Azure Cosmos DB instance or the local emulator
- Visual Studio 2019 or Visual Studio Code
Implementing a distributed cache
Luckily for us, the Microsoft.Identity.Web library comes with built-in support for distributed caches. In fact, it only takes one line of code to configure it. This makes it extremely straightforward to create a robust solution right out of the box. The official documentation provides the following options for setting up a distributed cache:
- SQL Server
- Redis Cache
- NCache
However, since all these cache providers implement the IDistributedCache interface, my assumption is that any provider that implements that same interface can be used with Microsoft.Identity.Web. And as luck will have it, there is already a provider for Cosmos DB (in preview) that implements this interface. Therefore, my assumption is that using this, our application should work straight out of the box without any code changes. Let’s do it!
First, we need to install the appropriate NuGet package. Use the option that works best for you (CLI, PowerShell, Package Manager etc.) to install the Microsoft.Extensions.Caching.Cosmos package
With the NuGet package installed, we need to edit the appsettings.json file and add the following parameters that will be used to instantiate our Cosmos DB cache which runs locally via the emulator:
"CosmosCacheContainer": "TokenCache",
"CosmosCacheDatabase": "BlazorCache",
"CosmosConnectionString": “AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",
NOTE: note that the
AccountKey
on the connection string is a well know key that is common for anyone using the emulator, hence the reason I didn’t omit it here. #security
The one last thing we need to do is update our middleware code in Startup.cs
to register the Cosmos DB cache and make it available to our authentication middleware. Paste the following code:
services.AddCosmosCache((CosmosCacheOptions cacheOptions) =>
{
cacheOptions.ContainerName = Configuration["CosmosCacheContainer"];
cacheOptions.DatabaseName = Configuration["CosmosCacheDatabase"];
cacheOptions.ClientBuilder = new CosmosClientBuilder(Configuration["CosmosConnectionString"]);
cacheOptions.CreateIfNotExists = true;
});
services.AddMicrosoftWebAppAuthentication(Configuration)
.AddMicrosoftWebAppCallsWebApi(Configuration, new string[] { "User.Read", "Mail.Read" })
.AddDistributedTokenCaches();
Running the code again, we can see that upon authentication, our Cosmos DB cache gets populated with our token information that can be used later by our app to retrieve the data from MS Graph:
Video recording
There is also a video recording where we (Christos and JP) show you how we put this all together live on Twitch!
The Identity Dev Advocates team streams on Tuesdays at 7am PT and Thursdays at 8am PT on Twitch. We cover all things identity and we like to bring guests and customers on the air to learn how they use our tools and platform to build their solutions.
If you want to get involved or have any questions make sure to reach out to Christos Matskas or JP
Summary
As you can see, the latest Microsoft.Identity.Web makes it very easy to work with distributed caches in a ‘plug-n-play’ mode. And, as long as, a cache provider implements the IDistributedCache interface, you can use any custom cache with your ASP.NET Core app.
Top comments (10)
Please raise an issue with our Dev Support team so that they can help you out aka.ms/425Show/help. Thx
Very nice. This vs RedisCache? Recommendations? Thanks!
It's totally up to you. Cosmos DB has very low latency but comes at a slightly higher cost. It depends on what you prefer to work with :)
We started using this package: Microsoft.Extensions.Caching.Cosmos, but was just confused with one thing that are you aware of when Microsoft is going to release this NuGet package?
Thanks @Fenil Shah... I reached out to the team to find out. I'll update this thread once I know
We are aiming to go GA within the next 6 months. However, the current preview bit is in full support and the team is monitoring GitHub for any issues so you should be able to go ahead and use it. The good news is that we don't anticipate any code changes between the Preview and GA bits.
Thank you so much Christos for your time and clear view of the package :)
I followed these above things and the token is getting saved perfectly. Now if we need to consume the same token for graph API access then how we will get/fetch the token?
Your MSAL client is able to get your token from the cache. When you do client.acquireTokenForUserSilent() it will look into the cache first... so it's seamless to you if you implement it correctly :)