I could be completely off basis here on how this works, but this is what I'm looking to achieve.
In AAD I have
- an App Registration called
backend-api
that represents an HTTP API
- an App Registration called
frontend-app
that represents some client (lets say a console app)
- an App Registration called
another-app
that represents nothing related to my solution
I have a console application where I put my client ID and client secret in for frontend-app
and I can request an access_token
with the aud
of backend-api
. This is great, exactly what I want. However, I can litterally do the same thing from another-app
if I have the client ID and client secret for that app. What I would like to accomplish is that only frontend-app
is allowed to get an access_token
for backend-api
.
I'm not quite sure how to go about configuring that specific requirement. I thought maybe I needed to add an appRoles
entry for allowedMemberTypes
Application
on backend-api
and then grant frontend-app
that role but that didn't apply any restriction to another-app
. Likewise I thought maybe backend-api
needed to have it's "Require User Signin" option checked under Enterprise Applications, but I couldn't find a way to add frontend-app
as a "user" -- probably the wrong direction anyhow.
What's the way to tell AAD to only hand out access_tokens
for backend-api
(aud
claim) if they are being requested via frontend-app
only? Maybe that's a silly question, and it just doesn't work this way?
You are on the right path with your thinking about adding appRoles
entry to backend-api
and then assigning the role specifically to frontend-app
.
Additionally, understand that enforcing this requirement that only applications coming in with this new role claim are allowed but others aren't is a responsibility of your API code.
I'll get to 2 specific approaches next. Both the approaches are explained on Microsoft Docs here - Microsoft identity platform and the OAuth 2.0 client credentials flow
Approach 1 - Use Application Permissions or Roles
Configure your API application to expose a set of application permissions (or roles).
This approach is a little more declarative, as you define an application permission that needs to be assigned to any application that can call your backend-api
.
Navigate to Azure Active Directory > App Registrations > App registration for your backend-api
app > Manifest
Add a new application role.. using json like this:
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"displayName": "Can invoke my API",
"id": "fc803414-3c61-4ebc-a5e5-cd1675c14bbb",
"isEnabled": true,
"description": "Apps that have this role have the ability to invoke my backend API",
"value": "MyAPIValidClient"
}]
Assign the app permission to your frontend app
New-AzureADServiceAppRoleAssignment -ObjectId <frontendapp.ObjectId> -PrincipalId <frontendapp.ObjectId> -Id "fc803414-3c61-4ebc-a5e5-cd1675c14bbb" -ResourceId <yourbackendapi.ObjectId>
Authenticate your frontend app to backend api using client credentials grant, i.e. using clientId and client secret.. as you're probably already doing.
Now, in the auth token received by your backend api, you can check that the role claims collection must contain a role named "MyAPIValidClient" otherwise you can reject the call with Unauthorized exception.
Approach 2 - Use Access Control Lists
When your backend API receives a token, it can decode the token and extract the client's application ID from the appid
and iss
claims. Then it compares the application against an access control list (ACL) that it maintains.
Depending on your requirement, API might grant only a subset of full permissions or all permissions to a specific client.
This 2nd approach may seem like a simpler one for some cases, although I like the first one better as it scales well when you have multiple application permissions/roles and different level of functionality to provide based on those roles.
Related SO Post and References
Related SO Post - Is there a way to secure an Azure Function that
will only be called from a specific Azure Logic App?
Microsoft Docs - Microsoft identity platform and the OAuth 2.0 client credentials
flow