Skip to content

WithClientClaims() - forward client-originated claims across MSI and confidential client flows#5999

Open
Robbie-Microsoft wants to merge 17 commits into
mainfrom
rginsburg/poc-withclientclaims
Open

WithClientClaims() - forward client-originated claims across MSI and confidential client flows#5999
Robbie-Microsoft wants to merge 17 commits into
mainfrom
rginsburg/poc-withclientclaims

Conversation

@Robbie-Microsoft
Copy link
Copy Markdown
Contributor

@Robbie-Microsoft Robbie-Microsoft commented May 11, 2026

Summary

Proof-of-concept implementation of WithClaimsFromClient(string claimsJson) — a new per-request API that lets clients forward a JSON claims payload (e.g., NSP xms_az_nwperimid) to ESTS / IMDS. Companion to the design doc in #5982.

What this PR does

Adds the API on:

  • AcquireTokenForManagedIdentityParameterBuilder (MSI flows — currently MSIv1 only; MSIv2 design pending IMDS team)
  • AcquireTokenForClientParameterBuilder and the FIC builder, via AbstractConfidentialClientAcquireTokenParameterBuilderExtension

Wires the claims through to the existing claims/capabilities merge pipeline so they participate correctly in cache keying and are sent on the wire as a standard OAuth claims parameter (body for ESTS, query string for IMDS v1).

