-
Notifications
You must be signed in to change notification settings - Fork 400
Implement UserFIC: IByUserFederatedIdentityCredential interface and user_fic grant type #5802
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
neha-bhargava
merged 13 commits into
main
from
copilot/add-federated-credential-provider
Mar 18, 2026
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
09ad389
Initial plan
Copilot 3120319
Implement UserFIC: Add FederatedCredentialProvider, IByUserFederatedI…
Copilot 08403bd
Fix missing newline in PublicAPI.Unshipped.txt and unused variable in…
Copilot b91c792
Merge branch 'main' into copilot/add-federated-credential-provider
neha-bhargava 7654c5e
Add integration tests for UserFIC flow using ficuser@msidlabtse4.onmi…
Copilot 50ef8b9
Update integration tests to pick up the user and tenant from KV
neha-bhargava 2352c7e
Update the agentic tests to use user fic
neha-bhargava 1a96c32
Use single app instance for both assertion source and token acquisiti…
Copilot 6093243
Remove FederatedCredentialProvider, simplify UserFIC API to accept pl…
Copilot b09ed11
Merge branch 'main' into copilot/add-federated-credential-provider
neha-bhargava c457ed1
Merge branch 'main' into copilot/add-federated-credential-provider
neha-bhargava bd330b3
Remove UserFederatedIdentityCredentialIntegrationTests.cs
Copilot f025754
Fix compile failures
neha-bhargava File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
109 changes: 109 additions & 0 deletions
109
...dentity.Client/ApiConfig/AcquireTokenByUserFederatedIdentityCredentialParameterBuilder.cs
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
| using Microsoft.Identity.Client.ApiConfig.Executors; | ||
| using Microsoft.Identity.Client.ApiConfig.Parameters; | ||
| using Microsoft.Identity.Client.TelemetryCore.Internal.Events; | ||
|
|
||
| namespace Microsoft.Identity.Client | ||
| { | ||
| /// <summary> | ||
| /// Parameter builder for the <see cref="IByUserFederatedIdentityCredential.AcquireTokenByUserFederatedIdentityCredential(IEnumerable{string}, string, string)"/> | ||
| /// operation. | ||
| /// </summary> | ||
| #if !SUPPORTS_CONFIDENTIAL_CLIENT | ||
| [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] // hide confidential client on mobile | ||
| #endif | ||
| public sealed class AcquireTokenByUserFederatedIdentityCredentialParameterBuilder : | ||
| AbstractConfidentialClientAcquireTokenParameterBuilder<AcquireTokenByUserFederatedIdentityCredentialParameterBuilder> | ||
| { | ||
| private AcquireTokenByUserFederatedIdentityCredentialParameters Parameters { get; } = new AcquireTokenByUserFederatedIdentityCredentialParameters(); | ||
|
|
||
| internal AcquireTokenByUserFederatedIdentityCredentialParameterBuilder( | ||
| IConfidentialClientApplicationExecutor confidentialClientApplicationExecutor, | ||
| string username, | ||
| string assertion) | ||
| : base(confidentialClientApplicationExecutor) | ||
| { | ||
| Parameters.Username = username; | ||
| Parameters.Assertion = assertion; | ||
| } | ||
|
|
||
| internal static AcquireTokenByUserFederatedIdentityCredentialParameterBuilder Create( | ||
| IConfidentialClientApplicationExecutor confidentialClientApplicationExecutor, | ||
| IEnumerable<string> scopes, | ||
| string username, | ||
| string assertion) | ||
| { | ||
| if (string.IsNullOrEmpty(username)) | ||
| { | ||
| throw new ArgumentNullException(nameof(username)); | ||
| } | ||
|
|
||
| if (string.IsNullOrEmpty(assertion)) | ||
| { | ||
| throw new ArgumentNullException(nameof(assertion)); | ||
| } | ||
|
|
||
| return new AcquireTokenByUserFederatedIdentityCredentialParameterBuilder( | ||
| confidentialClientApplicationExecutor, username, assertion) | ||
| .WithScopes(scopes); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Forces MSAL to refresh the token from the identity provider even if a cached token is available. | ||
| /// </summary> | ||
| /// <param name="forceRefresh"><c>true</c> to bypass the cache; otherwise <c>false</c>. Default is <c>false</c>.</param> | ||
| /// <returns>The builder to chain the .With methods</returns> | ||
| public AcquireTokenByUserFederatedIdentityCredentialParameterBuilder WithForceRefresh(bool forceRefresh) | ||
| { | ||
| Parameters.ForceRefresh = forceRefresh; | ||
| return this; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Applicable to first-party applications only, this method also allows to specify | ||
| /// if the <see href="https://datatracker.ietf.org/doc/html/rfc7517#section-4.7">x5c claim</see> should be sent to Azure AD. | ||
| /// Sending the x5c enables application developers to achieve easy certificate roll-over in Azure AD: | ||
| /// this method will send the certificate chain to Azure AD along with the token request, | ||
| /// so that Azure AD can use it to validate the subject name based on a trusted issuer policy. | ||
| /// This saves the application admin from the need to explicitly manage the certificate rollover | ||
| /// (either via portal or PowerShell/CLI operation). For details see https://aka.ms/msal-net-sni | ||
| /// </summary> | ||
| /// <param name="withSendX5C"><c>true</c> if the x5c should be sent. Otherwise <c>false</c>. | ||
| /// The default is <c>false</c></param> | ||
| /// <returns>The builder to chain the .With methods</returns> | ||
| public AcquireTokenByUserFederatedIdentityCredentialParameterBuilder WithSendX5C(bool withSendX5C) | ||
| { | ||
| Parameters.SendX5C = withSendX5C; | ||
| return this; | ||
| } | ||
|
|
||
| /// <inheritdoc/> | ||
| internal override Task<AuthenticationResult> ExecuteInternalAsync(CancellationToken cancellationToken) | ||
| { | ||
| return ConfidentialClientApplicationExecutor.ExecuteAsync(CommonParameters, Parameters, cancellationToken); | ||
| } | ||
|
|
||
| /// <inheritdoc/> | ||
| internal override ApiEvent.ApiIds CalculateApiEventId() | ||
| { | ||
| return ApiEvent.ApiIds.AcquireTokenByUserFederatedIdentityCredential; | ||
| } | ||
|
|
||
| /// <inheritdoc/> | ||
| protected override void Validate() | ||
| { | ||
| base.Validate(); | ||
|
|
||
| if (Parameters.SendX5C == null) | ||
| { | ||
| Parameters.SendX5C = ServiceBundle.Config?.SendX5C ?? false; | ||
| } | ||
| } | ||
| } | ||
| } |
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
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
20 changes: 20 additions & 0 deletions
20
...ty.Client/ApiConfig/Parameters/AcquireTokenByUserFederatedIdentityCredentialParameters.cs
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using Microsoft.Identity.Client.Core; | ||
|
|
||
| namespace Microsoft.Identity.Client.ApiConfig.Parameters | ||
| { | ||
| internal class AcquireTokenByUserFederatedIdentityCredentialParameters : IAcquireTokenParameters | ||
| { | ||
| public string Username { get; set; } | ||
| public string Assertion { get; set; } | ||
| public bool? SendX5C { get; set; } | ||
| public bool ForceRefresh { get; set; } | ||
|
|
||
| /// <inheritdoc/> | ||
| public void LogParameters(ILoggerAdapter logger) | ||
| { | ||
| } | ||
| } | ||
| } |
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
32 changes: 32 additions & 0 deletions
32
src/client/Microsoft.Identity.Client/IByUserFederatedIdentityCredential.cs
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System.Collections.Generic; | ||
|
|
||
| namespace Microsoft.Identity.Client | ||
| { | ||
| /// <summary> | ||
| /// Provides an interface for acquiring tokens using the User Federated Identity Credential (UserFIC) flow. | ||
| /// </summary> | ||
| #if !SUPPORTS_CONFIDENTIAL_CLIENT | ||
| [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] // hide confidential client on mobile | ||
| #endif | ||
| public interface IByUserFederatedIdentityCredential | ||
| { | ||
| /// <summary> | ||
| /// Acquires a token on behalf of a user using a federated identity credential assertion. | ||
| /// This uses the <c>user_fic</c> grant type. | ||
| /// </summary> | ||
| /// <param name="scopes">Scopes requested to access a protected API.</param> | ||
| /// <param name="username">The UPN (User Principal Name) of the user, e.g. <c>john.doe@contoso.com</c>.</param> | ||
| /// <param name="assertion"> | ||
| /// The federated identity credential assertion (JWT) for the user. | ||
| /// Acquire this token from a Managed Identity or Confidential Client application before calling this method. | ||
| /// </param> | ||
| /// <returns>A builder enabling you to add optional parameters before executing the token request.</returns> | ||
| AcquireTokenByUserFederatedIdentityCredentialParameterBuilder AcquireTokenByUserFederatedIdentityCredential( | ||
| IEnumerable<string> scopes, | ||
| string username, | ||
| string assertion); | ||
| } | ||
| } |
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
64 changes: 64 additions & 0 deletions
64
...ent/Microsoft.Identity.Client/Internal/Requests/UserFederatedIdentityCredentialRequest.cs
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System.Collections.Generic; | ||
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
| using Microsoft.Identity.Client.ApiConfig.Parameters; | ||
| using Microsoft.Identity.Client.OAuth2; | ||
| using Microsoft.Identity.Client.Utils; | ||
|
|
||
| namespace Microsoft.Identity.Client.Internal.Requests | ||
| { | ||
| internal class UserFederatedIdentityCredentialRequest : RequestBase | ||
| { | ||
| private readonly AcquireTokenByUserFederatedIdentityCredentialParameters _userFicParameters; | ||
|
|
||
| public UserFederatedIdentityCredentialRequest( | ||
| IServiceBundle serviceBundle, | ||
| AuthenticationRequestParameters authenticationRequestParameters, | ||
| AcquireTokenByUserFederatedIdentityCredentialParameters userFicParameters) | ||
| : base(serviceBundle, authenticationRequestParameters, userFicParameters) | ||
| { | ||
| _userFicParameters = userFicParameters; | ||
| } | ||
|
|
||
| protected override async Task<AuthenticationResult> ExecuteAsync(CancellationToken cancellationToken) | ||
| { | ||
| await ResolveAuthorityAsync().ConfigureAwait(false); | ||
|
|
||
| var additionalBodyParameters = GetAdditionalBodyParameters(_userFicParameters.Assertion); | ||
| MsalTokenResponse msalTokenResponse = await SendTokenRequestAsync(additionalBodyParameters, cancellationToken).ConfigureAwait(false); | ||
|
|
||
| return await CacheTokenResponseAndCreateAuthenticationResultAsync(msalTokenResponse, cancellationToken).ConfigureAwait(false); | ||
| } | ||
|
|
||
| private Dictionary<string, string> GetAdditionalBodyParameters(string assertion) | ||
| { | ||
| var dict = new Dictionary<string, string> | ||
| { | ||
| [OAuth2Parameter.GrantType] = OAuth2GrantType.UserFic, | ||
| [OAuth2Parameter.Username] = _userFicParameters.Username, | ||
| [OAuth2Parameter.UserFederatedIdentityCredential] = assertion | ||
| }; | ||
|
|
||
| ISet<string> unionScope = new HashSet<string> | ||
| { | ||
| OAuth2Value.ScopeOpenId, | ||
| OAuth2Value.ScopeOfflineAccess, | ||
| OAuth2Value.ScopeProfile | ||
| }; | ||
|
|
||
| unionScope.UnionWith(AuthenticationRequestParameters.Scope); | ||
| dict[OAuth2Parameter.Scope] = unionScope.AsSingleString(); | ||
| dict[OAuth2Parameter.ClientInfo] = "1"; | ||
|
|
||
| return dict; | ||
| } | ||
|
|
||
| protected override KeyValuePair<string, string>? GetCcsHeader(IDictionary<string, string> additionalBodyParameters) | ||
| { | ||
| return GetCcsUpnHeader(_userFicParameters.Username); | ||
| } | ||
| } | ||
| } | ||
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder.WithForceRefresh(bool forceRefresh) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder.WithSendX5C(bool withSendX5C) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.IByUserFederatedIdentityCredential | ||
| Microsoft.Identity.Client.IByUserFederatedIdentityCredential.AcquireTokenByUserFederatedIdentityCredential(System.Collections.Generic.IEnumerable<string> scopes, string username, string assertion) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder.WithForceRefresh(bool forceRefresh) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder.WithSendX5C(bool withSendX5C) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.IByUserFederatedIdentityCredential | ||
| Microsoft.Identity.Client.IByUserFederatedIdentityCredential.AcquireTokenByUserFederatedIdentityCredential(System.Collections.Generic.IEnumerable<string> scopes, string username, string assertion) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder.WithForceRefresh(bool forceRefresh) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder.WithSendX5C(bool withSendX5C) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.IByUserFederatedIdentityCredential | ||
| Microsoft.Identity.Client.IByUserFederatedIdentityCredential.AcquireTokenByUserFederatedIdentityCredential(System.Collections.Generic.IEnumerable<string> scopes, string username, string assertion) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder.WithForceRefresh(bool forceRefresh) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder.WithSendX5C(bool withSendX5C) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.IByUserFederatedIdentityCredential | ||
| Microsoft.Identity.Client.IByUserFederatedIdentityCredential.AcquireTokenByUserFederatedIdentityCredential(System.Collections.Generic.IEnumerable<string> scopes, string username, string assertion) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder.WithForceRefresh(bool forceRefresh) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder.WithSendX5C(bool withSendX5C) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.IByUserFederatedIdentityCredential | ||
| Microsoft.Identity.Client.IByUserFederatedIdentityCredential.AcquireTokenByUserFederatedIdentityCredential(System.Collections.Generic.IEnumerable<string> scopes, string username, string assertion) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder.WithForceRefresh(bool forceRefresh) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder.WithSendX5C(bool withSendX5C) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder | ||
| Microsoft.Identity.Client.IByUserFederatedIdentityCredential | ||
| Microsoft.Identity.Client.IByUserFederatedIdentityCredential.AcquireTokenByUserFederatedIdentityCredential(System.Collections.Generic.IEnumerable<string> scopes, string username, string assertion) -> Microsoft.Identity.Client.AcquireTokenByUserFederatedIdentityCredentialParameterBuilder |
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
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.