Daemon console app calling Azure AD cant find AppRole (MSAL) - azure

I have two applications registered in Azure, a REST API and daemon console application that calls the REST API.
The work flow is shown
Daemon console app --call for token using secret--> Azure AD
Daemon console app use the return token to call --> REST API.
I do get the token and correct AppRole is defined in REST API, with Admin consent.
however, when I try to call the REST API Daemon console app throws this error
Failed to call the web API: InternalServerError
Content: System.ArgumentException: Requested value 'ApplicationRole' was not found.
at System.Enum.TryParseByName(RuntimeType enumType, String originalValueString, ReadOnlySpan`1 value, Boolean ignoreCase, Boolean throwOnFailure, UInt64& result)
I followed the official MS documentation here
https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2/tree/master/2-Call-OwnApi
I decoded the JWT token it has the role defined:
...
"oid": "xxxxx",
"rh": "xxxx",
"roles": [
"ApplicationRole"
],
...
The Manifest file of REST API
...
appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"description": "Daemon apps in this role can consume the web api.",
"displayName": "ApplicationRole",
"id": "unique uid",
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "ApplicationRole"
}
],
...
The admin consent is also being granted to Daemon console App
API / Permissions name Type Description Admin consent require Status
IoT-Manager (1)
ApplicationRole Application ApplicationRole Yes Granted for XX
What could be wrong here ?
Update
I debug Daemon application I found out that the access token does not contain roles
...
AuthenticationResult result = null;
try
{
result = await app.AcquireTokenForClient(scopes)
.ExecuteAsync();
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Token acquired \n");
Console.WriteLine(result.AccessToken);
Console.WriteLine("Token ExpireOn \n");
Console.WriteLine(result.ExpiresOn);
Console.ResetColor();
}
...
When I print the access token and decode it shows it has AppRoles, where When I debug the object AuthenticationResult result has no attribute for roles.

I've run the sample you provided and it worked well, I'll show my steps below.
Creating an azure ad app as the service. When registering the app, I only enter the name field and keep others the default.
Next I exposed an api in this application. Expose an API-> Add a scope-> keep the default application id url->save and continue-> edit my scope like below:
Add the role like screenshot below:
Creating another azure ad app as the client, only enter the name field too.
Create client secret and add api permission.
set the sample code, the appsetting.json file of each project are needed to modify, and the controller file in api project. The value needed to be changed in controller depends on the api. In my side, you can see the screenshot in step 5, it shows api://xxx/App.Role, so I set the value as App.Role.

Related

How to add application permissions to my own App on azure AD

I have created an App Registration that exposes an API and a scope.
I then create a frontend app/client with another App Registration and I can add my own API as delegated permission and ask Azure AD for a token to the API on behalf of me using normal OAuth flows.
Let's say a 3 client needs access to the API but not as a given user but as the application itself. In the UI of Azure AD, there are no "Application Permissions" for my own API when adding this 3rd API and try to give it access to an API. What is the equivalent of this and how do I set it up?
I have an older article that shows you how to do it through the manifest.
https://joonasw.net/view/defining-permissions-and-roles-in-aad
Currently there is no UI for defining app permissions, so you'll have to do it through the manifest or with PowerShell.
Essentially you need to define an appRole with an allowed member type of Application.
That is an app permission that can then be assigned to apps.
It will appear in the roles claim in the token.
{
"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"
}
]
}

Azure AD authentication for node.js REST endpoint with Service Principal and Secret

I'm trying to call a REST API which is protected by AzureAD authentication. From Postman REST client it works like,
https://example.com/getexample
Header: Authorization: Bearer . This works great if i get token of the user interactively(example device_code or MFA).
As i wanted to run code Non Interactively, i'm trying to authenticate the REST endpoint by service principal.
The REST server is built in nodejs with azure-passport node.js package.
I have created Service Principal(Native app) and secret for the same. I was able to get access_token from this package as well as below curl command
curl -X POST -d 'grant_type=client_credentials&client_id=[client id]&client_secret=[client secret]&resource=[client id of the server]' https://login.microsoftonline.com/[tenant]/oauth2/token
But if i pass this generated token to REST endpoint i get 401.
Please help how to authenticate a custom REST endpoint with service principal and secret.
Below is the configuration details i have done for service principal(server and client)
Server SP(node.js app)
Create Service Principal, added User.Read API permission. Admin Granted the API permission.
Created a custom scope(API.Access) under "Expose an API" and selected "Admin and User" can grant.
In node.js application i'm using only user.read scope
Client SP(Postman)
Created Service Principal, added Server SP(Customer scope) under API permission
Used curl command to get access token without passing any scope.
To run code Non Interactively, the way you used to get access token is client credential flow which needs application permission. Here is the difference between delegated permission and application permission.
You can define the application permission by edit the manifest of server app.
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"description": "Apps that have this role have the ability to invoke my API",
"displayName": "Can invoke my API",
"id": "fc803414-3c61-4ebc-a5e5-cd1675c14bbb",
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "myTestRole"
}
]
Then your client app can add the application permissions(from your server app).

Azure AD Authentication in dotnet core 2 API and daemon application

I'm struggling to determine the best route to authenticate using Azure Active Directory for my dotnet core web API.
Here is the situation:
An application created in Azure Active Directory that the Web API authenticates users. It has multiple application roles associated with it.
A daemon application that needs to authenticate to the Web API.
What is the best solution to solve the authentication situation? It's difficult to find clear documentation on how to actually solve this.
Thank you for your advice and help!
Your daemon app will need to use application permissions (app roles with member type = Application) to call the API.
You can see how to define those here: https://joonasw.net/view/defining-permissions-and-roles-in-aad.
For example, this is how one looks like in the 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"
}
]
}
Then you assign the app permission to your daemon app.
After that it's a simple matter of authenticating with client credentials from the daemon app.
With ADAL.NET for example, you would acquire a token with ClientCredential + the resource URI of the API.
You can find the URI from your API's app registration (Properties blade, App ID URI).
You can then attach the resulting access token to HTTP requests and the API can find from the appid claim who the calling app is, and from the roles claim what app permissions they have.

Azure AD remove permissions for registered app

I am using Azure AD to secure my service to service calls. (Each service having an application identity in Azure AD).
Example: Application A wants to access Application B.
I noticed that when requesting an accesstoken from Application A using Client Credential Flow (with Certificate), an accesstoken is issued without having me to explicitly set the permissions to access Application B.
This seems odd to me because the token returned has its audience set to Application B even thought I haven't explicitly given it access.
If I understand correctly, all registered app have access to each other by default?
Is there a way in Azure AD to explicitly require permissions to be set in order for application to access each other?
Below is a screenshot of Application A required permissions. As you can see, Application B is not listed here.
In the following screenshot, I assigned TodoListService (aka Application B) to the required permissions of Application A
I noticed that when requesting an accesstoken from Application A using Client Credential Flow (with Certificate), an accesstoken is issued without having me to explicitly set the permissions to access Application B.
Yeah, that one can be a bit surprising and I'm not sure why that is the case either.
What you need to do is define application permissions on the API, and then assign it on the client.
Then you need to check the caller has the required app permission in the token.
I have an article on this topic: Defining permission scopes and roles offered by an app in Azure AD.
To define an app permission on the API, you'll have to edit its manifest in Azure AD, and add an app role with member type of Application, something like:
{
"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"
}
]
}
IIRC you have to generate a GUID for the id.
After defining this permission on the API, go to your client app, and add the app permission in the Required permissions.
Then you should press Grant permissions to grant the app permission.
Now then when the client acquires a token with client credentials, the token will contain:
{
"roles": [
"Todo.Read.All"
]
}
So you'll have to check that that is present.

Delegating Azure Active Directory Roles When Calling API from SPA

I have a single page application (SPA) and an API. Both are secured using Azure Active Directory using role based access control (RBAC). I can login and viewview my SPA using ADAL. I can also login, call my API and see the role claims I have given myeself.
I want to call the API from the SPA. I have added the API delegated permissions to the SPA. I have also hit the 'Grant Permissions' button so I don't see a consent screen.
The problem is when the SPA calls the API, no role claims appear, so the API always returns a 403 Forbidden response. How can I solve this?
Update
This is the manifest for my API:
{
"appId": "[API Client ID]",
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "Read Device",
"id": "b2e6f6c2-c3d5-4721-ad49-0eea255ccf45",
"isEnabled": true,
"description": "Can read a device.",
"value": "Device.Read.All"
}
],
...
}
In my SPA, I'm using ADAL and adal-angular like so:
var azureActiveDirectory = {
'instance': 'https://login.microsoftonline.com/',
'tenant': '[My Tenant ID]',
'clientId': '[SPA Client ID]',
'redirectUri': 'http://localhost:8080/',
'endpoints': {
'http://localhost:5000': '[API Client ID]'
}
adalAuthenticationServiceProvider.init(azureActiveDirectory, $httpProvider);
Apparently, roles in nested groups are not transitive i.e. If I am a member of Group 2, I do not have the Role granted to Group 1, even though Group 2 is a member of Group 2:
Group 1
Has a Role from Application 1
Has a Member called Group 2
This is absolutely unbelievable that such a feature has not been implemented. I've raised a suggestion on UserVoice. Please upvote the suggestion.
you should create the appRole in your API app, when your spa call API, it will get access token with the role in api app that the login user belongs to. so to make sure you create role and verify role in api app, not spa app.

Resources