Skip to content

Add User Federated Identity Credential (UserFIC) flow to ConfidentialClientApplication#5787

Closed
Copilot wants to merge 4 commits intomainfrom
copilot/add-msal-api-user-fic
Closed

Add User Federated Identity Credential (UserFIC) flow to ConfidentialClientApplication#5787
Copilot wants to merge 4 commits intomainfrom
copilot/add-msal-api-user-fic

Conversation

Copy link
Contributor

Copilot AI commented Feb 25, 2026

Adds a first-class MSAL API for acquiring user-scoped tokens using a federated identity credential assertion (e.g., Managed Identity or client credentials token) instead of a password. The underlying OAuth flow uses grant_type=user_fic, username, and user_federated_identity_credential.

New public API surface

  • IByUserFederatedIdentityCredential interface with AcquireTokenByUserFederatedIdentityCredential(scopes, username, assertionCallback, tokenExchangeScope)
  • AcquireTokenByUserFederatedIdentityCredentialParameterBuilder with .WithSendX5C() and .WithForceRefresh()
  • ConfidentialClientApplication now implements IByUserFederatedIdentityCredential

Usage pattern (callback-based, lazy assertion evaluation):

var result = await (app as IByUserFederatedIdentityCredential)
    .AcquireTokenByUserFederatedIdentityCredential(
        scopes: new[] { "https://graph.microsoft.com/.default" },
        username: "user@contoso.com",
        assertionCallback: async () =>
        {
            var mi = await miApp.AcquireTokenForManagedIdentity("api://AzureADTokenExchange/.default").ExecuteAsync();
            return mi.AccessToken;
        })
    .ExecuteAsync();

// Subsequent calls use standard AcquireTokenSilent (callback NOT invoked)
IAccount account = await app.GetAccountAsync(result.Account.HomeAccountId.Identifier);
var cached = await app.AcquireTokenSilent(scopes, account).ExecuteAsync();

Key implementation files

  • IByUserFederatedIdentityCredential.cs — new interface
  • AcquireTokenByUserFederatedIdentityCredentialParameters.cs — internal parameters
  • AcquireTokenByUserFederatedIdentityCredentialParameterBuilder.cs — fluent builder
  • UserFederatedIdentityCredentialRequest.cs — request handler; invokes callback, sends grant_type=user_fic body, stores result in user token cache (same partition as ROPC/OBO)
  • OAuthConstants.cs — added OAuth2GrantType.UserFic and OAuth2Parameter.UserFederatedIdentityCredential
  • ConfidentialClientExecutor.cs / IConfidentialClientApplicationExecutor.cs — wired new executor overload
  • All 6 TFM PublicAPI.Unshipped.txt files updated

Testing

  • 6 unit tests in UserFederatedIdentityCredentialTests.cs: happy path, cache hit (callback not re-invoked), force refresh (callback re-invoked), null argument guards, request body validation (grant_type, username, user_federated_identity_credential)
  • 3 integration tests in UserFicIntegrationTests.cs targeting ficadmin@msidlabtse4.onmicrosoft.com / 979a25aa-0daf-41a5-bcad-cebec5c7c254 using the lab auth cert, covering: initial token from IdP, silent cache hit, force refresh

Performance impact
No impact on existing flows. New flow follows identical code path as ROPC (network + user cache write).

Documentation

  • All relevant documentation is updated.
Original prompt

This section details on the original issue you should resolve

<issue_title>[Feature Request] Add MSAL .NET API for User FIC</issue_title>
<issue_description>### MSAL client type

Confidential

Problem statement

Internal partners moving off passwords for test automation need a first-class MSAL API to acquire tokens for a specific user using User Federated Identity Credentials (User FIC). The underlying token endpoint flow is ROPC-like but uses a federated user credential JWT instead of a password, via grant_type=user_fic, username, and user_federated_identity_credential.

Proposed solution

Proposed API (DevEx)

Summary

Add support for User Federated Identity Credential (UserFIC) flow to IConfidentialClientApplication, enabling acquisition of user-scoped tokens using federated identity credential assertions instead of passwords.

OAuth Flow:

  • grant_type: user_fic
  • Parameters: username, user_federated_identity_credential (assertion), scope
  • Returns user-scoped access token with account information in cache

Proposed API

Core Interface

