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

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).

Related

Azure B2C Works On My Local Machine But Not On Azure

I have created a Blazor application that calls a Web API(.Net) and uses Azure AD B2C for authentication. This works fine on my local machine. I can authenticate via the login screen and call the relevant endpoint. Once I deploy the application to Azure I get this error on the browser:
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed. These requirements were not met:
DenyAnonymousAuthorizationRequirement: Requires an authenticated user
Failed to load resource: the server responded with a status of 401 (Unauthorized)
On the Blazor(UI) side I have this set up:
"AzureAd": {
"Authority": "https://CarehomeRoomBookingTest.b2clogin.com/CarehomeRoomBookingTest.onmicrosoft.com/B2C_1_SignUpIn",
"ClientId": "77##############################",
"ClientSecret": "99#########################",
"ValidateAuthority": false
}
On the Web API side I have this set up:
"AzureAdB2C": {
"Instance": "https://CarehomeRoomBookingTest.b2clogin.com",
"ClientId": "16#############################",
"Domain": "CarehomeRoomBookingTest.onmicrosoft.com",
"SignedOutCallbackPath": "/signout/B2C_1_susi_reset_v2",
"SignUpSignInPolicyId": "B2C_1_SignUpIn",
"TenantId": "38#############################"
}
Why would this be happening when the application is deployed and hosted on Azure?
Please check if any of below is your case:
1.See if scope for your API that Your front-end app needs to use is correct. This way it will get an access token which is meant for your API. Register a
scope for your API app registration through the Expose an API
section and use the scope in your front-end app.
and grant admin consent :
Your scopes will be present this way
Please make sure to include the scopes exposed in the portal for your backend api in the auth in your code
Also please check if you have given proper permissons or if use of
delegated permissions is the issue .See
getting-401-unauthorized-error-StackOverflow

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

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.

How to use Azure API for FHIR Server without any authorization token

I have created a resource for Azure API for FHIR Server. I am able to get see the metadata information using the URL like https://fhir-server-url/metadata. As mentioned in the documentation https://learn.microsoft.com/en-us/azure/healthcare-apis/access-fhir-postman-tutorial to access other URLs like https://fhir-server-url/Patient, we need to get the Authorization token first. To get the authorization token we need ClientID which we can get by creating an application in Azure Active Directory. But I don't have access to it.
Is there any way I could access this URL without requiring the authorization token? By making some setup in Azure Portal.
If you are using the first party audience (e.g. https://azurehealthcareapis), which is the default when deploying the Azure API for FHIR, you can actually use a first party client application such as the Azure CLI to get a token. Check https://learn.microsoft.com/azure/healthcare-apis/get-healthcare-apis-access-token-cli for details.
First log in with the Azure CLI (https://learn.microsoft.com/cli/azure/?view=azure-cli-latest) :
az login
Get a token and store it
token=$(az account get-access-token --resource=https://azurehealthcareapis.com | jq -r .accessToken)
Use the token:
curl -X GET --header "Authorization: Bearer $token" https://<FHIR ACCOUNT NAME>.azurehealthcareapis.com/Patient
It looks like from the FHIR Server Doc you can turn this on or off based on the FhirServer:Security:Enabled config setting see https://github.com/microsoft/fhir-server/blob/master/docs/Authentication.md
"FhirServer" : {
"Security": {
"Enabled": true,
"Authentication": {
"Audience": "fhir-api",
"Authority": "https://localhost:44348"
}
}}
One way is to get your app registration in Azure Active Directory(AAD).
You would need two app registrations in AAD to get client Id & client secret for authorization token retrieval.

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.

Resources