You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Propose the addition of helper factory methods to FederatedCredentialProvider that simplify acquiring a FIC assertion using either a Managed Identity or a Confidential Client Application (CCA), for use with IByUserFederatedIdentityCredential.AcquireTokenByUserFederatedIdentityCredential.
Motivation and goals
Developers using the user_fic grant type must currently build their own assertion provider delegate, which requires boilerplate setup of a Managed Identity or CCA app and manual token acquisition.
Helper methods would remove this friction and make the correct usage pattern the default.
The exact API shape needs to be agreed upon with the team, specifically to account for bound FIC and whether to express bound/bearer as a parameter or as separate methods.
In scope
FederatedCredentialProvider.FromManagedIdentity(...) — builds an assertion provider using Managed Identity, accepting:
ManagedIdentityId managedIdentityId
string audience (defaulted to "api://AzureADTokenExchange/.default")
FederatedCredentialProvider.FromConfidentialClient(...) — builds an assertion provider using a caller-provided Confidential Client Application, accepting:
IConfidentialClientApplication cca
string audience (defaulted to "api://AzureADTokenExchange/.default")
Both methods return Func<AssertionRequestOptions, Task<string>> (async). A sync overload is a potential discussion point with the team.
Design discussion and decision on API shape for bound vs. bearer FIC. Bound FIC can pass additional claims via AssertionRequestOptions. Two options being considered:
The team (@bgavrilMS, @gladjohn) to align on which approach best covers current and future scenarios before implementation.
Out of scope
Protocol-level changes to the bound FIC flow itself.
Changes to IByUserFederatedIdentityCredential or AcquireTokenByUserFederatedIdentityCredential signatures.
Custom or third-party assertion provider implementations (the helpers are opt-in convenience wrappers).
Final async vs. sync design decision is a follow-up discussion item, not a blocker.
Risks / unknowns
Token caching behavior:
FromManagedIdentity: The Managed Identity application uses a static token cache, so repeated calls to the returned delegate will always benefit from cache reuse automatically. No additional guidance or configuration is needed from the caller — cached tokens will be returned if still valid, avoiding unnecessary network calls.
FromConfidentialClient: The caller provides an IConfidentialClientApplication instance. Since the CCA instance and its token cache are owned by the caller, the guidance is:
Preferred: Reuse the same CCA instance across calls so the token cache is shared and repeated calls return cached tokens.
Alternative: Enable static token caching on the CCA so that multiple CCA instances share a single cache.
⚠️ If neither approach is followed and a new CCA is created per call, a fresh token will be acquired on every assertion request, resulting in unnecessary network calls and risk of throttling.
Other risks:
Risk: If both async and sync overloads are provided, the sync variant must be carefully evaluated to avoid deadlocks in environments that do not support synchronous blocking (e.g., ASP.NET classic).
Helpers must propagate AssertionRequestOptions.CancellationToken to inner ExecuteAsync calls for proper cancellation support.
Examples
Using FromManagedIdentity (system-assigned):
// Static cache is used automatically — no extra configuration neededvarassertionProvider=FederatedCredentialProvider.FromManagedIdentity(ManagedIdentityId.SystemAssigned);varresult=await(appasIByUserFederatedIdentityCredential).AcquireTokenByUserFederatedIdentityCredential(scopes,"user@contoso.com",assertionProvider).ExecuteAsync();
Using FromManagedIdentity (user-assigned, with explicit audience):
Using FromConfidentialClient — reuse the same CCA instance (recommended):
// Build once and reuse — token cache is shared across all callsvarccaForAssertion=ConfidentialClientApplicationBuilder.Create(clientId).WithCertificate(cert).WithAuthority(authority).Build();varassertionProvider=FederatedCredentialProvider.FromConfidentialClient(ccaForAssertion,audience:"api://AzureADTokenExchange/.default");varresult=await(appasIByUserFederatedIdentityCredential).AcquireTokenByUserFederatedIdentityCredential(scopes,"user@contoso.com",assertionProvider).ExecuteAsync();
⚠️ Anti-pattern — do NOT create a new CCA per call (defeats token caching):
// Bad: a new CCA is created on every call, token cache is never reusedvarresult=await(appasIByUserFederatedIdentityCredential).AcquireTokenByUserFederatedIdentityCredential(scopes,"user@contoso.com",FederatedCredentialProvider.FromConfidentialClient(ConfidentialClientApplicationBuilder.Create(clientId).WithCertificate(cert).WithAuthority(authority).Build())).ExecuteAsync();
Summary
Propose the addition of helper factory methods to
FederatedCredentialProviderthat simplify acquiring a FIC assertion using either a Managed Identity or a Confidential Client Application (CCA), for use withIByUserFederatedIdentityCredential.AcquireTokenByUserFederatedIdentityCredential.Motivation and goals
user_ficgrant type must currently build their own assertion provider delegate, which requires boilerplate setup of a Managed Identity or CCA app and manual token acquisition.IByUserFederatedIdentityCredentialinterface but deferred the helper methods pending design discussion (see discussion comment).In scope
FederatedCredentialProvider.FromManagedIdentity(...)— builds an assertion provider using Managed Identity, accepting:ManagedIdentityId managedIdentityIdstring audience(defaulted to"api://AzureADTokenExchange/.default")FederatedCredentialProvider.FromConfidentialClient(...)— builds an assertion provider using a caller-provided Confidential Client Application, accepting:IConfidentialClientApplication ccastring audience(defaulted to"api://AzureADTokenExchange/.default")Func<AssertionRequestOptions, Task<string>>(async). A sync overload is a potential discussion point with the team.AssertionRequestOptions. Two options being considered:isBoundparameter:Out of scope
IByUserFederatedIdentityCredentialorAcquireTokenByUserFederatedIdentityCredentialsignatures.Risks / unknowns
Token caching behavior:
FromManagedIdentity: The Managed Identity application uses a static token cache, so repeated calls to the returned delegate will always benefit from cache reuse automatically. No additional guidance or configuration is needed from the caller — cached tokens will be returned if still valid, avoiding unnecessary network calls.FromConfidentialClient: The caller provides anIConfidentialClientApplicationinstance. Since the CCA instance and its token cache are owned by the caller, the guidance is:Other risks:
AssertionRequestOptions.CancellationTokento innerExecuteAsynccalls for proper cancellation support.Examples
Using
FromManagedIdentity(system-assigned):Using
FromManagedIdentity(user-assigned, with explicit audience):Using
FromConfidentialClient— reuse the same CCA instance (recommended):