Skip to content

[API Proposal] Add WithMtlsPopFallback() and MtlsPopOptions for managed identity mTLS PoP with automatic attested-to-non-attested fallback#5964

Draft
gladjohn wants to merge 2 commits intomainfrom
gladjohn-new-api-proposal
Draft

[API Proposal] Add WithMtlsPopFallback() and MtlsPopOptions for managed identity mTLS PoP with automatic attested-to-non-attested fallback#5964
gladjohn wants to merge 2 commits intomainfrom
gladjohn-new-api-proposal

Conversation

@gladjohn
Copy link
Copy Markdown
Contributor

Summary

Proposes a new public API on AcquireTokenForManagedIdentityParameterBuilder that enables mTLS Proof-of-Possession token acquisition with automatic fallback from attested to non-attested binding when attestation fails.

Higher-level SDKs (e.g., Microsoft.Identity.Web) should not need to understand or orchestrate attestation internals. They need a bound token — MSAL should handle the "how."

Problem

Today, IdWeb must explicitly call:

miBuilder.WithMtlsProofOfPossession()
         .WithAttestationSupport();

This has three issues:

  1. IdWeb is coupled to attestation — a low-level binding mechanism detail.
  2. No fallback — if attestation fails (provider exception, KeyGuard unavailable), MSAL throws instead of falling back to non-attested mTLS PoP.
  3. Rigid strategy — IdWeb hard-codes the binding approach rather than declaring intent.

Proposed API

Two equivalent ways to opt in (Option 1 is sugar for Option 2):

Option 1: WithMtlsPopFallback() (Recommended)

miBuilder.WithMtlsPopFallback()
         .WithAttestationSupport();   // still needed — brings in native DLL

Option 2: WithMtlsProofOfPossession(MtlsPopOptions)

miBuilder.WithMtlsProofOfPossession(new MtlsPopOptions { EnableFallback = true })
         .WithAttestationSupport();   // still needed — brings in native DLL

New Options Class

public class MtlsPopOptions
{
    /// <summary>
    /// When true, MSAL attempts attested binding first and silently
    /// falls back to non-attested mTLS PoP if attestation fails.
    /// When false (default), attestation failures throw exceptions.
    /// </summary>
    public bool EnableFallback { get; set; }
}

Fallback Behavior

When EnableFallback = true:

Scenario Current Behavior New Behavior
KeyGuard + attestation succeeds ✅ Works ✅ Same
KeyGuard + attestation fails ❌ Throws attestation_failed 🔄 Falls back to non-attested flow
Non-KeyGuard key (Hardware/InMemory) ❌ Throws mtls_pop_requires_keyguard 🔄 Proceeds with non-attested mTLS PoP
Attestation provider not configured ✅ Non-attested flow ✅ Same
IMDSv1 host (no mTLS support) ❌ Throws ❌ Throws (correct — bound token required)

How IdWeb Changes

// Before — IdWeb knows about attestation
- miBuilder.WithMtlsProofOfPossession()
-          .WithAttestationSupport();

// After — IdWeb declares intent, MSAL handles fallback
+ miBuilder.WithMtlsPopFallback()
+          .WithAttestationSupport();
  • WithAttestationSupport() becomes a capability registration (brings in native DLL), not a strategy directive.
  • WithMtlsProofOfPossession() (no args) remains as the strict, no-fallback API for advanced callers.

Breaking Changes

None. Purely additive:

  • WithMtlsProofOfPossession() — unchanged
  • WithAttestationSupport() — unchanged
  • WithMtlsPopFallback() — new
  • WithMtlsProofOfPossession(MtlsPopOptions) — new overload
  • MtlsPopOptions — new class

Related

Updated the API documentation to reflect changes in the mTLS-bound token handling, including new options and migration paths for IdWeb and direct MSAL consumers.
Copilot AI review requested due to automatic review settings April 30, 2026 15:52
@gladjohn gladjohn changed the title **[API Proposal] Add WithMtlsPopFallback() and MtlsPopOptions for managed identity mTLS PoP with automatic attested-to-non-attested fallback** [API Proposal] Add WithMtlsPopFallback() and MtlsPopOptions for managed identity mTLS PoP with automatic attested-to-non-attested fallback Apr 30, 2026
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

Adds a draft API specification document for a new managed identity mTLS PoP “fallback” experience, aiming to let higher-level SDKs request a bound token without having to orchestrate attestation behavior directly.

Changes:

  • Adds a new markdown spec describing WithMtlsPopFallback() and WithMtlsProofOfPossession(MtlsPopOptions) (with EnableFallback) for managed identity.
  • Documents proposed internal plumbing (IsBoundTokenFallbackEnabled) and the intended fallback behavior in ImdsV2ManagedIdentitySource.
  • Describes intended logging/telemetry and discusses cache key partitioning implications.

Comment thread docs/msi_v2/msal-bound-token-api-spec.md Outdated
Comment thread docs/msi_v2/msal-bound-token-api-spec.md
Comment thread docs/msi_v2/msal-bound-token-api-spec.md
Comment thread docs/msi_v2/msal-bound-token-api-spec.md Outdated
…ocs accuracy

- Fix Section 7: Cache key partitioning was wrong - both token and cert
  caches use provider presence not actual outcome. Documented the bug
  and proposed concrete fix for fallback mode.
- Fix Section 3: Full end-to-end plumbing for IsBoundTokenFallbackEnabled
  through ApplyMtlsPopAndAttestation() and AuthenticateAsync() capture.
- Fix Section 4: Consistent use of _isBoundTokenFallbackEnabled instance
  field. Added Section 4.3 for credential_guard_requires_cng fallback.
- Fix Section 2.2: Added ArgumentNullException for null options and
  NET462 guard matching existing WithMtlsProofOfPossession().
- Fix Section 2.3: MtlsPopOptions docs corrected - provider not
  configured is existing behavior not a fallback scenario.
- Fix Section 1: Reframed value proposition - KeyAttestation dependency
  stays, fallback orchestration moves to MSAL.
- Fix Section 5: Added FIC scope clarification.
- Fix Section 6: Log messages now match Section 4 code exactly.
- Fix WithAttestationSupport docs: call ordering is not required.
- Fix behavior table: added CNG and NET462 rows.
- Fix naming: MSAL .NET -> MSAL.NET per repo conventions.
- Fix open questions numbering (2->4 skip).

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.

2 participants