Skip to content
This repository has been archived by the owner on Jun 30, 2023. It is now read-only.

Service to service calls on behalf of the user

Jean-Marc Prieur edited this page Oct 15, 2018 · 5 revisions

Web APIs can acquire tokens in the name of a user, leveraging User assertions

Web API cannot have any user interaction, and therefore when a web API (labeled "first Web API") needs to call another Web API (named "second Web API") in the name of a user, it needs to use the "On Behalf Of" OAuth 2.0 flow, which is one of the flows described in details in Daemon or Server Application to Web API (along with the client credential flows that you have already seen).

This flow is a confidential client flow, and therefore the first web API provides client credentials (client secret or certificate), as seen in the previous paragraph. However, it will also provide another parameter named the userAssertion: this time, the first web API will receive a bearer token and send it to Azure AD by embedding it into a user assertion to request another token to the downstream API.

image

How to do?

The flow is explained in details in the following sample: https://github.com/Azure-Samples/active-directory-dotnet-webapi-onbehalfof and https://github.com/Azure-Samples/active-directory-dotnet-webapi-onbehalfof-ca, this last sample demonstrates how the middle Web API needs to process claims exceptions in the case of conditional access.

The code extracting the bearer token and creating the user assertion is available from TodoListController.cs#L138-L142

ClientCredential clientCred = new ClientCredential(clientId, appKey);
ClaimsPrincipal current = ClaimsPrincipal.Current;
var bootstrapContext = current.Identities.First().BootstrapContext 
                                          as System.IdentityModel.Tokens.BootstrapContext;
string userName = current.FindFirst(ClaimTypes.Upn) != null 
    ? current.FindFirst(ClaimTypes.Upn).Value 
    : current.FindFirst(ClaimTypes.Email).Value;
string userAccessToken = bootstrapContext.Token;
UserAssertion userAssertion = new UserAssertion(userAccessToken,
                                             "urn:ietf:params:oauth:grant-type:jwt-bearer", 
                                                userName);

The web API then acquires an access token for the downstream web API using the overrides of AcquireTokenAsync having a user assertion parameter as shown in TodoListController.cs#L158

try
{
 result = await authContext.AcquireTokenSilentAsync(graphResourceId, clientId);
}
catch (AdalException adalException) 
{
 if (adalException.ErrorCode == AdalError.FailedToAcquireTokenSilently || adalException.ErrorCode == AdalError.UserInteractionRequired)
 {
  result = await authContext.AcquireTokenAsync(graphResourceId,
                                               clientCred, 
                                               userAssertion);
 }
}

Handling claim challenge exceptions.

See Handling ADAL.NET claim challenge exceptions See also Developer Guidance for Azure Active Directory Conditional Access

Samples illustrating the on-behalf-of flow with ADAL.NET

Sample Platform Description
active-directory-dotnet-webapi-onbehalfof Desktop (WPF), SPA (JavaScript), Web API (ASP.NET MVC) A .NET 4.5 MVC Web API protected by Azure AD that receives tokens from a client and uses ADAL to get tokens for calling the Microsoft Graph
active-directory-dotnet-webapi-onbehalfof-ca Desktop (WPF), SPA (JavaScript), Web API (ASP.NET MVC) A .NET 4.5 MVC Web API protected by Azure AD that receives tokens from a client and uses ADAL to get tokens for calling a downstream web API with a Conditional Access policy applied to it. This is a variation of the previous sample to illustrate processing of Conditional access
Clone this wiki locally