12
votes

I have create a webapi secured with azure active directory. I need to test this now and trying to use fiddler with an authorization header. I am trying to generate the token with below code.

Target obj = (Target)cmbTarget.SelectedItem;

AuthenticationResult authenticationResult;
string aadInstance = obj.AADInstance; // "https://login.windows.net/{0}";
string tenant = obj.Tenant; //"rudderless.onmicrosoft.com";
string apiResourceId = obj.ApiResourceId; //"15b4ac7f-23a8-4958-96a5-64159254690d";
string clientId = obj.ClientId; // "47cdc6c3-226a-4c38-b08e-055be8409056";

Uri redirectUri = new Uri(obj.RedirectUri); //new Uri("http://nativeclient");
string authority = string.Format(aadInstance, tenant);
authContext = new AuthenticationContext(authority);

authenticationResult = this.authContext.AcquireToken(apiResourceId, 
                            clientId, redirectUri, PromptBehavior.Always);

txtToken.Text = authenticationResult.AccessToken;
Clipboard.SetText($"Bearer {txtToken.Text}");

I get the token generated successfully and when I am using the token to call the webapi it throwing 401 with message

WWW-Authenticate: Bearer error="invalid_token", error_description="The audience is invalid"

7
As far as I know, you could configure Audience as the CLIENT ID or APP ID URI of your Web API application secured by AD. According to the error you provided, I assumed that you could try to check the audience in your Web API application and the ResourceId in your client app.Bruce Chen
Any solution here? Having the same problem.SolarX
You need to pass scope/audience while requesting token. Here is a link to Microsoft documentation 1. docs.microsoft.com/en-us/azure/active-directory-b2c/… 2. docs.microsoft.com/en-us/azure/storage/common/…koopar
Try passing resourceUri instead of apiResourceId as in this example --> docs.microsoft.com/en-us/rest/api/datacatalog/…koopar

7 Answers

19
votes

I think it is important to revisit the different steps of authentication, and hopefully through the discussion you will be able to solve the issue you are having.

When a client is trying to get an access token to a resource, it needs to specify to AAD which resource it wants to get a token for. A client may be configured to call multiple resources, all with different configurations, so it is an expectation that the resource is always specified in an Access Token Request.

The resource can either be an App ID GUID for the Resource, or a valid App ID URI which is registered on the Resource. AAD should be able to uniquely identify which resource you are trying to reach based on the value you provide. However, note that if you use an App ID GUID, you will get a token from AAD where the Audience claim is the App ID GUID. Alternatively, if you use an App ID URI, you will see that URI as the audience claim in the token.

In both situations, you will get a token for the 'same' resource, but the claim in the token will appear differently. Additionally, it may be possible that a single application resource may have multiple App ID URIs registered on their app. Depending on which one you use in the authentication request, you will get a different audience claim in the token which matches the resource parameter you passed in.

Finally, once you get the token, you send it over to the Resource API who will validate the token for a number of things, such as: the Client ID Claim, the Scopes/Roles Claims, the authentication method ('acr' claim), and definitely that the audience claim matches what they expect!

This means that the Resource API ultimately needs to say "I accept < App ID GUID > as a valid Audience Claim"... or "I accept < App ID URI > as a valid Audience Claim". This kind of logic may be built into the library you are using (like OWIN), but you need to make sure that on your API side, you have it configured correctly for the Audiences you expect. You could, if you wanted, make it so that your API does not check the Audience claim at all! All the claims in the token are plaintext, and thus you could really do whatever you want, but you would not have a very secure API in that situation :]

End of the day, my hunch is that this error is coming from your own API, and it is happening because you have not configured your app to accept an Audience claim which matches your Resource's App ID GUID (which it looks like what you are passing when you are getting a token based on your code sample).

I hope this solves your issue!

12
votes

Problem

After implementing the instructions found in this Protected web API: Code configuration article, I received an error message similar to the OP's:

WWW-Authenticate: Bearer error="invalid_token", error_description="The audience is invalid"

The problem turned out to be my AzureAd > ClientId setting in my appsettings.json file.

Solution

I updated the appsettings.json file of my ASP.NET Core Web API app so that the ClientId setting used the "Application ID URI" found in portal.Azure.com under my App Registriation > "Expose An API" section.

enter image description here

The section in appsettings.json looks similar to this:

"AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "XXXXXXXX-XXXXX-XXXXX-XXXXX-XXXXXXXXXX",
    // ClientId = Portal.Azure.com > App Registration > Expose an API > "Application ID URI"
    "ClientId": "api://XXXXX-XXXXXX-XXXXX-XXXX-XXXXXXXXX"   
}
5
votes

Important note

"aud" value that is being generated for JWT token by azure is also controlled by "accessTokenAcceptedVersion" property in AD application manifest.

This property defines a version of the access token that will be generated (MS docs about accessTokenAcceptedVersion).

Possible results for its values:

  • null or 1 - "api://" prepended to GUID
  • 2 - "api://" is not added, so there should be GUID only
3
votes

I had the same issue. Thought of sharing it. I have change the Web Api Audience to the ClientId of the Web App. After this it works.

3
votes

Can also be that your app/lib is using a newer version of the api. If accessTokenAcceptedVersion is null in the manifest of your app ms defaults to v1. Check your jwt token in http://jwt.io If you get this - check your JWT Token. If ISS isn't like this

 "iss": "https://login.microsoftonline.com/[yadyada]/v2.0",

then most likely you're using another version (like version 1 which is default). Check the manifest of your azure ad app: Below value is probably null or one, should be two:

"accessTokenAcceptedVersion": 2,
1
votes

I had the same issue. I was using the client's Resource ID as the parameter for AcquireToken when I should have used the server's Resource ID.

It works when I use the correct Resource ID.

0
votes

While calling api for implementing service principle through App registration in active directory. I got this error while calling api-GET {vaultBaseUrl}/secrets/{secret-name}/{secret-version}?api-version=7.0 with bearer key to get key vault secret value. As part of fix, to get bearer value, Apart from passing clientid, client secret, grant_type,I added resource key with value https://vault.azure.net as part of request body of api call for https://login.microsoftonline.com/{ActiveDirectoryId}/oauth2/token.