How to Fetch Token to access APIM from Function App with Managed identity - azure

I am trying to access APIM from Azure Function and want APIM to authenticate through Managed Identity Token. I have assigned system assigned identity to the function app.I am following this (sample)[https://learn.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=dotnet#asal] to generate token. In the below line if I give "https://vault.azure.net" to GetAccessTokenAsync method I am getting the token. but I want the audience to be APIM so I provided https://azure-api.net like mentioned in the last line. but I am getting exception. how can I provide the APIM Url to fetch the access token?
using Microsoft.Azure.Services.AppAuthentication;
var azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://vault.azure.net");
string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://azure-api.net");
An Update. I think something wrong with listing the resources. because when I give the proper resource name it says resource doesnt exist in the tenant though I can see the subscription is under the same tenant when I run through az cli.

As I mentioned in the comment, you need to Register an application in Azure AD to represent the API, then you can get the token for it(i.e. with the Application ID URI in the previous link).
string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("<Application ID URI>");
Something you need to know:
You can use azureServiceTokenProvider to get the token for https://vault.azure.net, https://managment.azure.com, because they are all the APIs exposed by Microsoft, i.e. azure keyvault rest api and azure management rest api, essentially they are all AD App registered by Microsoft, so if you want to get the token for your own API, you need to register the AD App first to represent the API first.
Also, when you use managed identity to get the token, essentially it uses the client credential flow to get the token, actually the managed identity is a service principal(i.e. enterprise application) managed by azure. Remember to leverage the app role if you need to validate the roles claim when you get the access token.

Related

Authorization_IdentityNotFound while calling https://graph.microsoft.com/v1.0/organization API

I want, when user login he should get list of tenant, from that list, user decide in which tenant he want to redirect
I want to call https://graph.microsoft.com/v1.0/organization API but when I write code to call it , it will returned error, I have get token using below code, it is worked for users API of Graph, but not working for organization api
B2BGraphClient.AccessToken = await authContext.AcquireTokenAsync("https://graph.microsoft.com/", credential).ConfigureAwait(false);
I have checked it using Postman, when I have pass token generated using https://login.microsoftonline.com/common/oauth2/token this api, organization api returns correct output, but logically it is not possible in code to pass userid and password to api and get token, below is image of postman call
I want correct way to do this
Your code is using Client_credentials flow but in Postman you are using ROPC flow.
The two flows use different permission type. Client_credentials flow uses Application permission while ROPC flow uses Delegated permission.
So for Client_credentials flow, if the app belongs to a work or school (organization) context then for https://login.microsoftonline.com/common/oauth2/token replace common with a tenantId or domain name. If you don't do this, you will get the Authorization_IdentityNotFound error.
Specify the tenant in the code (modify the sample code based on your needs).
this.clientId = clientId;
this.clientSecret = clientSecret;
this.tenant = tenant;
// The AuthenticationContext is ADAL's primary class, in which you indicate the direcotry to use.
this.authContext = new AuthenticationContext("https://login.microsoftonline.com/" + tenant);
// The ClientCredential is where you pass in your client_id and client_secret, which are provided to Azure AD in order to receive an access_token using the app's identity.
this.credential = new ClientCredential(clientId, clientSecret);
B2BGraphClient.AccessToken = await this.authContext.AcquireTokenAsync("https://graph.microsoft.com/", this.credential).ConfigureAwait(false);
And don't forget to add one of the following Application permissions Organization.Read.All, Directory.Read.All, Organization.ReadWrite.All, Directory.ReadWrite.All in your app registration as per Permissions.
UPDATE:
In fact this endpoint https://graph.microsoft.com/v1.0/organization can't return the tenants which the user is member of.
You have found the correct Azure rest API to list the tenants.
But this API also doesn't support client_credentials flow.
In another word, you cannot use authContext.AcquireTokenAsync to get the token. You should consider AcquireTokenByAuthorizationCodeAsync. And specify the scope as https://management.azure.com/ instead of https://graph.microsoft.com.
Don't forget to add the Azure Rest permission in app registration.

Azure usage details API shows "Authentication failed" after sign in with azure active directory v1 connection

I completely followed this link https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-authentication?view=azure-bot-service-4.0&tabs=aadv1%2Ccsharp%2Cbot-oauth and created a Azure AD app registration and used Azure Active Directory v1 for my web app bot.
After sign in, I view the token but with that token I cannot access the Azure API's, as it shows below response in Postman:
{
"error": {
"code": "AuthenticationFailed",
"message": "Authentication failed."
}
I called the Azure API below:
https://management.azure.com/subscriptions/${subscriptionId}/providers/Microsoft.Consumption/usageDetailsapi-version=2018-10-01
In my app registration in Azure AD, I have given these permission to access the Azure API:
In my Web App Bot -> Settings -> OAuth Connection Settings, I select:
ClientId -> My application client id
ClinetSecret -> My application client secret
GrantType -> I does not know what to give so I just typed "authorization_code" (If this wrong then Where I need to find my grantType)
LoginURL -> https://login.microsoftonline.com
TenantId -> common (To allow any user)
ResourceURL -> https://graph.microsoft.com/
Scopes -> I just left blank
Why am I not able to access the Azure API with that token?
Any Help. Thanks
An access token issued by Azure AD will always be for a specific resource. Which service a token is intended for is identified in the token's "audience" (in the aud claim). When using the v1 endpoint, the resource for which an app requests an access token is identified in the resource parameter of the authorization request. In the v2 endpoint, the resource is identified as part of the scope parameter.
In your case, the resource you've configured your bot to get a token for is Microsoft Graph (https://graph.microsoft.com), but then you're trying to use the resulting token to call the Azure Management API. The first thing the Azure Management API does is check if the access token it received is actually intended for it. If the audience does not match, it will immediately respond with an error.
Instead of trying to get a token for Microsoft Graph, you need to configure your bot to get a token for the Azure Management API. You should use https://management.azure.com, which is the resource URI for the Azure Management API, instead of https://graph.microsoft.com which is the resource URI for Microsoft Graph.

Azure monitor REST API throwing invalid token error

I created a native APP with Client credentials
AuthenticationContext authContext = new AuthenticationContext(AUTHORITY, false, service);
ClientCredential clientCred = new ClientCredential(CLIENT_ID, "myclientsecret");
//Future<AuthenticationResult> future = authContext.acquireToken("https://graph.microsoft.com", clientCred, null);
Future<AuthenticationResult> future = authContext.acquireToken("https://graph.microsoft.com", clientCred, null);
Authority is:
https://login.microsoftonline.com/{tenetID}/oauth2/authorize/
This worked fine and got a access token. Then I tried to access Azure Management REST API by setting this token as Bearer Token. Getting
401 Unauthorized
WWW-Authenticate: Bearer authorization_uri="https://login.windows.net/{tenentid}", error="invalid_token", error_description="Could not find identity for access token."
Any idea what am I doing wrong?
Another observation is, based on this create service principal documentation, when we add an app in AD it should show up in IAM --> assignment roles, some how my app is not showing up there. Seems I am missing some critical step.
If you want to call Azure Management REST API, the resource should be https://management.azure.com in your code, not the https://graph.microsoft.com which is for Microsoft Graph API.
Another observation is, based on this create service principal documentation, when we add an app in AD it should show up in IAM --> assignment roles, some how my app is not showing up there.
When you create an app in AAD, it will not be added to the Access control (IAM) of your subscription automatically, you need to add it as a role manually. Navigate to the Access control (IAM) in your subscription -> Add -> Add role assignment -> search for your service principal(AD App) by name and select a role (e.g. Owner) -> Save.

What is ResourceId Here?

Currently, am trying to get the bearer token from the AAD(which is a Native app). I have the current block of code
private AuthenticationContext authContext = null;
authContext.AcquireTokenAsync(todoListResourceId, clientId, redirectUri, new PlatformParameters(PromptBehavior.Always))
So in the current Code block what is todoListResourceId ?
That's the resource identifier for the API you want an access token for.
In this case your client app says to Azure AD "Give me a token for the Todo List Service".
In case of MS APIs, you typically use the URI e.g.:
MS Graph API: https://graph.microsoft.com
Azure AD Graph API: https://graph.windows.net
In case of your own APIs, you can use either the API client id or App ID URI (found in the Properties for the app registration).
Though it does require the API to be configured to accept both as a valid audience.
If it only accepts one, then you have to use that one.

authority_not_in_valid_list: 'authority' is not in the list of valid addresses

I am trying to call a Authenticated API from my client app. However, when making AcquireTokenAsync, I get following error "authority_not_in_valid_list: 'authority' is not in the list of valid addresses"
here is my code snippet:
resourceUrl = "https://myApiEndPoint.com";
var clientCredential =
new ClientCredential( myClientAppId, myClientSecretKey );
// myClientAppId and myClientSecretKey are the values from Azure Portal
var authContext =
new AuthenticationContext( "https://my_authority/myApiEndPoint");
return await authContext.AcquireTokenAsync( resourceUrl, clientCredential );
In my azure Portal for my client Id of app, I have granted delegated permission to access https://myApiEndPOint.com api.
Any thoughts on what could be causing this issue and what does it mean by not in valid list?
I understand that:
you created your application in the Azure portal, and therefore the authority is the Azure AD endpoint. Therefore the authority is probably https://login.microsoftonline.com/common? Or do you have good reasons to use "https://my_authority" ?
you have granted delegated permissions to access the API. This means that your application will access the API in the name of the user. However the AcquireTokenAsync method that you use is using the "ClientCredential" flow (meaning with an application secret)
You probably rather want to use another override passing the resourceUri, the clientId, ...
If this is your use case, I suggest you have a look to the active-directory-dotnet-webapi-onbehalfof sample (See here)

Resources