[Do not review] Agent ID support through minimal changes#6008
Closed
Avery-Dunn wants to merge 5 commits into
Closed
[Do not review] Agent ID support through minimal changes#6008Avery-Dunn wants to merge 5 commits into
Avery-Dunn wants to merge 5 commits into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR explores a minimal agent identity approach by adding a per-request client ID override that affects token requests and cache partitioning, plus integration coverage for single-CCA agent identity flows.
Changes:
- Adds
ClientIdOverrideplumbing through common request parameters, token requests, cache saves/lookups, and app-token cache keys. - Exposes
WithClientIdOverrideon confidential-client token builders and silent acquisition builders. - Adds integration tests for single-CCA agent identity cache behavior and updates public API manifests.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/Agentic.cs |
Adds integration tests for single-CCA agent identity flows using client ID override. |
src/client/Microsoft.Identity.Client/TokenCache.ITokenCacheInternal.cs |
Uses effective client ID for token save/filter/account lookup paths. |
src/client/Microsoft.Identity.Client/TokenCache.cs |
Uses effective client ID when deleting overlapping access tokens and matching RTs to accounts. |
src/client/Microsoft.Identity.Client/PublicApi/netstandard2.0/PublicAPI.Unshipped.txt |
Adds public API entries for the new override methods. |
src/client/Microsoft.Identity.Client/PublicApi/net8.0/PublicAPI.Unshipped.txt |
Adds public API entries for the new override methods. |
src/client/Microsoft.Identity.Client/PublicApi/net8.0-ios/PublicAPI.Unshipped.txt |
Adds mobile public API entry for silent override. |
src/client/Microsoft.Identity.Client/PublicApi/net8.0-android/PublicAPI.Unshipped.txt |
Adds mobile public API entry for silent override. |
src/client/Microsoft.Identity.Client/PublicApi/net472/PublicAPI.Unshipped.txt |
Adds public API entries for the new override methods. |
src/client/Microsoft.Identity.Client/PublicApi/net462/PublicAPI.Unshipped.txt |
Adds public API entries for the new override methods. |
src/client/Microsoft.Identity.Client/OAuth2/TokenClient.cs |
Sends effective client ID in token request body. |
src/client/Microsoft.Identity.Client/Internal/Requests/AuthenticationRequestParameters.cs |
Adds effective client ID request property. |
src/client/Microsoft.Identity.Client/Cache/CacheKeyFactory.cs |
Uses effective client ID for app-token cache keys. |
src/client/Microsoft.Identity.Client/ApiConfig/Parameters/AcquireTokenCommonParameters.cs |
Adds common client ID override storage. |
src/client/Microsoft.Identity.Client/ApiConfig/AcquireTokenSilentParameterBuilder.cs |
Adds silent-acquisition override API. |
src/client/Microsoft.Identity.Client/ApiConfig/AbstractConfidentialClientAcquireTokenParameterBuilder.cs |
Adds confidential-client override API. |
| @@ -3,3 +3,4 @@ Microsoft.Identity.Client.AuthScheme.IAuthenticationOperation3.AfterCredentialEv | |||
| Microsoft.Identity.Client.AuthScheme.CredentialEvaluationContext | |||
| Microsoft.Identity.Client.AuthScheme.CredentialEvaluationContext.CredentialEvaluationContext(System.Security.Cryptography.X509Certificates.X509Certificate2 mtlsCertificate) -> void | |||
| Microsoft.Identity.Client.AuthScheme.CredentialEvaluationContext.MtlsCertificate.get -> System.Security.Cryptography.X509Certificates.X509Certificate2 | |||
| @@ -3,3 +3,4 @@ Microsoft.Identity.Client.AuthScheme.IAuthenticationOperation3.AfterCredentialEv | |||
| Microsoft.Identity.Client.AuthScheme.CredentialEvaluationContext | |||
| Microsoft.Identity.Client.AuthScheme.CredentialEvaluationContext.CredentialEvaluationContext(System.Security.Cryptography.X509Certificates.X509Certificate2 mtlsCertificate) -> void | |||
| Microsoft.Identity.Client.AuthScheme.CredentialEvaluationContext.MtlsCertificate.get -> System.Security.Cryptography.X509Certificates.X509Certificate2 | |||
| public T WithClientIdOverride(string clientId) | ||
| { | ||
| ValidateUseOfExperimentalFeature(); | ||
| CommonParameters.ClientIdOverride = clientId ?? throw new ArgumentNullException(nameof(clientId)); |
| "WithClientIdOverride is only supported on confidential client applications."); | ||
| } | ||
|
|
||
| CommonParameters.ClientIdOverride = clientId ?? throw new ArgumentNullException(nameof(clientId)); |
| msalIdTokenCacheItem = new MsalIdTokenCacheItem( | ||
| instanceDiscoveryMetadata.PreferredCache, | ||
| requestParams.AppConfig.ClientId, | ||
| requestParams.EffectiveClientId, |
Comment on lines
99
to
+101
| msalRefreshTokenCacheItem = new MsalRefreshTokenCacheItem( | ||
| instanceDiscoveryMetadata.PreferredCache, | ||
| requestParams.AppConfig.ClientId, | ||
| requestParams.EffectiveClientId, |
Comment on lines
994
to
+997
| if (filterByClientId) | ||
| { | ||
| refreshTokenCacheItems.FilterWithLogging(item => | ||
| string.Equals(item.ClientId, ClientId, StringComparison.OrdinalIgnoreCase), | ||
| string.Equals(item.ClientId, requestParameters.EffectiveClientId, StringComparison.OrdinalIgnoreCase), |
The net8.0-ios and net8.0-android PublicAPI.Unshipped.txt files were missing the declaration for AbstractConfidentialClientAcquireTokenParameterBuilder<T>.WithClientIdOverride, causing build failures in CI (LibsAndSamples.sln). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eAD/microsoft-authentication-library-for-dotnet into avdunn/agent-id-support-alt
bgavrilMS
reviewed
May 21, 2026
| string t1Token = leg1Result.AccessToken; | ||
| var leg2Result = await cca | ||
| .AcquireTokenForClient([TokenExchangeUrl]) | ||
| .WithClientIdOverride(AgentIdentity) |
Member
There was a problem hiding this comment.
At this rate, we will move everything to the request. That's the ADAL way. Let's think more about an abstraction.
bgavrilMS
reviewed
May 21, 2026
| var leg2Result = await cca | ||
| .AcquireTokenForClient([TokenExchangeUrl]) | ||
| .WithClientIdOverride(AgentIdentity) | ||
| .OnBeforeTokenRequest(data => |
Member
There was a problem hiding this comment.
You could have used WithClientAssertion ? The problem with this approach is the expiration of the t1token
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Not yet ready for review, just exploring potential alternatives to: #5883
Currently adds:
WithClientIdOverride: a new request level parameter, to help test whether using the correct client ID in the cache key is enough to avoid the agent ID flow's cache collision risksAgentIdentityCacheIsolationTests: new unit test class covering:TwoUsers_SameAgent_NoCacheCollision_Test: Two different users through the same agent have distinct cache entries (differentHomeAccountId), silent calls return the correct user's tokenTwoAgents_SameUser_NoCacheCollision_Test: Same user through two different agents has distinct cache entries (differentClientIdin key), silent calls return the correct agent's tokenAgentUserToken_DoesNotCollide_WithBlueprintUserToken_Test: A user token acquired via agent (with override) doesn't collide with the same user+scope acquired directly by the blueprint (without override)Agentic: Extra integration tests covering:SingleCca_AgentUserIdentity_WithCacheHit_Test: Full 3-leg flow works end-to-end, all legs cache correctly, silent works, force-refresh worksSingleCca_AgentUserIdentity_AppTokenCacheIsolation_Test: Leg 1 and Leg 2 target the same scope but produce different tokens in different cache partitions