I have two Azure Daemon apps. App A and App B.
App B works as expected. I call the /oauth2/v2.0/token to the the access token. Then I decode the token and extract the roles.
App A does not.. when i decode and validate the token it says "Invalid Audience".
When i use jwt.ms to look at the token, the difference is App A is putting api:// in the aud portion.. and App B is not.
For example..
App A: { "aud":"api://3srlk3j..."}
App B: { "aud":"323f4lk2..."}
What is causing one to add api:// for one and not the other?
The value of audience is also controlled by the accesstokenacceptedversion in the manifest file.
When you decode the token you can check if issuer has v1 or v2 endpoint
"iss": "https://login.microsoftonline.com/xxxxx/v2.0",
For example here I have v2 endpoint ,so accesstokenacceptedversion in manifest must be set to 2 which might be probably null or 1 by default.
"accessTokenAcceptedVersion": 2,
So please check the same for your web app A and set it accordingly .(Also check the same for web app B) and then try to generate token.
Also if above alone doesn’t solve the error,the problem might be the configuration data for the Web API. When we say the ClientId ,it is the value under the "expose an API" option where it says "Application ID URI
Depending on how you request the access token, the audience of the token might be either the client id or Application ID URI of the API.
Here under expose an API , it has App ID Uri as api://xxxxx, same must be set as client id in the application app settings.
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "myportal.onmicrosoft.com",
"TenantId": "mytenant-guid",
"ClientId": "api://xxxxx"
},
So please check this match in both the applications(A and B) with their respective app ID URIs in their app registrations.
Related
I am trying to setup client credentials authentication for machines (original question:
Web API with Microsoft Identity Platform Authentication)
I am getting a valid token from https://login.microsoftonline.com/xxx/oauth2/v2.0/token.
However, I am receiving the following error when trying to call the secured action of my controller:
IDW10203: The 'scope' or 'scp' claim does not contain scopes 'access_as_machine' or was not found.
This is how my controller action looks like:
[Authorize]
[HttpGet("GetAsMachine")]
[RequiredScope("access_as_machine")]
public string GetAsMachine() => $"Machine {Assembly.GetExecutingAssembly().GetName().Version}";
In client credentials I had to set my scope to "api://xxx/.default".
When I try to set it to the actual scope, I am getting this error:
1002012: The provided value for scope api://xxx/access_as_machine is not valid. Client credential flows must have a scope value with /.default suffixed to the resource identifier (application ID URI).
Any idea what I am missing here?
Please notice one thing, when you want to use client credential flow, that means the token will contain roles claim but not the scp claim for delegate access token(generated by auth code flow/ropc flow..).
Then when you want to authenticate token generated by client credential flow, you may follow this document.
In brief, for example, I created a new .net 5 MVC project, and add configurations in appsettigns.json:
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "clientid_which_have_api_permission",
"Domain": "tenantname.onmicrosoft.com",
"TenantId": "common",
"Audience": "clientid_of_the_app_exposed_api"//e.g: api://client_id
}
Then in Startup.cs, add services.AddMicrosoftIdentityWebApiAuthentication(Configuration, "AzureAd"); in ConfigureServices method and add app.UseAuthentication(); in Configure method.
Then in my controller, I add an action like this:
[Authorize(Roles = "Tiny.TestRead")]
public string getData() {
//HttpContext.ValidateAppRole("Tiny.TestRead");
return "success";
}
Then I think you can notice I used Tiny.TestRead as target role name. This is defined in Azure ad and it requires you to expose an api with a role. And don't forget to add api permission.
In my test, I only create 1 azure ad app, this app exposed an api(role type) then I add this api permission to itself. So I generate access token like this:
I completely followed this link https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-authentication?view=azure-bot-service-4.0&tabs=aadv1%2Ccsharp%2Cbot-oauth and created a Azure AD app registration and used Azure Active Directory v1 for my web app bot.
After sign in, I view the token but with that token I cannot access the Azure API's, as it shows below response in Postman:
{
"error": {
"code": "AuthenticationFailed",
"message": "Authentication failed."
}
I called the Azure API below:
https://management.azure.com/subscriptions/${subscriptionId}/providers/Microsoft.Consumption/usageDetailsapi-version=2018-10-01
In my app registration in Azure AD, I have given these permission to access the Azure API:
In my Web App Bot -> Settings -> OAuth Connection Settings, I select:
ClientId -> My application client id
ClinetSecret -> My application client secret
GrantType -> I does not know what to give so I just typed "authorization_code" (If this wrong then Where I need to find my grantType)
LoginURL -> https://login.microsoftonline.com
TenantId -> common (To allow any user)
ResourceURL -> https://graph.microsoft.com/
Scopes -> I just left blank
Why am I not able to access the Azure API with that token?
Any Help. Thanks
An access token issued by Azure AD will always be for a specific resource. Which service a token is intended for is identified in the token's "audience" (in the aud claim). When using the v1 endpoint, the resource for which an app requests an access token is identified in the resource parameter of the authorization request. In the v2 endpoint, the resource is identified as part of the scope parameter.
In your case, the resource you've configured your bot to get a token for is Microsoft Graph (https://graph.microsoft.com), but then you're trying to use the resulting token to call the Azure Management API. The first thing the Azure Management API does is check if the access token it received is actually intended for it. If the audience does not match, it will immediately respond with an error.
Instead of trying to get a token for Microsoft Graph, you need to configure your bot to get a token for the Azure Management API. You should use https://management.azure.com, which is the resource URI for the Azure Management API, instead of https://graph.microsoft.com which is the resource URI for Microsoft Graph.
My ASP.NET Core web app works great when running and debugging locally, but fails to run once published to Azure.
I enabled Organizational Authentication and selected the appropriate domain upon publishing.
The appropriate reply URL was registered
After I publish to Azure I get this error:
An unhandled exception occurred while processing the request.
OpenIdConnectProtocolException: Message contains error: 'invalid_client', error_description: 'AADSTS70002: The request body must contain the following parameter: 'client_secret or client_assertion'.
Trace ID: 640186d6-9a50-4fce-ae39-bbfc1caf2400
Correlation ID: 622758b2-ca52-4bb0-9a98-e14d5a45cf80
Timestamp: 2017-04-19 16:36:32Z', error_uri: 'error_uri is null'.
I'm assuming that it's because the Client Secret needs to be stored in Azure somewhere; however, the value in secrets.json did not work when I added it as an App Setting (invalid client secret error) as I saw someone was able to do on another post. Also not sure if putting the value of "Authentication:AzureAd:ClientSecret" in Azure AppSettings is a good idea anyway.
Not sure if this is useful to anyone or not. But i receive a similar error message.
OpenIdConnectProtocolException: Message contains error: 'invalid_client', error_description: 'error_description is null', error_uri: 'error_uri is null'.
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler+<RedeemAuthorizationCodeAsync>d__22.MoveNext()
The solution for me was to provide a secret in the token service
,new Client
{
ClientId = "Testclient",
ClientName = "client",
ClientSecrets =
{
new Secret("secret".Sha256())
},
//Hybrid is a mix between implicit and authorization flow
AllowedGrantTypes = GrantTypes.Hybrid,
And provide the secret in the client
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
//The name of the authentication configuration.. just incase we have multiple
AuthenticationScheme = "oidc",
//Represents where to store the identity information -> which points to the cookie middleware declared above
SignInScheme = "Cookies",
//where the token service reside -> system will configure itself by invoking the discovery endpoint for the token service
Authority = "http://localhost:5000",
RequireHttpsMetadata = false,
ClientId = "Testclient",
ClientSecret = "secret",
//hybrid flow -grant type
ResponseType = "code id_token",
Hopefully this helps someone
Somehow I the Azure AD IDs needed for the proper Azure Active Directory App Registration were mixed up. There were 2 App Registration entries and the ClientID and TenentID's didn't match up with the local. So I synchronized the Client and Tenent IDs with one of the App Registration entries, and made sure the Client Secret was in App Settings, and it worked properly.
I verified these steps with this fine example Win's GitHub repository and they match now.
I'm using the Azure AD Basic tier with an ASP.NET Core API, I've followed the RBAC sample. I've set up an application with roles in my manifest like so:
appRoles": [
{
"allowedMemberTypes": [ "User" ],
"displayName": "Read Device",
"id": "b2e6f6c2-c3d5-4721-ad49-0eea255ccf45",
"isEnabled": true,
"description": "Can read a device.",
"value": "read_device"
},
...
]
I've setup my API to use the UseJwtBearerAuthentication middleware like so:
application.UseJwtBearerAuthentication(
new JwtBearerOptions()
{
AuthenticationScheme = "Azure Active Directory",
Authority = options.Authority,
Audience = options.ClientId,
TokenValidationParameters = new TokenValidationParameters()
{
RoleClaimType = "roles",
ValidateIssuer = false
}
})
I've given my user the above 'Read Device' role:
I'm using Swagger UI to make the call to get the auth token. It calls the following URL:
https://login.microsoftonline.com/[Tenant].onmicrosoft.com/oauth2/authorize?
response_type=token
&redirect_uri=http%3A%2F%2Flocalhost%3A5100%2Fswagger%2Fo2c.html
&realm=-
&client_id=[Client ID]
&scope=http%3A%2F%2Fschemas.microsoft.com%2Fws%2F2008%2F06%2Fidentity%2Fclaims%2Frole
&state=oauth2
&resource=[Client ID]
I suspected that I am not passing the correct values to the scope parameter, so I have tried asking for every scope I can think of:
&scope=openid
%20email
%20profile
%20offline_access
%20user_impersonation
%20roles
%20http%3A%2F%2Fschemas.microsoft.com%2Fws%2F2008%2F06%2Fidentity%2Fclaims%2Frole
%20read_device
If I set "groupMembershipClaims": "All" in my manifest I can see group claims but I want roles instead. I'm able to login to call my API, however I never get any roles back in my JWT token, so I'm unable check the users role. What am I doing wrong?
It turns out I needed to request an id_token instead of a token. An id_token contains extra claims/scopes/resources about the user. I also needed to provide a nonce parameter containing a new random GUID on every request. Thus, I ended up with the following URL:
https://login.microsoftonline.com/[Tenant].onmicrosoft.com/oauth2/authorize?
response_type=id_token
&client_id=[Client ID]
&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2F
&nonce=9ac5ad8d-df44-48e6-9bd6-e72743b3625c
If you are want to enable the role be assigned to users or groups(allowedMemberTypes=User) :
If you want to perform authorization using role claims , you could
follow the steps in this code sample , you could find the roles
claim is in the id_token .
If you want to make a client app to call your web api , when user
sign in ,app could check the access rules based on the role
claim,
you could use delegate flow(OAuth Authorization Code Grant,Implicit
Grant Flow..),roles claim is in the access_token ;
If you want to specify the role be assigned to client applications(allowedMemberTypes=Application), you could use OAuth Client Credential Flow ,appRoles of resource app/api that are assigned to the client app, and you will find the roles claim in the access_token ,check the detail steps from here.
Please click here for more details .
In my case I had mistakenly configured the App Registration to emit Security Groups as roles claims, thus overwriting the App Roles from the manifest. Removing the optional groups claim and logging back in correctly emitted the App Roles names in the roles claim of the id_token.
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"
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!
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.
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"
}
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
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.
The Microsoft references show the following example:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "[Client_id-of-web-api-eg-2ec40e65-ba09-4853-bcde-bcb60029e596]",
"TenantId": "common",
"Audience": "custom App ID URI for your web API"
},
// more lines
}
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,
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.
I got the same error. It was because I was using a custom domain, so my API ID URL wasn't api://{client-id}.
The solution is to set the Audience setting on your appsettings.json, just like mentioned in the Microsoft Wiki:
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "XXXXXXXX-XXXXX-XXXXX-XXXXX-XXXXXXXXXX",
"ClientId" : "XXXXXXXX-XXXXX-XXXXX-XXXXX-XXXXXXXXXX",
// Audience = Portal.Azure.com > App Registration > Expose an API > "Application ID URI"
"Audience": "Application ID URI"
}
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.
This might help someone: I've encountered this error because the MS Graph User.Read permission was missing on the SharePoint Online Client Extensibility Web Application Principal. Out of the box, this app reg already has the User.Read permission, but I had removed that one because (for an earlier project) I already used User.Read.All, thinking that it included User.Read. However, User.Read is used for sign-in purposes while User.Read.All is not. When I restored User.Read, my problem was solved.
Quite the unintuitive solution.