Reviewer feedback addressed in latest commit

  • Renamed WithClientClaimsWithClaimsFromClient (Bogdan's suggestion) to avoid clash with the obsolete ConfidentialClientApplicationBuilder.WithClientClaims(X509Certificate2, ...) overload.
  • Removed all JSON normalization. ClaimsHelper.NormalizeClaimsJson / SortJsonObjectKeys are deleted. The raw caller-provided string is stored verbatim and used as part of the cache key. Per Bogdan: "It's the app's responsibility to use the same string. We should not penalize the 99% of ppl who will use the same claimsJson, to help the 1% who will introduce some random whitespace." Also addresses Travis's earlier request to avoid JSON parsing in the builder.
  • Removed all flow-restriction guards on the CCA extension. Claims are standard OAuth and supported on every flow (auth-code, ROPC, FIC, etc.). Per Bogdan: "Claims are supported by all those. It's a standard OAuth mechanism."
  • Moved the claims + client-capabilities merge off the cache hot path via Lazy<string> on AuthenticationRequestParameters. Cache hits no longer parse JSON.

Files changed

  • src/.../ApiConfig/AcquireTokenForManagedIdentityParameterBuilder.cs
  • src/.../Extensibility/AbstractConfidentialClientAcquireTokenParameterBuilderExtension.cs
  • src/.../Internal/ClaimsHelper.cs
  • src/.../Internal/Requests/AuthenticationRequestParameters.cs
  • src/.../ManagedIdentity/AbstractManagedIdentity.cs (MSIv1 allowlist error messages)
  • All six PublicAPI.Unshipped.txt files
  • Unit tests rewritten (dropped normalization-equivalence tests; renamed class + helper constants)

Build / test status

  • Microsoft.Identity.Client.csproj: 0 warnings, 0 errors
  • Microsoft.Identity.Test.Unit.csproj: 0 warnings, 0 errors

Out of scope (tracked separately)

  • MSIv1 single-claim allowlist (Raghu — canary by end June)
  • MSIv2 /issuecredential boolean parameter (blocked on IMDS team design)
  • E2E tests against a real VM in an NSP (blocked on test infra coordination with Redis Cache team)

Related

Robbie-Microsoft and others added 2 commits May 11, 2026 14:21
…lows

Introduces WithClientClaims(string claimsJson) as a client-originated
claims API that, unlike WithClaims(), does NOT bypass the token cache.
Tokens are cached and keyed on the normalized claims value.

Key behaviors:
- JSON is normalized (keys sorted, whitespace stripped) before use as
  a cache key to prevent cache fragmentation from cosmetic differences.
- MSIv1 (IMDS GET): claims forwarded as 'claims' query parameter.
- MSIv2 (ESTS POST): claims forwarded as 'claims' body parameter.
- Cert/FIC: merged into ClaimsAndClientCapabilities sent to ESTS.
- Cache key includes 'client_claims' component (via CacheKeyComponents).

Files changed:
- ClaimsHelper.cs: NormalizeClaimsJson, MergeClaimsObjects, SortJsonObjectKeys
- AcquireTokenCommonParameters.cs: ClientClaims property
- AcquireTokenForManagedIdentityParameters.cs: ClientClaims property
- AcquireTokenForManagedIdentityParameterBuilder.cs: WithClientClaims()
- AbstractConfidentialClientAcquireTokenParameterBuilderExtension.cs: WithClientClaims<T>()
- AuthenticationRequestParameters.cs: merge ClientClaims into ClaimsAndClientCapabilities
- ManagedIdentityAuthRequest.cs: propagate ClientClaims to MI parameters
- AbstractManagedIdentity.cs: transport client claims (query/body) per request method
- PublicAPI.Unshipped.txt (6 TFMs): new method signatures

Open questions (see PR #5982):
- MSIv2: IMDS team confirmation needed that ESTS endpoint accepts 'claims' body param
- MSIv1 param name: confirm 'claims' vs IMDS-specific param name

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- URL-encode ClientClaims with Uri.EscapeDataString before adding to
  QueryParameters in AbstractManagedIdentity.AuthenticateAsync.
  UriBuilder encodes braces/quotes but not colons when building the URI,
  while MockHttpMessageHandler parses the query without URL-decoding.
  Pre-encoding with EscapeDataString ensures the stored value
  (%7B%22...%7D) matches what ParseKeyValueList extracts.

- Update WithClientClaimsTests to use Uri.EscapeDataString(normalizedClaims)
  as the expected claims value in extraQueryParameters mock setup.

- Add ClaimsHelperTests (12 passing) and WithClientClaimsTests (33 passing)
  covering all 3 flows: IMDS GET, ESTS POST, and confidential client.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 11, 2026 19:05
@Robbie-Microsoft Robbie-Microsoft requested a review from a team as a code owner May 11, 2026 19:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a proof-of-concept WithClientClaims() API to forward client-originated claims JSON through MSAL’s Managed Identity and confidential client token acquisition flows, while keeping tokens cacheable by keying cache entries on a normalized claims representation.

Changes:

  • Added WithClientClaims(string claimsJson) for Managed Identity and a WithClientClaims<T>(string claimsJson) extension for confidential client builders.
  • Implemented canonicalization helpers in ClaimsHelper (normalize + merge) and propagated client claims through request parameters to MI transport (GET query param vs POST body).
  • Added unit tests for JSON normalization/merging and for expected caching / wire behavior in MI and confidential client scenarios.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/Microsoft.Identity.Test.Unit/ManagedIdentityTests/WithClientClaimsTests.cs New tests covering MI + confidential client behavior, caching expectations, and invalid JSON handling.
tests/Microsoft.Identity.Test.Unit/CoreTests/OAuth2Tests/ClaimsHelperTests.cs New unit tests for claims JSON normalization and merge behavior.
src/client/Microsoft.Identity.Client/PublicApi/netstandard2.0/PublicAPI.Unshipped.txt Declares new public APIs for netstandard2.0.
src/client/Microsoft.Identity.Client/PublicApi/net8.0/PublicAPI.Unshipped.txt Declares new public APIs for net8.0.
src/client/Microsoft.Identity.Client/PublicApi/net8.0-ios/PublicAPI.Unshipped.txt Declares new public APIs for net8.0-ios.
src/client/Microsoft.Identity.Client/PublicApi/net8.0-android/PublicAPI.Unshipped.txt Declares new public APIs for net8.0-android.
src/client/Microsoft.Identity.Client/PublicApi/net472/PublicAPI.Unshipped.txt Declares new public APIs for net472.
src/client/Microsoft.Identity.Client/PublicApi/net462/PublicAPI.Unshipped.txt Declares new public APIs for net462.
src/client/Microsoft.Identity.Client/ManagedIdentity/AbstractManagedIdentity.cs Adds forwarding of client claims to MI requests (query param for GET; body param for POST).
src/client/Microsoft.Identity.Client/Internal/Requests/ManagedIdentityAuthRequest.cs Propagates ClientClaims from AuthenticationRequestParameters into MI request parameters.
src/client/Microsoft.Identity.Client/Internal/Requests/AuthenticationRequestParameters.cs Merges server-issued claims + client-originated claims into the claims parameter used in OAuth2 requests.
src/client/Microsoft.Identity.Client/Internal/ClaimsHelper.cs Adds JSON normalization + merge helpers to canonicalize and combine claims objects.
src/client/Microsoft.Identity.Client/Extensibility/AbstractConfidentialClientAcquireTokenParameterBuilderExtension.cs Adds confidential-client builder extension method WithClientClaims<T>.
src/client/Microsoft.Identity.Client/ApiConfig/Parameters/AcquireTokenForManagedIdentityParameters.cs Adds ClientClaims to MI parameter object and logs presence (without logging content).
src/client/Microsoft.Identity.Client/ApiConfig/Parameters/AcquireTokenCommonParameters.cs Adds ClientClaims to common parameters.
src/client/Microsoft.Identity.Client/ApiConfig/AcquireTokenForManagedIdentityParameterBuilder.cs Adds MI builder method WithClientClaims(string) and includes normalized claims in cache key components.

Comment thread tests/Microsoft.Identity.Test.Unit/ManagedIdentityTests/WithClientClaimsTests.cs Outdated
Comment thread src/client/Microsoft.Identity.Client/Internal/ClaimsHelper.cs Outdated
Comment thread src/client/Microsoft.Identity.Client/Internal/ClaimsHelper.cs Outdated
Robbie-Microsoft and others added 2 commits May 12, 2026 16:37
- Add ValidateUseOfExperimentalFeature() gate to WithClientClaims on both
  MSI builder and confidential client extension (null/whitespace still a no-op
  without the gate so existing no-claims callers are unaffected)
- Fix double-call behavior: use SortedList indexer (last-write-wins) instead
  of .Add() which threw InvalidOperationException on second call
- Fix security issue: remove raw claimsJson from MsalClientException message
  in NormalizeClaimsJson (sensitive data must not appear in logs/telemetry)
- Wrap MergeClaimsObjects JSON parsing in MsalClientException to match the
  existing pattern from MergeClaimsIntoCapabilityJson
- Fix misleading 'cached normally' comment in ManagedIdentityAuthRequest.cs
  to accurately describe the cache contract (keyed via CacheKeyComponents)
- Remove unused System.Net.Http and System.Text.Json usings from test file
- Add OIDC section 5.5 test coverage to ClaimsHelperTests:
  array element order preservation, null claim values, idempotency,
  URI-named claims, combined userinfo+id_token shape
- Update all WithClientClaims tests to enable experimental features

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 13, 2026 17:15
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

src/client/Microsoft.Identity.Client/Internal/ClaimsHelper.cs:66

  • This has the same exception-shaping gap as normalization: ParseIntoJsonObject can throw InvalidOperationException for valid JSON that is not an object, but this block only translates JsonException. A caller combining WithClaims("[]") with WithClientClaims(...) would now get a raw exception instead of the MSAL invalid-claims error.
                JObject obj1 = JsonHelper.ParseIntoJsonObject(claims1);
                JObject obj2 = JsonHelper.ParseIntoJsonObject(claims2);
                JObject merged = JsonHelper.Merge(obj1, obj2);
                return JsonHelper.JsonObjectToString(merged);
            }
            catch (JsonException ex)

Comment thread src/client/Microsoft.Identity.Client/Internal/ClaimsHelper.cs Outdated
Comment thread src/client/Microsoft.Identity.Client/Internal/ClaimsHelper.cs Outdated
Robbie-Microsoft and others added 2 commits May 13, 2026 13:53
ParseIntoJsonObject calls JsonNode.AsObject() which throws
InvalidOperationException (not JsonException) when the input is valid
JSON but not an object (e.g. arrays, scalars). Broaden the catch
clauses in NormalizeClaimsJson and MergeClaimsObjects to translate
this into the expected MsalClientException(invalid_json_claims_format).

Also adds a TODO comment in SortJsonObjectKeys noting that objects
nested inside JSON arrays are not recursively key-sorted — a theoretical
gap for current OIDC §5.5 callers who use string arrays, deferred.

Adds 6 new tests covering the InvalidOperationException path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 13, 2026 17:57
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (2)

src/client/Microsoft.Identity.Client/Internal/ClaimsHelper.cs:68

  • MergeClaimsObjects has the same JSON-null gap: if either input is the literal null, ParseIntoJsonObject(...).AsObject() can throw NullReferenceException, which bypasses this filter. That can happen when server claims are combined with client claims, so this should be translated to the documented MSAL invalid-claims exception just like other non-object JSON.
            catch (Exception ex) when (ex is JsonException || ex is InvalidOperationException)

tests/Microsoft.Identity.Test.Unit/CoreTests/OAuth2Tests/ClaimsHelperTests.cs:309

  • This assertion is reversed. The comment and expected sorted output say id_token should appear before userinfo, but the assertion checks for userinfo before id_token, causing the test to fail for the correct ordering.
            // id_token sorts before userinfo
            Assert.IsLessThan(result.IndexOf("userinfo", StringComparison.Ordinal), result.IndexOf("id_token", StringComparison.Ordinal),
                "id_token must appear before userinfo after ordinal key sort.");

Comment thread src/client/Microsoft.Identity.Client/Internal/ClaimsHelper.cs Outdated
Comment thread src/client/Microsoft.Identity.Client/Internal/ClaimsHelper.cs
Comment thread tests/Microsoft.Identity.Test.Unit/CoreTests/OAuth2Tests/ClaimsHelperTests.cs Outdated
Comment thread src/client/Microsoft.Identity.Client/Internal/ClaimsHelper.cs Outdated
Robbie-Microsoft and others added 2 commits May 13, 2026 18:33
Bug fixes:
- Fix NullReferenceException when WithClientClaims is called with the JSON
  literal 'null': JsonHelper.ParseIntoJsonObject now null-checks the parsed
  JsonNode and throws InvalidOperationException before calling .AsObject(),
  so callers get MsalClientException(invalid_json_claims_format) as expected
- Remove raw claims payload from MsalClientException messages in
  MergeClaimsObjects and MergeClaimsIntoCapabilityJson — claims can contain
  sensitive data that must not appear in exception logs or telemetry
- Fix reversed test assertions in ClaimsHelperTests: IndexOf(bronze) must be
  less than IndexOf(silver), and IndexOf(id_token) must be less than
  IndexOf(userinfo) after ordinal key sort

New test coverage:
- WithClientClaims_JsonNullLiteral_ThrowsMsalClientException: validates the
  NRE fix for the JSON 'null' literal
- WithClientClaims_NonImdsSource_SetsBuilderParameter: documents that the
  builder parameter is set regardless of the underlying MI source (AppService)

Docs:
- Add XML doc <remarks> to the confidential client WithClientClaims extension
  noting that B2C, ADFS, and dSTS are unsupported/undefined for this API

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
InvalidOperationException is in the System namespace. The file had no
using System directive, causing CS0246 on CI (Linux/net8.0 strict build).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 13, 2026 22:45
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.

Comment thread src/client/Microsoft.Identity.Client/Internal/ClaimsHelper.cs Outdated
Robbie-Microsoft and others added 2 commits May 13, 2026 19:00
…Identity

- ClaimsHelper.cs: fix 'using System' ordering (move to top per convention)
- ClaimsHelper.cs: MergeClaimsIntoCapabilityJson now catches InvalidOperationException
  in addition to JsonException — consistent with NormalizeClaimsJson/MergeClaimsObjects
- ClaimsHelper.cs: neutral error message in MergeClaimsIntoCapabilityJson; the method
  also handles server-issued claims from .WithClaims() so the message no longer names
  'client_claims' specifically
- ClaimsHelper.cs: SortJsonObjectKeys — add comment explaining why array elements are
  cloned as-is (OIDC array element order is semantically significant)
- AbstractManagedIdentity.cs: gate ClientClaims forwarding to Imds/ImdsV2 sources only;
  other sources (App Service, Azure Arc, Service Fabric, etc.) have no confirmed contract
  for the 'claims' parameter and receiving it could cause failures
- AbstractConfidentialClientAcquireTokenParameterBuilderExtension.cs: throw MsalClientException
  when WithClientClaims is called on GetAuthorizationRequestUrlParameterBuilder — client claims
  must not appear in front-channel auth URLs (security + cache key mismatch)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Directory.Packages.props was accidentally committed with MSTest bumped
from 4.0.2 to 4.2.2. MSTest 4.2.2 introduces MSTEST0060 (TreatWarningsAsErrors)
which flags E2E tests that use both [RunOn] and [TestMethod] — a valid pattern
in this repo where [RunOn] inherits from TestMethodAttribute.

Revert to 4.0.2. Also replace Assert.IsLessThan(a, b) with Assert.IsTrue(a < b)
in ClaimsHelperTests to avoid argument-order ambiguity between MSTest versions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 13, 2026 23:09
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (1)

src/client/Microsoft.Identity.Client/Extensibility/AbstractConfidentialClientAcquireTokenParameterBuilderExtension.cs:66

  • This sets a cache key for client_claims, but the WithAppTokenProvider client-credential path never receives ClientClaims (it passes only AuthenticationRequestParameters.Claims to AppTokenProviderParameters.Claims). Callers using an app token provider will get cache entries partitioned by claims that the provider could not honor; either pass the merged claims to the provider or reject this combination.
            builder.CommonParameters.ClientClaims = normalized;

            // Use indexer (not SortedList.Add) so repeated calls are last-write-wins rather than throwing.
            builder.CommonParameters.CacheKeyComponents ??= new SortedList<string, Func<CancellationToken, Task<string>>>();
            builder.CommonParameters.CacheKeyComponents["client_claims"] = _ => Task.FromResult(normalized);

Comment thread tests/Microsoft.Identity.Test.Unit/ManagedIdentityTests/WithClientClaimsTests.cs Outdated
Comment thread src/client/Microsoft.Identity.Client/ManagedIdentity/AbstractManagedIdentity.cs Outdated
Comment thread src/client/Microsoft.Identity.Client/Internal/ClaimsHelper.cs Outdated
Robbie-Microsoft and others added 2 commits May 14, 2026 11:26
MSTest 4.0.2 uses IsLessThan(upperBound, value) semantics, so asserting
'bronze before silver' requires IsLessThan(silverIdx, bronzeIdx). The
previous commit changed these to Assert.IsTrue(a < b) to avoid arg-order
ambiguity, but MSTest.Analyzers 4.0.2 has MSTEST0037 which flags IsTrue
for comparisons as a build error under TreatWarningsAsErrors.

Revert to the original (pre-session) arg order which is correct for 4.0.2.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Thread 30: Neutralize error messages in NormalizeClaimsJson and
MergeClaimsObjects from 'client_claims value' to 'claims value' —
both methods are also called for server-issued claims from .WithClaims()
so naming client_claims specifically was misleading.

Thread 28: Replace silent drop of ClientClaims for non-IMDS managed
identity sources with a MsalClientException(InvalidRequest). Previously
the cache key included client_claims but the endpoint never received the
parameter, risking wrong cached tokens and cache fragmentation. Fail fast
instead.

Thread 31: Extend the existing GetAuthorizationRequestUrl guard to also
block AcquireTokenByAuthorizationCode, AcquireTokenByUsernameAndPassword,
and AcquireTokenByUserFederatedIdentityCredential. Those user-token flows
cache with client_claims in the key but AcquireTokenSilent has no
WithClientClaims equivalent, so cached tokens could never be retrieved
silently.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 14, 2026 18:44
The guard for non-IMDS sources fires in AbstractManagedIdentity at request
execution time, not at builder construction time. Update the test name and
comment to accurately reflect this so reviewers understand the builder still
accepts the parameter (by design) but execution throws MsalClientException.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- AbstractManagedIdentity: validate that WithClientClaims for MSIv1 (IMDS v1) only
  contains xms_az_nwperimid. IMDS v1 returns HTTP 400 with no useful message for any
  other claim; this gives callers a clear MsalClientException(InvalidRequest) instead.
- WithClientClaimsTests: add 3 tests covering valid xms_az_nwperimid claim, unsupported
  claim, and mixed (valid + unsupported) claims for MSIv1.
- ClaimsHelperTests: fix reversed Assert.IsLessThan arguments in
  NormalizeClaimsJson_CombinedUserinfoAndIdToken_BothKeysPresent — id_token must appear
  at a lower string index than userinfo after ordinal key sort.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Robbie-Microsoft added a commit that referenced this pull request May 22, 2026
…pe restriction, and MSIv1 claim allowlist

- Clarify CCA transport: WithClientClaims sends claims as ESTS request body parameter,
  NOT embedded in the client assertion JWT. This resolves Bogdan's concern.
- Add Scope section: MIRP-gated, Redis Cache only, delegated identities only initially.
- Add MSIv1 claim restriction: only xms_az_nwperimid is accepted; MSAL validates upfront
  to avoid opaque HTTP 400 from IMDS.
- Add ETAs table: CCA done; MSIv1 (Raghu) canary by June 30; MSIv2 blocked on IMDS design.
- Add E2E testing plan: Redis Cache team's help needed for MSI; existing test tenant for CCA.
- Move resolved questions from Open Questions to a Resolved Questions table.
- Update remaining open questions to only the two still unresolved items.
- Add link to POC implementation PR #5999.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep WithClientClaims and IAuthenticationOperation3/CredentialEvaluationContext entries
from this branch alongside WithCachePartitionKey and WithReservedScopes from main.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Robbie-Microsoft Robbie-Microsoft changed the title POC: WithClientClaims() - forward client-originated claims across MSI and confidential client flows WithClientClaims() - forward client-originated claims across MSI and confidential client flows May 22, 2026
Comment thread src/client/Microsoft.Identity.Client/Internal/ClaimsHelper.cs Outdated
Addresses reviewer feedback from Bogdan (bgavrilMS) and Travis Walker (trwalke) on PR #5999:

- Rename API `WithClientClaims(string)` -> `WithClaimsFromClient(string)`
  (Bogdan's preferred name; avoids confusion with the pre-existing
  ConfidentialClientApplicationBuilder.WithClientClaims certificate overload).
- Remove `ClaimsHelper.NormalizeClaimsJson` and `SortJsonObjectKeys` entirely.
  MSAL no longer parses or reshapes the caller's claims JSON. Apps that want a
  single cache entry must pass the same string each call -- this is consistent
  with how every other claims parameter is handled and avoids penalizing the
  99 percent who already do the right thing.
- Remove all flow-restriction guards on the CCA extension. Claims are a
  standard OAuth parameter and are supported on every flow; there is no reason
  to reject GetAuthorizationRequestUrl, AcquireTokenByAuthorizationCode, ROPC,
  federated identity, etc.
- Defer the claims + client-capabilities merge off the cache hot path by
  wrapping it in a `Lazy<string>` on AuthenticationRequestParameters, so cache
  hits never parse JSON.
- Update PublicAPI.Unshipped.txt across all six TFMs.
- Update unit tests: drop NormalizeClaimsJson coverage (method is gone),
  drop the two whitespace-equivalence tests (behavior no longer guaranteed),
  rename remaining test methods, helper constants, and the test class.
- Update MSIv1 validation error messages to reference WithClaimsFromClient.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Robbie-Microsoft added a commit that referenced this pull request May 27, 2026
…cision

Addresses Bogdan's feedback on PR #5982 + #5999:

- Rename the proposed API throughout from `WithClientClaims` to
  `WithClaimsFromClient` (Bogdan's suggestion). The historical reference to
  the unrelated obsolete `ConfidentialClientApplicationBuilder.WithClientClaims(X509Certificate2, ...)`
  overload is left intact in the Naming Note for clarity.
- Document the no-normalization design decision in Key Behaviors and add it to
  the Resolved Questions table. MSAL uses the raw claims string verbatim as
  part of the cache key. The application is responsible for passing a
  consistent string. Quote: "We will not penalize the 99% who already do that
  for the cost of normalizing for the 1% who would not."

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants