- 
                Notifications
    You must be signed in to change notification settings 
- Fork 378
Description
Library version used
4.73.1
.NET version
net8-windows
Scenario
PublicClient - desktop app
Is this a new or an existing app?
The app is in production, I haven't upgraded MSAL, but started seeing this issue
Issue description and reproduction steps
The issue occurs when using non-tenanted OIDC authority (OpenIdDict in our case):
builder.WithExperimentalFeatures().WithOidcAuthority(xxx).
When attempting to silently acquire an access token for the same scopes as before, after it was auto-renewed at least once (before the previous token has expired), we end up in a situation where we have two valid access tokens in cache.
After researching the code, we have noticed that when creating a token cache item for non-tenanted authority, the tenantId on the token cache item is set to an empty string:
Line 141 in f3810f5
| TenantId = tenantId ?? ""; | 
While in DeleteAccessTokensWithIntersectingScopes method it looks for tokens that have tenantId strictly equal to null therefore not deleting the previous token which is still active for a few minutes.
microsoft-authentication-library-for-dotnet/src/client/Microsoft.Identity.Client/TokenCache.cs
Lines 140 to 141 in f3810f5
| string.Equals(accessToken.TokenType ?? "", tokenType ?? "", StringComparison.OrdinalIgnoreCase) && | |
| string.Equals(accessToken.TenantId, tenantId, StringComparison.OrdinalIgnoreCase) && | 
The next time AcquireTokenSilent is called for the same authority/account/scope, the following exception will be thrown, which makes sense, since there will indeed be two active tokens in the cache:
Microsoft.Identity.Client.MsalClientException
  HResult=0x80131500
  Message=The cache contains multiple tokens satisfying the requirements. Try to clear token cache. 
  Source=Microsoft.Identity.Client
  StackTrace:
   at Microsoft.Identity.Client.TokenCache.GetSingleToken(List`1 tokenCacheItems, AuthenticationRequestParameters requestParams)
   at Microsoft.Identity.Client.TokenCache.<Microsoft-Identity-Client-ITokenCacheInternal-FindAccessTokenAsync>d__41.MoveNext()
  This exception was originally thrown at this call stack:
    Microsoft.Identity.Client.TokenCache.GetSingleToken(System.Collections.Generic.List<Microsoft.Identity.Client.Cache.Items.MsalAccessTokenCacheItem>, Microsoft.Identity.Client.Internal.Requests.AuthenticationRequestParameters)
    Microsoft.Identity.Client.TokenCache.Microsoft.Identity.Client.ITokenCacheInternal.FindAccessTokenAsync(Microsoft.Identity.Client.Internal.Requests.AuthenticationRequestParameters)
Relevant code snippets
Expected behavior
Upon renewal of an access token for non-tenanted authority, the old access token should be removed from cache.
Identity provider
Other
Regression
No response
Solution and workarounds
No response