Skip to content

TokenCache expects that token providers send pre-sorted (alphabetically) scopes - Auth0 does not - which results in multiple_matching_tokens_detected  #4474

@torangel

Description

@torangel

Library version used

4.5.7

.NET version

net4.8

Scenario

ConfidentialClient - web site (AcquireTokenByAuthCode)

Is this a new or an existing app?

This is a new app or experiment

Issue description and reproduction steps

MsalAccessTokenCacheItem seems to expect that the token returned from the token endpoint has the scopes ordered alphabetically.
The scopes are included in the cache-key - which results in cache miss if the scopes are sorted different in the response to AcquireTokenByAuthorizationCode vs the response to msal.AcquireTokenSilent(scopes, account).WithForceRefresh(true)

This in turn results in multiple access-tokens added to the cache - which becomes a problem when trying to obtain a token silently from the cache.

MSAL.Desktop.4.57.0.0.MsalClientException: ErrorCode: multiple_matching_tokens_detected Microsoft.Identity.Client.MsalClientException: The cache contains multiple tokens satisfying the requirements. Try to clear token cache. at Microsoft.Identity.Client.Internal.Requests.Silent.SilentRequest.d__5.MoveNext()

I have read through the Oauth2 spec without finding any requirements for how scopes should be ordered in the token response.

The picture below shows the responses from the code exchange and the refreshtoken exchange. The result of these two requests are two items in the token cache - with the same scopes, but with different order.

image
image

Relevant code snippets

//Setup application with "generic autority (auth0)
var msal = ConfidentialClientApplicationBuilder
                .Create(ClientId)
                .WithExperimentalFeatures(true)
                .WithRedirectUri(RedirectUri)
                .WithClientSecret(ClientSecret)
                .WithLegacyCacheCompatibility(false)
                .WithGenericAuthority($"https://{Tenant}")
                .WithLogging(new MyIdentityLogger(),true)
                .Build();

//Configure token caching using SQL server
msal.AddDistributedTokenCache(services => {
                services.AddDistributedTokenCaches();
                services.AddDistributedSqlServerCache(options => {
                    options.SchemaName = "dbo";
                    options.TableName = "TokenCache";
                    options.ConnectionString = TokenCacheSqlServerConnectionString;
                    options.DefaultSlidingExpiration = TimeSpan.FromDays(30);
                });
            });

//Exchange authcode with access-, id- and refreshtoken
await msal.AcquireTokenByAuthorizationCode(scopes, notification.ProtocolMessage.Code)
                        .ExecuteAsync();

//Force usage of refresh token
await msal.AcquireTokenSilent(scopes, account).WithForceRefresh(true).ExecuteAsync();

//try to aquire token from cache - this fails because of multiple access tokens in cache which have the same scopes
await msal.AcquireTokenSilent(scopes, account).ExecuteAsync()

Expected behavior

No response

Identity provider

Other

Regression

No response

Solution and workarounds

Not sure how this might affect existing cache-items, but either this library has to sort the returned scopes before creating the cache key, or the identity provider has to be consistent on the order of returned scopes.

Changing the order of the requested scopes does not seem to make any difference on the response from Auth0

Metadata

Metadata

Assignees

Type

No type

Projects

Status

Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions