Skip to content

Multi tenant client_credential use

Bogdan Gavril edited this page May 19, 2021 · 27 revisions

Pattern for using MSAL for client credential flow in multi-tenant services

Decision point - token caching

MSAL maintains a token cache which grows with each token acquired. MSAL manages token lifetimes in a smart way, so you should always use the cache. If your service needs to call N tenants, there will be potentially N tokens in MSAL's cache, each around 2Kb in size. N can be very large, there are > 1 million tenants in AAD and this number is growing.

Pattern 1 - let MSAL do it

// When your service starts, create a singleton / static ConfidentialClientApplication
static ConfidentiClientApplication s_cca = ConfidentiClientApplicationBuilder
              .WithCertificate(x509certificate)
              .Create("client_id"); 

// Then, whenever you need a token, specify the authority
var result = await s_cca .AcquireTokenForClient("scope_for_downstream_api")
                      .WithAuthority("https://login.microsoft.com/<tenant_id>") // do NOT use common or organizations here
                      .WithSendX5C(true) // for SNI
                      .ExecuteAsync();

// You can monitor if the cache was hit
bool cacheHit = result.AuthenticationResult.AuthenticationResultMetadata.TokenSource == TokenSource.Cache;
  • MSAL does not evict items from the cache, and at 2KB size per token, you could eventually go out of memory.
  • But if you are migrating from ADAL and haven't run out of memory, this will have the same memory profile.
  • If you need to use different client_ids, then maintain a dictionary of <client_id> -> ConfidentialClientApplication

Pattern 2 - take control of the cache

This is the North Star.

// In your app initialization define a cache 
// See https://github.com/Azure-Samples/active-directory-dotnet-v1-to-v2/blob/master/ConfidentialClientTokenCache/Program.cs#L83 for several implementations 
static var s_cache = InMemoryWithLRU / Redis / SqlServer / L1InMemroy_L2Distributed / etc.

// Then when you need a token
var cca = ConfidentialClientApplicationBuilder.Create("client_id")
               .WithAuthority("https://login.microsoftonline.com/<tenantid>")
               .WithCertificate(certificate)
               .Build();

s_cache.Initialize(cca.AppTokenCache); // configure the CCA to use your token cache

var result = await app.AcquireTokenForClient(new[] {"https://graph.windows.net/.default"})
                 .WithSendX5C(true) // SNI
                 .ExecuteAsync();

  • Microsoft.Identity.Web project has several high performance token cache implementations
  • If you are using ASP.NET Core, consider using Microsoft.Identity.Web - it's a higher level API that takes care of many aspects for you
  • If not, see this simple sample that shows how to use a token cache from Microsoft.Identity.Web in ANY application
  • For best performance, in-memory caching with LRU policies plus optional distributed cache, use the L1/L2 cache or the InMemoryCache.

Getting started with MSAL.NET

Acquiring tokens

Desktop/Mobile apps

Web Apps / Web APIs / daemon apps

Advanced topics

News

FAQ

Other resources

Clone this wiki locally