Preserve ManagedIdentity when converting AcquireTokenOptions to TokenAcquisitionOptions#3914
Merged
gladjohn merged 2 commits intoJul 2, 2026
Merged
Conversation
…AcquisitionOptions
TokenAcquirer.GetEffectiveTokenAcquisitionOptions maps the caller's
AcquireTokenOptions onto a new TokenAcquisitionOptions, but did not copy the
ManagedIdentity property. As a result, any ITokenAcquirer.GetTokenForAppAsync
or GetTokenForUserAsync call that specified a managed identity silently lost
it and fell back to the confidential-client path. For token-binding (mTLS PoP)
scenarios this surfaced as IDW10115 ("Token binding requires either a signing
certificate or a binding-aware signed assertion...").
Copy ManagedIdentity alongside the other AcquireTokenOptions properties, and
add regression tests asserting the managed identity flows through to the
effective TokenAcquisitionOptions for both the app and user token paths.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
4gust
approved these changes
Jul 2, 2026
iarekk
approved these changes
Jul 2, 2026
bgavrilMS
approved these changes
Jul 2, 2026
This was referenced Jul 3, 2026
Closed
This was referenced Jul 6, 2026
Open
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.
Summary
TokenAcquirer.GetEffectiveTokenAcquisitionOptions(AcquireTokenOptions)maps thecaller-supplied
AcquireTokenOptionsonto a newTokenAcquisitionOptions, but nevercopies the
ManagedIdentityproperty. As a result, anyITokenAcquirer.GetTokenForAppAsync/GetTokenForUserAsynccaller that requests amanaged identity silently loses it and falls back to the confidential-client path.
The fix is a single line that copies
ManagedIdentityalongside the other properties.The bug in detail
The
ITokenAcquirersurface (GetTokenForAppAsync/GetTokenForUserAsync) funnelsthrough
GetEffectiveTokenAcquisitionOptions, which rebuilds aTokenAcquisitionOptionsfrom the caller's
AcquireTokenOptions:Downstream,
TokenAcquisition.GetAuthenticationResultForAppInternalAsyncselects betweenthe managed-identity flow and the confidential-client flow based on whether
ManagedIdentityis set:Because
ManagedIdentityis dropped during the conversion, this check is alwaysfalsefor
ITokenAcquirercallers, so IdWeb builds a confidential client that has nocredential configured. For token-bound (mTLS PoP) requests that then surfaces as:
The
DownstreamApipath (CreateTokenAcquisitionOptionsFromApiOptions) already copiesManagedIdentity, which is why this only reproduces through theITokenAcquirerseam.Why this fix is needed — MISE Native managed-identity mTLS PoP
The concrete motivating scenario is MISE Native (the NativeAOT
mise.dll) performinguser-assigned managed identity + mTLS Proof-of-Possession against a downstream API
(e.g. Azure Key Vault).
MISE Native's authorization-header creation resolves an
MTLS_POPtoken strategy thatcalls
ITokenAcquirer.GetTokenForAppAsync(scope, acquireTokenOptions)with:acquireTokenOptions.ManagedIdentity = { UserAssignedClientId = <uami> }ProtocolScheme = MTLS_POPBecause
GetEffectiveTokenAcquisitionOptionsdroppedManagedIdentity, MISE Native couldnever take the managed-identity path — every call fell back to the confidential client and
failed with
Cannot acquire bound authorization header(IDW10115, masked by the outerresult). This blocks managed-identity mTLS PoP for MISE Native entirely.
End-to-end validation
Rebuilding
mise.dllagainst this fix and running the MISE Native downstream-API call:IDW10115→Cannot acquire bound authorization header.ManagedIdentityApplication created,ApiId AcquireTokenForUserAssignedManagedIdentity,IsConfidentialClient: False,IsMtlsPopRequested: True,[Managed Identity] mTLS PoP requested, routing to IMDSv2→ the bound token is acquiredvia the managed-identity path. (Off the target host, IMDSv2 returns
identity_not_found,which still confirms the correct managed-identity path is now taken instead of the
confidential-client fallback.)
Tests
Adds two regression tests to
TokenAcquirerTeststhat build aTokenAcquirerover asubstitute
ITokenAcquisition, invoke the app and user token paths with anAcquireTokenOptions.ManagedIdentity, and assert theManagedIdentitysurvives into theeffective
TokenAcquisitionOptionshanded toITokenAcquisition:GetTokenForAppAsync_WithManagedIdentity_PreservesManagedIdentityInEffectiveOptionsGetTokenForUserAsync_WithManagedIdentity_PreservesManagedIdentityInEffectiveOptionsBoth fail without the fix (
Assert.NotNull() Failure: Value is null) and pass with it.