namespace Microsoft.Identity.Client
{
    /// <summary>
    /// Provides methods to acquire tokens using User Federated Identity Credential (UserFIC) flow.
    /// </summary>
    public interface IByUserFederatedIdentityCredential
    {
        /// <summary>
        /// Acquires a user-scoped token using federated identity credential assertion.
        /// </summary>
        /// <param name="scopes">Scopes requested to access a protected API</param>
        /// <param name="username">User principal name (e.g., user@contoso.com)</param>
        /// <param name="assertionCallback">
        /// Callback to provide the assertion token. Invoked when acquiring new tokens (not from cache).
        /// </param>
        /// <param name="tokenExchangeScope">
        /// Scope for assertion token. Defaults to "api://AzureADTokenExchange/.default".
        /// Use "api://AzureADTokenExchangeUSGov/.default" for US Gov,
        /// "api://AzureADTokenExchangeChina/.default" for China.
        /// </param>
        AcquireTokenByUserFederatedIdentityCredentialParameterBuilder 
            AcquireTokenByUserFederatedIdentityCredential(
                IEnumerable<string> scopes,
                string username,
                Func<Task<string>> assertionCallback,
                string tokenExchangeScope = "api://AzureADTokenExchange/.default");
    }
}

Parameter Builder

namespace Microsoft.Identity.Client
{
    public sealed class AcquireTokenByUserFederatedIdentityCredentialParameterBuilder :
        AbstractConfidentialClientAcquireTokenParameterBuilder<AcquireTokenByUserFederatedIdentityCredentialParameterBuilder>
    {
        public AcquireTokenByUserFederatedIdentityCredentialParameterBuilder WithSendX5C(bool sendX5C);
        public AcquireTokenByUserFederatedIdentityCredentialParameterBuilder WithClaims(string claims);
        public AcquireTokenByUserFederatedIdentityCredentialParameterBuilder WithCorrelationId(Guid correlationId);
        public AcquireTokenByUserFederatedIdentityCredentialParameterBuilder WithProofOfPossession(PoPAuthenticationConfiguration popConfig);
        public AcquireTokenByUserFederatedIdentityCredentialParameterBuilder WithForceRefresh(bool forceRefresh);
        public Task<AuthenticationResult> ExecuteAsync(CancellationToken cancellationToken = default);
    }
}

Usage Examples

Example 1: Managed Identity as Assertion Source

// Setup (reuse these instances)
var miApp = ManagedIdentityApplicationBuilder
    .Create(ManagedIdentityId.SystemAssigned)
    .Build();

var confidentialApp = ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithAuthority($"https://login.microsoftonline.com/{tenantId}")
    .WithCertificate(cert)
    .Build();

// Acquire user-scoped token
var result = await confidentialApp
    .AcquireTokenByUserFederatedIdentityCredential(
        scopes: new[] { "User.Read", "Mail.Send" },
        username: "user@contoso.com",
        assertionCallback: async () =>
        {
            var miResult = await miApp
                .AcquireTokenForManagedIdentity("api://AzureADTokenExchange/.default")
                .ExecuteAsync();
            return miResult.AccessToken;
        })
    .ExecuteAsync();

// Result contains user context
Console.WriteLine($"User: {result.Account.Username}");
Console.WriteLine($"Token Source: {result.AuthenticationResultMetadata.TokenSource}"); // IdentityProvider

Example 2: Client Credentials (Certificate) as Assertion Source

// Separate app for getting assertions (using certificate)
var assertionApp = ConfidentialClientApplicationBuilder
    .Create(assertionAppId)
    .WithAuthority($"https://login.microsoftonline.com/{tenantId}")
    .WithCertificate(assertionCert)
    .Build();

var mainApp = ConfidentialClientApplicationBuilder
    .Create(mainAppId)
    .WithAuthorit...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes AzureAD/microsoft-authentication-library-for-dotnet#5766

<!-- START COPILOT CODING AGENT TIPS -->
---Let Copilot coding agent [set things up for you](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo.

…dentialClientApplication

Co-authored-by: neha-bhargava <61847233+neha-bhargava@users.noreply.github.com>
Copilot AI changed the title [WIP] Add MSAL .NET API for User Federated Identity Credentials Add User Federated Identity Credential (UserFIC) flow to ConfidentialClientApplication Feb 25, 2026
@neha-bhargava neha-bhargava linked an issue Mar 2, 2026 that may be closed by this pull request
@neha-bhargava
Copy link
Contributor

Completed the work in another PR

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.

[Feature Request] Add MSAL .NET API for User FIC

2 participants