0
votes

I have a couple of APIs("Group A and B") which call a single, central API ("API X"). All use authentication via Azure AD.

Within "API X", I want to restrict a couple of routes to a subset of the available routes.

/api/stuffForEveryOne/...    <-- Group A and B should be able to call this
/api/specialStuff/...        <-- Only Group B should be able to call this

What is the proper way to implement this?

My idea was to assign the AAD applications to AAD groups, and validate by querying graph API in "API X". But since there are no users this context, I am not sure if this is the correct way. Ideally, it would be great if "Group B" would get an additional claim when they request a JWT token for "API X". But I don't know if that is possible. "Group A" should not be able to get this claim.

1

1 Answers

2
votes

Use app permissions :)

You can define two app permissions in the API X manifest like this (example showing one, removed other properties for clarity):

{
  "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"
  }
  ]
}

Set the value to something that makes sense for you, it will be included in the access token.

Example token (with most claims removed):

{
  "appid": "28d6c0d7-6017-42f7-8cee-c27d80bb9709",
  "roles": [
    "Todo.Read.All"
  ]
}

You can read about them more in my blog: https://joonasw.net/view/defining-permissions-and-roles-in-aad.

Then you go to both of your app's using the API X in AAD, and require both app permissions in one of them, and only one of the permissions in the other. Don't forget to grant the permissions.

Then, you can add authorization policies that require the existence of a claim with type "roles"/ClaimTypes.Role (I forget which one it is), and value of the value in the app permission.

Example policy definition:

services.AddAuthorization(o =>
{
    o.AddPolicy("SpecialStuff", p => p.RequireClaim(ClaimTypes.Role, "SpecialStuff.Read"));
});

Then you specify [Authorize("PolicyName")] on the controller or action where you want to require the permission.

Side note: I really should write a blog on doing this stuff in ASP.NET Core APIs..