Skip to content

[Bug] The cache contains multiple tokens satisfying the requirements #5400

@andkorsh

Description

@andkorsh

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:

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.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions