I am trying to control authorization via app registrations in Azure.
Right now, I have two app registrations set up.
ApiApp is set up with the default settings, but I have added this to the manifest:
"oauth2Permissions": [
{
"adminConsentDescription": "Allow admin access to ApiApp",
"adminConsentDisplayName": "Admin",
"id": "<guid>",
"isEnabled": true,
"type": "User",
"userConsentDescription": "Allow admin access to ApiApp",
"userConsentDisplayName": "Admin",
"value": "Admin"
},
...
]
In the client app registration, I have all the defaults, but I added:
In my client app, it uses this code for authentication purposes:
...
var context = new AuthenticationContext(authority);
var clientCredentials = new ClientCredential(<clientId>, <clientSecret>);
var result = await context.AcquireTokenAsync(<apiAppUri>, clientCredentials);
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", result.AccessToken);
var webResult = await client.GetAsync(<api uri>);
My ApiApp is just using the built in authorization if you select work or school accounts when you create a Web API project:
public void ConfigureAuth(IAppBuilder app)
{
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters = new TokenValidationParameters {
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
},
});
}
This works:
[Authorize]
public class ValuesController : ApiController
These do not work:
[Authorize(Users = "Admin")]
public class ValuesController : ApiController
or
[Authorize(Roles= "Admin")]
public class ValuesController : ApiController
Based on what I'm reading, I believe I have everything set up appropriately except the ApiApp project itself. I think I need to set up the authorization differently or with extra info to allow the oauth2Permission scopes to be used correctly for WebAPI.
What step(s) am I missing to allow specific scopes in WebAPI instead of just the [Authorize] attribute?
I used Integrating applications with Azure Active Directory to help me set up the app registrations, along with Service to service calls using client credentials , but I can't seem to find exactly what I need to implement the code in the Web API part.
UPDATE
I found this resource: Azure AD .NET Web API getting started
It shows that you can use this code to check out scope claims:
public IEnumerable<TodoItem> Get()
{
// user_impersonation is the default permission exposed by applications in Azure AD
if (ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/scope")
.Value != "user_impersonation")
{
throw new HttpResponseException(new HttpResponseMessage {
StatusCode = HttpStatusCode.Unauthorized,
ReasonPhrase = "The Scope claim does not contain 'user_impersonation' or scope claim not found"
});
}
...
}
However, the claims I get do not include any scope claims.
You have to use appRoles for applications, and scopes for applications acting on behalf of users.
As per GianlucaBertelli in the comments of Azure AD, Scope-based authorization:
...in the Service 2 Service scenario, using the client credentials flow you won’t get the SCP field. As you are not impersonating any user, but the calling App (you are providing a fixed credential set). In this case you need to use AppRoles (so Application permissions, not delegated) that results in a different claim. Check a great how-to and explanation here: https://joonasw.net/view/defining-permissions-and-roles-in-aad.
In the link he provides, it discusses appRoles in the application manifest.
The intention behind the resources I was looking at before was to allow users to login to the client application, and then the client application authenticates against the API on behalf of the user. This is not the functionality I was trying to use -- simply for a client application to be able to authenticate and be authorized for the API.
To accomplish that, you have to use appRoles, which look like this in the application manifest:
{
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"displayName": "Read all todo items",
"id": "f8d39977-e31e-460b-b92c-9bef51d14f98",
"isEnabled": true,
"description": "Allow the application to read all todo items as itself.",
"value": "Todo.Read.All"
}
]
}
When you set the required permissions for the client application, you choose application permissions instead of delegated permissions.
After requiring the permissions, make sure to click the "Grant Permissions" button. To grant application permissions, it requires an Azure Active Directory admin.
Once this is done, requesting an access token as the client application will give you a "roles" claim in the token, which will be a collection of string values indicating which roles the application holds.