diff --git a/src/Microsoft.Identity.Web/ITokenAcquisition.cs b/src/Microsoft.Identity.Web/ITokenAcquisition.cs
index 69a8c387d..599f21b9d 100644
--- a/src/Microsoft.Identity.Web/ITokenAcquisition.cs
+++ b/src/Microsoft.Identity.Web/ITokenAcquisition.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System.Collections.Generic;
+using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Identity.Client;
@@ -22,8 +23,15 @@ public interface ITokenAcquisition
/// Enables to override the tenant/account for the same identity. This is useful in the
/// cases where a given account is guest in other tenants, and you want to acquire tokens for a specific tenant.
/// Azure AD B2C UserFlow to target.
+ /// Optional claims principal representing the user. If not provided, will use the signed-in
+ /// user (in a web app), or the user for which the token was received (in a web API)
+ /// cases where a given account is guest in other tenants, and you want to acquire tokens for a specific tenant, like where the user is a guest in.
/// An access token to call on behalf of the user, the downstream API characterized by its scopes.
- Task GetAccessTokenForUserAsync(IEnumerable scopes, string? tenantId = null, string? userFlow = null);
+ Task GetAccessTokenForUserAsync(
+ IEnumerable scopes,
+ string? tenantId = null,
+ string? userFlow = null,
+ ClaimsPrincipal? user = null);
///
/// Acquires a token from the authority configured in the app, for the confidential client itself (not on behalf of a user)
diff --git a/src/Microsoft.Identity.Web/Microsoft.Identity.Web.xml b/src/Microsoft.Identity.Web/Microsoft.Identity.Web.xml
index af462f1b4..569d2d0d5 100644
--- a/src/Microsoft.Identity.Web/Microsoft.Identity.Web.xml
+++ b/src/Microsoft.Identity.Web/Microsoft.Identity.Web.xml
@@ -477,6 +477,8 @@
Name Identifier ID claim: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier".
+
+
General constants.
@@ -620,7 +622,7 @@
Interface for the token acquisition service (encapsulating MSAL.NET).
-
+
Typically used from an ASP.NET Core Web App or Web API controller, this method gets an access token
for a downstream API on behalf of the user account which claims are provided in the
@@ -630,6 +632,9 @@
Enables to override the tenant/account for the same identity. This is useful in the
cases where a given account is guest in other tenants, and you want to acquire tokens for a specific tenant.
Azure AD B2C UserFlow to target.
+ Optional claims principal representing the user. If not provided, will use the signed-in
+ user (in a web app), or the user for which the token was received (in a web API)
+ cases where a given account is guest in other tenants, and you want to acquire tokens for a specific tenant, like where the user is a guest in.
An access token to call on behalf of the user, the downstream API characterized by its scopes.
@@ -1397,7 +1402,7 @@
you have previously called AddAccountToCacheFromAuthorizationCodeAsync from a method called by
OpenIdConnectOptions.Events.OnAuthorizationCodeReceived.
-
+
Typically used from a Web App or WebAPI controller, this method retrieves an access token
for a downstream API using;
@@ -1410,8 +1415,11 @@
Enables overriding of the tenant/account for the same identity. This is useful in the
cases where a given account is guest in other tenants, and you want to acquire tokens for a specific tenant, like where the user is a guest in.
Azure AD B2C user flow to target.
+ Optional claims principal representing the user. If not provided, will use the signed-in
+ user (in a web app), or the user for which the token was received (in a Web API)
+ cases where a given account is guest in other tenants, and you want to acquire tokens for a specific tenant, like where the user is a guest in.
An access token to call the downstream API and populated with this downstream API's scopes.
- Calling this method from a Web API supposes that you have previously called,
+ Calling this method from a web API supposes that you have previously called,
in a method called by JwtBearerOptions.Events.OnTokenValidated, the HttpContextExtensions.StoreTokenUsedToCallWebAPI method
passing the validated token (as a JwtSecurityToken). Calling it from a Web App supposes that
you have previously called AddAccountToCacheFromAuthorizationCodeAsync from a method called by
diff --git a/src/Microsoft.Identity.Web/TokenAcquisition.cs b/src/Microsoft.Identity.Web/TokenAcquisition.cs
index b27d85f14..797c4b664 100644
--- a/src/Microsoft.Identity.Web/TokenAcquisition.cs
+++ b/src/Microsoft.Identity.Web/TokenAcquisition.cs
@@ -191,8 +191,11 @@ public async Task GetAccessTokenOnBehalfOfUserAsync(
/// Enables overriding of the tenant/account for the same identity. This is useful in the
/// cases where a given account is guest in other tenants, and you want to acquire tokens for a specific tenant, like where the user is a guest in.
/// Azure AD B2C user flow to target.
+ /// Optional claims principal representing the user. If not provided, will use the signed-in
+ /// user (in a web app), or the user for which the token was received (in a Web API)
+ /// cases where a given account is guest in other tenants, and you want to acquire tokens for a specific tenant, like where the user is a guest in.
/// An access token to call the downstream API and populated with this downstream API's scopes.
- /// Calling this method from a Web API supposes that you have previously called,
+ /// Calling this method from a web API supposes that you have previously called,
/// in a method called by JwtBearerOptions.Events.OnTokenValidated, the HttpContextExtensions.StoreTokenUsedToCallWebAPI method
/// passing the validated token (as a JwtSecurityToken). Calling it from a Web App supposes that
/// you have previously called AddAccountToCacheFromAuthorizationCodeAsync from a method called by
@@ -200,7 +203,8 @@ public async Task GetAccessTokenOnBehalfOfUserAsync(
public async Task GetAccessTokenForUserAsync(
IEnumerable scopes,
string? tenant = null,
- string? userFlow = null)
+ string? userFlow = null,
+ ClaimsPrincipal? user = null)
{
if (scopes == null)
{
@@ -215,7 +219,7 @@ public async Task GetAccessTokenForUserAsync(
{
accessToken = await GetAccessTokenOnBehalfOfUserFromCacheAsync(
_application,
- CurrentHttpContext.User,
+ user ?? CurrentHttpContext.User,
scopes,
tenant,
userFlow)
@@ -334,12 +338,16 @@ private async Task GetOrBuildConfidentialClientA
///
private async Task BuildConfidentialClientApplicationAsync()
{
- var request = CurrentHttpContext.Request;
- string currentUri = UriHelper.BuildAbsolute(
- request.Scheme,
- request.Host,
- request.PathBase,
- _microsoftIdentityOptions.CallbackPath.Value ?? string.Empty);
+ var request = CurrentHttpContext?.Request;
+ string? currentUri = null;
+ if (request != null)
+ {
+ currentUri = UriHelper.BuildAbsolute(
+ request.Scheme,
+ request.Host,
+ request.PathBase,
+ _microsoftIdentityOptions.CallbackPath.Value ?? string.Empty);
+ }
if (!_applicationOptions.Instance.EndsWith("/", StringComparison.InvariantCulture))
{
@@ -354,9 +362,14 @@ private async Task BuildConfidentialClientApplic
{
var builder = ConfidentialClientApplicationBuilder
.CreateWithApplicationOptions(_applicationOptions)
- .WithRedirectUri(currentUri)
.WithHttpClientFactory(_httpClientFactory);
+ // The redirect URI is not needed for OBO
+ if (!string.IsNullOrEmpty(currentUri))
+ {
+ builder.WithRedirectUri(currentUri);
+ }
+
string authority;
if (_microsoftIdentityOptions.IsB2C)