2

I've got a single page app that authenticates users in Azure using adal-angular.js/adal.js [client].
The returned token is inserted into the auth header and passed to a web API [server]. This web api generates a new access token for the app using the on-behalf-of workflow (https://github.com/Azure-Samples/active-directory-dotnet-webapi-onbehalfof) This token is then used to call a downstream API [API1]. So the downstream API then repeats this process to get a new token to call another API [API2]. It's at this point that I'm getting the above error.

The aud value in the token passed from [client] to [server] is the application id of the [server] app. The aud value in the token passed from the [server] to [API1] is the Application URI of the [API1] app. So far so good.

When I call AcquireTokenAsync in [API1] app, I get the following error:

AADSTS70002: Error validating credentials. AADSTS50013: Assertion audience claim does not match the required value. The audience in the assertion was 'http://application_uri.com/' and the expected audience is 'snip-a1d5-e82e84f4e19e' or one of the Application Uris of this application with App ID 'snip-a1d5-e82e84f4e19e'

The relevant code from [API1]:

public static async Task<string> GetApplicationTokenOnBehalfOfUser(string appId, string appKey)
    {
        var clientCredential = new ClientCredential(appId, appKey);
        var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as
                System.IdentityModel.Tokens.BootstrapContext;
        var userName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
        var userAccessToken = bootstrapContext.Token;
        var userAssertion = new UserAssertion(userAccessToken, _assertionType, userName);
        var authority = string.Format(System.Globalization.CultureInfo.InvariantCulture, _aadInstance, _tenant);

        var userId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
        var authContext = new AuthenticationContext(authority, new TokenCache());

        var result = await authContext.AcquireTokenAsync(_resourceId, clientCredential, userAssertion);
        var accessToken = result.AccessToken;
        return accessToken;
    }

Where: appId = "snip-a1d5-e82e84f4e19e"

And the "aud" value from the BootstrapContext.Token is: "aud": "http://application_uri.com/"

If I change the above to use the "aud" value from the token as the appId in the ClientCredential, I get this error instead:

AADSTS65001: The user or administrator has not consented to use the application with ID 'http://application_uri.com/'. Send an interactive authorization request for this user and resource.

Am I doing this right? Thanks.

gooram
  • 89
  • 2
  • 16

2 Answers2

0

AADSTS70002: Error validating credentials. AADSTS50013: Assertion audience claim does not match the required value. The audience in the assertion was 'http://application_uri.com/' and the expected audience is 'snip-a1d5-e82e84f4e19e' or one of the Application Uris of this application with App ID 'snip-a1d5-e82e84f4e19e'

To use the on-behalf-of flow, we need to provide the access token for the API1 and provide the clientId and secrect of API1 to request the access token for the API2.

AADSTS65001: The user or administrator has not consented to use the application with ID 'http://application_uri.com/'. Send an interactive authorization request for this user and resource.

Before that tenant users can use the app, the corresponding service principal must be register to that tenant first by permission grant. Is API2 is not in the tenant of the users sign-in?

If I understand correctly, we need to specify the knownClientApplications in the manifest of API1(http://application_uri.com/') with the client_id of your SPA, and it also require to set the permission of API1 to the SPA. After that, when the users sign-in your SPA, the API1 app will also register to the users' tenant.

More detail about multi-tier applications please refer the document below:

How to sign in any Azure Active Directory (AD) user using the multi-tenant application pattern

Update( append the test result to explain)

enter image description here

Fei Xue
  • 14,369
  • 1
  • 19
  • 27
  • No, all apps are in the same tenant. Re this: "To use the on-behalf-of flow, we need to provide the access token for the API1 and provide the clientId and secrect of API1 to request the access token for the API2." I believe I am doing this, only concern is that the aud value in the AP1 token is the app URI and not the appId. – gooram Mar 21 '17 at 07:01
  • The aud value in the API1 token is the app URI(app id URI of API1 which repsents the resource) is expected. Please make sure that the app `http://application_uri.com/` is on the same tenant as the users sign-in SPA. – Fei Xue Mar 21 '17 at 07:43
  • Yes the API1 app is on the same tenant as both the SPA and API2. As in the original post, when I change the ClientCredential to use the AppUri and AppKey (instead of the AppId and AppKey), I get the AADSTS65001 error. Is this what I should be doing? And if so, how do I consent the App URI for access to API2? – gooram Mar 21 '17 at 07:56
  • If you register the apps using Azure portal and developing with single-tenant app, there is no need to give the consent for the apps. When we register the apps on the portal, it already give the consent by default. Since the scenario is complex, I am trying to explain it in a figure for your reference. – Fei Xue Mar 21 '17 at 08:10
-1

To get this working I had to add the following delegated permissions to API1 for AP2. Azure Permissions

gooram
  • 89
  • 2
  • 16
  • 1
    How did you add these permissions exactly? Is there a step-by-step guide you can point me to? When I try to add "Required permissions" in the Azure portal for "API1" app registration, I only see a single delegated permission that I can select called, "Access ". – Scott Lin Jun 29 '17 at 00:26
  • This image was taken from the legacy portal, in the new Azure portal, you're right, you only need to delegate to the downstream API and that's it. – gooram Apr 20 '18 at 01:42