You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Which version of Microsoft Identity Web are you using?
1.15.1
Where is the issue?
Token cache serialization in .Net framework
[x ] In-memory caches
[x ] Distributed caches
The issue only affects the TokenCache confidential client extensions used to add token cache support in ASP.net MVC, or .NET Core, but without fully using Id.Web. It only happens when you re create the confidential client application each time you want to get a token
Repro
With the in memory and distributed in memory cache, the cache is not hit, because a new InMemory cache is instantiated each time.
The following code
// Copyright (c) Microsoft Corporation. All rights reserved.// Licensed under the MIT License.using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Logging;using Microsoft.Identity.Client;using Microsoft.Identity.Web;using System;using System.Collections.Generic;using System.Threading.Tasks;namespaceConfidentialClientTokenCache{/// <summary>/// The goal of this little sample is to show how you can use MSAL token cache adapters/// in confidential client applications both in .NET Core, or .NET Framework 4.7.2/// Note that if you write a .NET Core web app or web API, Microsoft recommends that you use the/// IDownstreamApi or ITokenAcquisition interfaces directly (instead of MSAL)/// </summary>staticclassProgram{staticasyncTask<AuthenticationResult>CreateAppAndGetToken(CertificateDescriptioncertDescription,intcacheType){stringclientId="6af093f3-b445-4b7a-beae-046864468ad6";stringtenant="msidentitysamplestesting.onmicrosoft.com";string[]scopes=new[]{"api://8206b76f-586e-4098-b1e5-598c1aa3e2a1/.default"};// Create the confidential client applicationIConfidentialClientApplicationapp;app= ConfidentialClientApplicationBuilder.Create(clientId)// Alternatively to the certificate you can use .WithClientSecret(clientSecret).WithCertificate(certDescription.Certificate).WithTenantId(tenant).Build();if(cacheType==0){// In memory token caches (App and User caches)
app.AddInMemoryTokenCache();}// Or// Distributed token caches (App and User caches)// Add one of the below: SQL, Redis, CosmosDbelse{
app.AddDistributedTokenCache(services =>{ services.AddDistributedMemoryCache(); services.AddLogging(configure => configure.AddConsole()).Configure<LoggerFilterOptions>(options => options.MinLevel = Microsoft.Extensions.Logging.LogLevel.Warning);/* Remove comments to use SQL cache implementation services.AddDistributedSqlServerCache(options => { // SQL Server token cache // Requires to reference Microsoft.Extensions.Caching.SqlServer options.ConnectionString = @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=TestCache;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"; options.SchemaName = "dbo"; options.TableName = "TestCache"; // You don't want the SQL token cache to be purged before the access token has expired. Usually // access tokens expire after 1 hour (but this can be changed by token lifetime policies), whereas // the default sliding expiration for the distributed SQL database is 20 mins. // Use a value which is above 60 mins (or the lifetime of a token in case of longer lived tokens) options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90); }); *//* Remove comments to use Redis cache implementation // Add Redis services.AddStackExchangeRedisCache(options => { options.Configuration = "localhost"; options.InstanceName = "Redis"; }); *//* Remove comments to use CosmosDB cache implementation // Add CosmosDB services.AddCosmosCache((CosmosCacheOptions cacheOptions) => { cacheOptions.ContainerName = Configuration["CosmosCacheContainer"]; cacheOptions.DatabaseName = Configuration["CosmosCacheDatabase"]; cacheOptions.ClientBuilder = new CosmosClientBuilder(Configuration["CosmosConnectionString"]); cacheOptions.CreateIfNotExists = true; }); */});}// Acquire a token (twice)varresult=await app.AcquireTokenForClient(scopes).ExecuteAsync();returnresult;}staticasync Task Main(string[]args){// Simulates the configuration, could be a IConfiguration or anythingDictionary<string,string>Configuration=newDictionary<string,string>();// Certificate LoadingstringkeyVaultContainer="https://WebAppsApisTests.vault.azure.net";stringkeyVaultReference="Self-Signed-5-5-22";CertificateDescriptioncertDescription= CertificateDescription.FromKeyVault(keyVaultContainer, keyVaultReference);ICertificateLoadercertificateLoader=new DefaultCertificateLoader();
certificateLoader.LoadIfNeeded(certDescription);varresult=await CreateAppAndGetToken(certDescription,0);
Console.WriteLine(result.AuthenticationResultMetadata.TokenSource);result=await CreateAppAndGetToken(certDescription,0);
Console.WriteLine(result.AuthenticationResultMetadata.TokenSource);result=await CreateAppAndGetToken(certDescription,1);
Console.WriteLine(result.AuthenticationResultMetadata.TokenSource);result=await CreateAppAndGetToken(certDescription,1);
Console.WriteLine(result.AuthenticationResultMetadata.TokenSource);}}}
Expected behavior
The console app should display:
IdentityProviderCache
IdentityProvider
Cache
Actual behavior
The console app actually displays:
jmprieur
changed the title
[Bug]
[Bug] In .Net framework, when recreating the CCA each time one wants to acquire a token, the cache is not hit
Aug 17, 2021
Which version of Microsoft Identity Web are you using?
1.15.1
Where is the issue?
The issue only affects the TokenCache confidential client extensions used to add token cache support in ASP.net MVC, or .NET Core, but without fully using Id.Web. It only happens when you re create the confidential client application each time you want to get a token
Repro
With the in memory and distributed in memory cache, the cache is not hit, because a new InMemory cache is instantiated each time.
The following code
Expected behavior
The console app should display:
Actual behavior
The console app actually displays:
Additional context / logs / screenshots
We instantiate a ServiceProvider each time
The text was updated successfully, but these errors were encountered: