Repository: AzureAD/microsoft-authentication-library-for-dotnet

Issue #3218: [Bug] NotImplementedException when loading a user token cache in the app token cache
Created: 2022-03-10T14:06:07Z
Logs and network traces
Without logs or traces, it is unlikely that the team can investigate your issue. Capturing logs and network traces is described in Logging wiki.
Which version of MSAL.NET are you using?
Msal 4.42
Platform
confidential client
What authentication flow has the issue?

Desktop / Mobile

 Interactive
 Integrated Windows Authentication
 Username Password
 Device code flow (browserless)


Web app

 Authorization code
 On-Behalf-Of


Daemon app

 Service to Service calls



Repro

Configure an app to use both a user flow (like authorization code, but you can repro with ROPC too) and S2S and point the UserTokenCache and the AppTokenCache to the same location (e.g. file for simplicity)
Make sure you exercise the user flow first
Call S2S

Expected behavior
S2S should just work
Actual behavior
A NotImplementedException is thrown
Root cause: the app token cache does not expect RTs to be given to it.
Note: this does not happen if you use Microsoft.Identity.Web.TokenCache
Possible solution
Throw a better exception that NotImplementedException, asking to use Microsoft.Identity.Web.TokenCache or a partitioned cache.

Duplicate issue #3861: [Bug] Microsoft.Identity.Client 4.48.1 InMemoryPartitionedAppTokenCacheAccessor.SaveRefreshToken throws NotSupportedException
Created: 2022-12-13T16:09:34Z
Which version of MSAL.NET are you using?
Microsoft.Identity.Client 4.48.1
Microsoft.Identity.Client.Extensions.Msal 2.25.0
Azure.Identity 1.8.0
Platform
.NET 4.7.1
What authentication flow has the issue?
During AcquireTokenForClient for a confidential client app.
Is this a new or existing app?
a. The app is in production, and I have upgraded to a new version of MSAL.
Repro
TokenCachePersistenceOptions persistenceOptions = new TokenCachePersistenceOptions();
persistenceOptions.UnsafeAllowUnencryptedStorage = false;

ClientCertificateCredentialOptions credentialOptions = new ClientCertificateCredentialOptions
{
    AuthorityHost = new Uri("https://login.microsoftonline.com/"),
    TokenCachePersistenceOptions = persistenceOptions,
};

lock (creationLock)
{
    if (credential == null)
    {
        Tracer?.Trace(TraceCodes.General, "credential is null; creating a new credential instance");
        credential = new ClientCertificateCredential(tenantId, applicationId, cert, credentialOptions);
        
    }
}

return credential; 

Expected behavior
An access token is retrieved.
Actual behavior
InMemoryPartitionedAppTokenCacheAccessor.SaveIdToken throws a NotSupportedException.
Additional context / logs / screenshots

  
    
      microsoft-authentication-library-for-dotnet/src/client/Microsoft.Identity.Client/PlatformsCommon/Shared/InMemoryPartitionedAppTokenCacheAccessor.cs
    
    
        Lines 77 to 84
      in
      eb81652
    
  
  
    

        
          
           /// <summary> 
        

        
          
           /// This method is not supported for the app token cache because 
        

        
          
           /// there are no ID tokens in a client credential flow. 
        

        
          
           /// </summary> 
        

        
          
           public void SaveIdToken(MsalIdTokenCacheItem item) 
        

        
          
           { 
        

        
          
               throw new NotSupportedException(); 
        

        
          
           } 
        
    
  


Error Stack Trace:
exception in DeployTemplate: base exception: System.NotSupportedException: Specified method is not supported.
   at Microsoft.Identity.Client.PlatformsCommon.Shared.InMemoryPartitionedAppTokenCacheAccessor.SaveRefreshToken(MsalRefreshTokenCacheItem item)
   at Microsoft.Identity.Client.Cache.TokenCacheJsonSerializer.Deserialize(Byte[] bytes, Boolean clearExistingCacheData)
   at Microsoft.Identity.Client.TokenCache.Microsoft.Identity.Client.ITokenCacheSerializer.DeserializeMsalV3(Byte[] msalV3State, Boolean shouldClearExistingCache)
   at Microsoft.Identity.Client.Extensions.Msal.MsalCacheHelper.BeforeAccessNotification(TokenCacheNotificationArgs args)
   at Microsoft.Identity.Client.TokenCache.<Microsoft-Identity-Client-ITokenCacheInternal-OnBeforeAccessAsync>d__110.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Identity.Client.Cache.CacheSessionManager.<RefreshCacheForReadOperationsAsync>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.Identity.Client.Cache.CacheSessionManager.<RefreshCacheForReadOperationsAsync>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Identity.Client.Cache.CacheSessionManager.<FindAccessTokenAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Identity.Client.Internal.Requests.ClientCredentialRequest.<ExecuteAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Identity.Client.Internal.Requests.RequestBase.<RunAsync>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Identity.Client.ApiConfig.Executors.ConfidentialClientExecutor.<ExecuteAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Azure.Identity.AbstractAcquireTokenParameterBuilderExtensions.<ExecuteAsync>d__0`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Azure.Identity.MsalConfidentialClient.<AcquireTokenForClientCoreAsync>d__21.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Azure.Identity.MsalConfidentialClient.<AcquireTokenForClientAsync>d__20.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Azure.Identity.ClientCertificateCredential.<GetTokenAsync>d__26.MoveNext()
: {0}

Use Case
We are migrating from the old Azure sdks to the new track2 sdks. While the Azure.Identity library tried to obtain the token, the Microsoft.Identity.Client threw the above error.

Closing comment (2022-12-13T19:26:55Z): This is a duplicate of #3218. Basically it's because the same cache source is shared for app and user tokens. App and user tokens should be in separate files (for public clients) or in distributed cache, like Redis (for confidential clients).
@paujohn Which Azure.Identity SDK version do you use?
@bgavrilMS Do you know, does AzureSDK have a user work around for this scenario? Like maybe specifying different persistence options for user/app credentials? If so, I can document it. Otherwise, would this have to be a fix on AzureSDKs or our side (as we discussed, right?)