Reputation: 909
We are developing an application with a frontend and a backend. The backend should be accessed via Rest API with an OAuth2 token. Authorization provider is Azure AD.
In Azure we created 2 app registrations. One for the API, one for the client app. The API registration defines 3 scopes (Read, Write, Delete). The client app registration has delegated permission for these scopes.
We are requesting tokens with the clientID and clientSecret from the client app registration.
The problem is that we can only request tokens with scope api/.default. E.g. api/read results in invalid scope error. But if we use api/.default, no scope (scp) attribute is included in the token. Isn't that needed to check if the app consuming the API has the right permissions?
I am not sure if we are doing something wrong or if we have a wrong understanding/expectation.
Upvotes: 13
Views: 27990
Reputation: 301
The claims contained in the token returned by Azure AD depends on the OAuth2 grant type being used. When using a Client Credentials flow it implies that two applications, of which neither involves any user interaction, are being used. Azure documentation uses the terms daemon app and web API app. The daemon app is the application calling API's of the web API app.
The obvious but unfortunately wrong way is to use "Expose an API" e.g. on Azure portal: AD -> application -> Expose an API to create permissions. The problem is that "Expose an API" creates only delegated permissions. But delegated permissions are only relevant when a user is involved. Which is not the case when using a Client Credentials grant.
What one needs to create are application permissions. These permissions can, so it seems, currently only be created directly in the Manifest. The following is needed to create an application permission:
{
// ...
"appRoles": [
{
"allowedMemberTypes": ["Application"], // Must be "Application"
"description": "Allows Read operation",
"displayName": "Read",
"id": "a35fcf6e-58c4-42af-937d-f43e90103b44", // A unique UUID
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "Read" // The role one wants to create
}
]
// ...
}
More information can also be found on the official Azure documentation page Protected web API: App registration.
Now one can go to the daemon app in the AD and grant the created application permissions. In Azure portal this is done by these steps:
The daemon app can now request a token using client credentials grant. The scope in the request must be '/.default'. (Only for delegated permissions one can ask for non-default scope.) The returned token will then contain the claim roles which is a list of granted permissions. The permissions in the list are the permissions granted to the Damon app. E.g.
"roles": ["Read"]
Upvotes: 20
Reputation: 818
When using Client Credential flow to get Azure AD JWT token, the scope has to be in the format of
api://<clientid of the API app registered>/.default
As per MSDN, OAUTH Client Credential Flow
scope - Required - The value passed for the scope parameter in this request should be the resource identifier (application ID URI) of the resource you want, affixed with the .default suffix. For the Microsoft Graph example, the value is https://graph.microsoft.com/.default. This value tells the Microsoft identity platform that of all the direct application permissions you have configured for your app, the endpoint should issue a token for the ones associated with the resource you want to use. To learn more about the /.default scope, see the consent documentation.
Upvotes: 19