Microsoft Azure Active Directory supports an OAuth2 protocol extension called On-Behalf-Of flow (OBO flow). This is documented at both the Microsoft Identity Platform V1 and V2 endpoint. The OBO flow is used in the following scenario. Both Web API 1 and Web API 2 are protected by Azure AD.
- A client application (could be a SPA app, a front-end Web Application, or a native application) signs a user into Azure AD and request a delegated access token for Web API 1
- Client application then calls Web API 1 with the issued access token
- Web API 1 in turn needs to call a downstream Web API 2 so it uses its access token (in step 2 above) to request an access token for Web API 2. What happens in this step is that Web API 1 uses the OBO flow to exchange its access token for another resource’s access token. The exchanged token is still issued on behalf of the original sign in user and it has delegated permission.
- Web API 2 uses the new access token to call Web API 2
Let’s look at the parameters used in an OBO flow at the V1 endpoint below. I want to call out a few highlighted parameters as their significance will become more obvious a little bit later.
this is the access token issued in step 2 above
application id of Web API 1
this is Application ID URI or Application ID of Web API 2
Let’s look at an OBO end to end traffic in Fiddler:
Frame 1 – 14 below shows the user navigates to the web site and is redirected to Azure AD to log in. Frame 15 is the request to the token endpoint to get an access token for Web API 1
Hover over image to enlarge
In this example Web API 2 is Microsoft Graph. In frame 19 below Web API 1 uses an OBO flow to request a token for Microsoft Graph. It uses the access token received in frame 15 as the assertion parameter.
Hover over image to enlarge
It is extremely important to use the correct parameter in the OBO flow. Note that the OBO parameters client_id and the assertion (access token) are for the calling application (Web API 1) in this token exchange request.
Common pitfall customers run into when using the OBO flow
I have seen a few AADSTS error returned for this flow when either the client_id or the assertion parameters used are not for the calling application (Web API 1). Below are a few examples:
HTTP 400 error: AADSTS500131: Assertion audience does not match the Client app presenting the assertion. The audience in the assertion was ‘00000002-0000-0000-c000-000000000000’ and the expected audience is …
Root cause: The access token used in the assertion is for a different application / resource instead of for the calling app Web API 1. The GUID in this error is an Azure AD Graph resource.
HTTP 400 error: AADSTS50013: Assertion failed signature validation. [Reason – The provided signature value did not match the expected signature value., Thumbprint of key used by client:…
Root cause: The access token used in the assertion is for Microsoft Graph resource (https://graph.microsoft.com)
HTTP 400 error: AADSTS50013: Assertion failed signature validation. [Reason – The key was not found., Thumbprint of key used by client: ‘B25930C…..
Root cause: Web API 1 is a SAML Application (check the Enterprise Application blade to see if Single sign-on is enabled and there is a SAML signing Certificate attached).
HTTP 500 error: AADSTS50000: There was an error issuing a token.
Root cause: the client id used is either not valid or does not exist in the tenant.
How can I diagnose this issue?
- Take a Fiddler trace to see what the parameters used are.
Use https://jwt.ms to decode the access token assertion and look at the “aud” (audience) claim to see if it’s for the calling web API 1
What if my Web API 2 is SAML Application?
If the downstream API App can only consume SAML token (instead of jwt token), you can certainly use the OBO flow to exchange a JWT token for the SAML token using the following parameters (see https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-on-behalf-of-flow for more info). The key is in the parameter requested_token_type. The allowed values are
urn:ietf:params:oauth:token-type:saml2 – SAML 2.0 token
urn:ietf:params:oauth:token-type:saml1 – SAML 1.1 token
this JWT – SAML token exchange OBO flow is only available in the V1 endpoint since the V2 endpoint does not support SAML token. See https://docs.microsoft.com/en-us/azure/active-directory/develop/azure-ad-endpoint-comparison for more info
What about Azure AD B2C?
The OBO flow is currently not supported in Azure AD B2C per https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-apps#web-api-chains-on-behalf-of-flow
Drop me a comment if you find this useful or any other important information I should add.
Update 8/22 – added one more condition for error AADSTS50013 due to SAML App