Skip to content

fix: include isTokenBinding in CCA cache key to prevent bearer/PoP collision - #3867

Merged
Gladwin Johnson VR (gladjohn) merged 4 commits into
masterfrom
gladjohn/fix-cca-cache-key-tokenbinding
Jun 17, 2026
Merged

Gladwin Johnson VR (gladjohn) merged 4 commits into
masterfrom
gladjohn/fix-cca-cache-key-tokenbinding

Conversation

@gladjohn

@gladjohn Gladwin Johnson VR (gladjohn) commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor

Problem

GetApplicationKey did not include the isTokenBinding flag in the CCA cache key. When the same app made a bearer call followed by an mTLS PoP call (or vice versa), both resolved to the same cache key — so the second call reused the CCA built for the first.

This caused MSAL to throw at request time:

A string-returning client assertion callback cannot be used over mTLS. Use a certificate credential or a ClientSignedAssertion callback that can return a token-binding certificate.

The root cause is that bearer builds the CCA with WithClientAssertion(Func<string>) while PoP builds it with WithClientAssertion(Func<ClientSignedAssertion>) or WithCertificate() — these are fundamentally incompatible credential wirings that must not share a cache entry.

Fix

Append -tokenBinding to the cache key when isTokenBinding = true. This is a minimal, backwards-compatible change:

  • Existing bearer callers pass false (default) → their keys are unchanged.
  • PoP callers get a distinct key → build a separate CCA with the correct credential wiring.

Test

Added GetOrBuildCca_BearerThenTokenBinding_DoesNotReturnCachedBearerApp which:

  1. Builds a bearer CCA (isTokenBinding: false) — succeeds and caches.
  2. Requests a PoP CCA (isTokenBinding: true) — with the fix, this is a cache miss and attempts a fresh build. Since the test uses a secret credential (which can't do mTLS binding), it correctly throws IDW10115.
  3. Before the fix, step 2 silently returned the bearer CCA (no throw, wrong behavior).

Results

  • 949/949 Microsoft.Identity.Web.Test pass (net9.0, 4 pre-existing skips)
  • No API surface changes — GetApplicationKey is private, parameter has a default value

Add GetOrBuildCca_BearerThenTokenBinding_ShouldReturnDifferentInstances to
demonstrate that GetApplicationKey does not include the isTokenBinding flag.

A bearer call (isTokenBinding=false) caches a CCA with a string-assertion
credential, and a subsequent PoP call (isTokenBinding=true) incorrectly reuses
the same instance. MSAL then throws 'A string-returning client assertion
callback cannot be used over mTLS' because the cached CCA was never wired
with the ClientSignedAssertion bundle overload.

This test is intentionally failing (Assert.NotSame on the same instance).
Once the cache key is fixed to include isTokenBinding, it will pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…llision

GetApplicationKey did not include the isTokenBinding flag, so a CCA built for
bearer (WithClientAssertion string delegate) was cached and reused for mTLS PoP
requests. MSAL then threw 'A string-returning client assertion callback cannot
be used over mTLS' because the cached CCA was never wired with the
ClientSignedAssertion bundle overload.

Fix: append '-tokenBinding' to the cache key when isTokenBinding=true so bearer
and PoP builds get separate cache entries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@gladjohn
Gladwin Johnson VR (gladjohn) requested a review from a team as a code owner June 16, 2026 15:46
Addresses review feedback from cpp11nullptr: add
GetOrBuildCca_TokenBindingThenBearer_DoesNotReturnCachedPopApp to cover
the reverse cache-key collision direction.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread src/Microsoft.Identity.Web.TokenAcquisition/TokenAcquisition.cs Outdated
Address bgavrilMS review: remove default value from isTokenBinding
parameter to force callers to explicitly specify the flag. Add XML
doc explaining why isTokenBinding is part of the cache key (bearer
and mTLS PoP use incompatible MSAL credential wirings).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@gladjohn
Gladwin Johnson VR (gladjohn) merged commit 69a75e9 into master Jun 17, 2026
4 checks passed
@gladjohn
Gladwin Johnson VR (gladjohn) deleted the gladjohn/fix-cca-cache-key-tokenbinding branch June 17, 2026 13:01
This was referenced Jun 24, 2026
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.

3 participants