Microsoft Graph OAuth issues - azure

I have a background JS app that wont have any user input, so i was looking at using the app authentication without user input. I have set up an app in the Azure AD portal and also apps.dev.microsoft.com.
I am using the following endpoint:
login.microsoftonline.com/{Tenant}/oauth2/token
With the following body:
client_id: application_id
client_secret: generated key
grant_type: client_credentials
scope: "https://graph.microsoft.com/.default"
This generates an access_token however when i try and use it using the graph API, I get the following error
Access token validation failure
When investigating the token compared to a normal OAuth token with user input, i noticed its passing in roles rather then scp and the audience is my application rather then graph.microsoft.com.
What am i doing wrong?

The app registered in Azure AD portal works with Azure AD V1.0 endpoint ,app registered in apps.dev.microsoft.com that works with the v2.0 endpoint , Please firstly refer to this document for what's different about the v2.0 endpoint .
To use Azure AD v2.0 to access secure resources without user interaction(client credential flow) , you should send a POST request to the /token v2.0 endpoint:
POST /common/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=535fb089-9ff3-47b6-9bfb-4f1264799865&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=qWgdYAmab0YSkuL1qKv5bPX&grant_type=client_credentials
You could refer to this document for how to use the OAuth 2.0 client credentials grant with Azure AD V2.0 endpoint .
If you want to use azure ad v1.0 (app registered in azure portal) with client credential flow, you could refer to this document . In azure ad v1.0 , you should indicate the resource parameter which the client app is requesting authorization for , in your scenario , the resource should be https://graph.microsoft.com/ if you want to acquire token to call microsoft graph api .

Related

Query Application Insights via Azure REST API

I'm trying to query application insights via their REST API. I'm stuck on getting a token.
I have created an API key using the API Access blade in Azure Application Insights:
That gives you an Application ID and an API Key.
I have populated postman with the following:
url: https://login.microsoftonline.com/<Our Tenant ID>/oauth2/token
tenant: <Our Tenant ID>
client_id: <The Application ID from the API Access screen>
scope: https://api.applicationinsights.io/.default
client_secret: <The API Key from the API Access screen>
grant_type: client_credentials
All of this is taken from their documentation page here: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#get-a-token
The error is as follows:
"error": "unauthorized_client",
"error_description": "AADSTS700016: Application with identifier '<application ID from API Access screen>' was not found in the directory '<My Company Name>'. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.\r\nTrace ID: 57f78a92-fe94-40e3-a183-e3002be32801\r\nCorrelation ID: 0ab8e3ec-655d-44aa-93fa-4d3941862d11\r\nTimestamp: 2022-11-30 15:04:20Z",
I checked with the Azure Admin for our company and I'm definitely sending this to the right tenant. Also he created another key for me so it's not that either.
Thanks.
I tried to reproduce the same in my environment and got below results:
I created an API key from API Access blade in Azure Application Insights like below:
When I tried to acquire the token via Postman with below parameters, I got same error as below:
POST https://login.microsoftonline.com/<TenantID>/oauth2/token
client_id: <Application ID from API Access screen>
grant_type:client_credentials
client_secret: <API Key from API Access screen>
scope: https://api.applicationinsights.io/.default
Response:
There is no need to generate token separately if you want to query Application insights using API key.
Without including token, you can directly query Application insights by including x-api-key header like below:
GET https://api.applicationinsights.io/v1/apps/{Application ID from API Access screen}/metadata
x-api-key: <API Key from API Access screen>
Response:
The process you are currently following works only if you want to authenticate your API via Azure AD. In that case, you can generate the access token by granting required roles and scopes to registered Azure AD application.
But if your requirement is using API key, you can run any query by simply including x-api-key header for Authorization purpose.

Calling an azure function secured by AAD

I want to call an azure function. The authentication for this function is enabled by Azure AD.
I want to call this function from an azure web job or internal tool that may use HTTP and connect the function automatically. In this case, there is no way to prompt a login page and then login.
Can I get a token for the function where AAD is enabled, and then while calling the function will send the token as bearer token?
How to accomplish that or any better idea?
Regarding how to call the Azure function projected by Azure AD, please refer to the following steps
Configure Azure AD for Azure Function
Get the details of AD application used to project Azure function
a. Get application ID
b. Create client secret
c. Get Application Id Url
Use client credentials flow to get Azure AD access token
POST /<your tenant id>/oauth2/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
grant_type =client_credentials
&client_id=<your application id>
&client_secret=<your client secret>
&resource=<your application id url>
Call Azure function
<function url>
Authorization: Bearer <access token>

Accessing AD secured Azure Function via AJAX

I have an Azure Function setup with a Web Trigger endpoint that I want to use as my backend for a React app. Without authentication setup, it works fine. When I setup App Service Authentication using AD, it works fine when I access directly via the browser (after authentication), but when I try to access from JS providing the Bearer token I get a 401.
const response = await axios.get(`${window.apiUrl}api/jobs`, {
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + token.accessToken,
},
});
The client app is running on Azure and is registered as an Azure AD app. I am able to authenticate, query AD, and use MS Graph API successfully.
I am using the built-in Azure App Services AD authentication. I have the Client ID set as the same client ID as the previously mentioned Azure AD app, as well as the same Issuer Url.
Attempt to get session token:
const accessToken = await authProvider.getAccessToken();
const idToken = await authProvider.getIdToken();
const login = await axios.post(
'https://<appname>.azurewebsites.net/.auth/login/aad',
{ access_token: accessToken.accessToken },
{
headers: {
'Content-Type': 'application/json',
},
},
);
More Info
My aud claim is 00000003-0000-0000-c000-000000000000. In Azure Portal, my Azure Function is configured to use the same Azure AD App as my SPA. I am using MSAL.js for authentication in my SPA. I am requesting the User.Read and Directory.Read.All scopes.
Microsoft has published a how-to article entitled Advanced usage of authentication and authorization in Azure App Service. In the section on validating tokens from providers, it says:
In a client-directed sign-in, the application signs in the user to the
provider manually and then submits the authentication token to App
Service for validation (see Authentication flow). This validation
itself doesn't actually grant you access to the desired app resources,
but a successful validation will give you a session token that you can
use to access app resources.
So you need to get the session token to access app resources.
Request:
POST https://<appname>.azurewebsites.net/.auth/login/aad HTTP/1.1
Content-Type: application/json
{"id_token":"<token>","access_token":"<token>"}
Response:
{
"authenticationToken": "...",
"user": {
"userId": "sid:..."
}
}
Once you have this session token(authenticationToken), you can access protected app resources by adding the X-ZUMO-AUTH header to your HTTP requests
GET https://<appname>.azurewebsites.net/api/products/1
X-ZUMO-AUTH: <authenticationToken_value>
You cannot request a token for Microsoft Graph and use it to call your own API. The Audience "00000003-0000-0000-c000-000000000000" means "intended for Microsoft Graph".
In MSAL, when you request the token, you need to adjust the scopes. Delete User.Read, delete Directory.Read.All and add the "Application ID URI" with a /.default at the end of it. You can find the Application ID URI in the "Expose an API" blade of your application registration on portal.azure.com. Example: https://SaeedApp/.default
If you need to do both, you can only request an access token for one resource at a time. However, you can request as many scopes as you need for one resource (User.Read and Directory.Read.All are both scopes for the same resource).
So you'll need to make two sets of requests:
1) to get an access token with all the scopes you need for Microsoft Graph
2) to get an access token with all of the scopes you need for your API
The reason behind why: If I could take an access token that's intended for your API and call Microsoft Graph with it, then that would open up "replay" attacks where one Resource API is hacked and the hacker that controls one resource can now reply access tokens it receives from clients against all the other Resource APIs.

Azure AD Token based Authentication for WebAPI

We have developed Web API in .net Core 2.1 without authentication.
But now we are trying to add the Azure AD token based authentication.
we have registered app in azure AD and we did necessary changes in startup.cs file. and added authorize tag
When we test the API in postman we generated token we are getting Microsoft login page in Html format as result.
when we crosscheck the API in browser, its asking domain user name and password by providing the user name password we are getting the result.
Its seems some configuration or setting missing in Azure AD setup or code.
Can anyone help on this. other wise anyone share the steps for token based authentication implementation for API.
If you already have the api , you should firstly register an app in Azure Portal .
In your api application , you can follow the below steps :
Install the package Microsoft.AspNetCore.Authentication.AzureAD.UI
Register the Azure AD Bearer authentication service in ConfigureServices function :
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
In appsettings.json , set the correct api configuration from Azure Portal :
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "YourDomain.onmicrosoft.com",
"TenantId": "cb1c3f2e-a2dd-4fde-bf8f-f75ab18b21ac",
"ClientId": "83bf146d-4948-4596-a4b3-b7b2e68ac3e0"
},
Tenant ID ,domain name and API's ClientId could be find in Azure Portal .Then you can add Authorize attribute on protected controllers/actions . If you have multiple authentication schema , you can authorize with a specific scheme .
You client app will uses the OpenID Connect middleware and the ADAL/MSAL to obtain a JWT bearer token for the signed-in user using the OAuth 2.0 protocol. The bearer token is passed to the web API, which validates the token and authorizes the user using the JWT bearer authentication middleware.

Getting Authorization has been denied for this request in Fiddler with Azure AD

I have created a ASP.Net Web API (.Net Framework) app with "Work or School Accounts" as authentication type. This automatically registers this API app in my Azure subscription and I can see it under "App Registrations". I can see that Home Page Url is pointing to localhost address. I can see that API is launching locally on localhost address. I then launch Fiddler to get access token from Azure AD. My POST request to endpoint https://login.microsoftonline.com/<mytenant>.onmicrosoft.com/oauth2/token. has following 4 parameters
grant_type=client_credentials
&client_id=<appid from Azure AD Portal>
&client_secret=<secret from Azure AD Portal>
&resource=<appid from Azure AD Portal>
I get a token back. When I decode this token, I see aud and appid as expected(matching appid in Azure AD). I use this token as bearer token to invoke API call by adding Authorization: Bearer <mytoken> header in GET request to https://localhost:44374/api/values. However, this GET call to my API is returning me {"Message":"Authorization has been denied for this request."} error message.
What am I missing?
You should use App ID URI as the resource value when acquiring token , you could find the App ID URI in Properties of api app in azure portal ,like https://xxxxx.onmicrosoft.com/WebApplicationName . Web api will check whether the aud claim in access token matches the one you set in web.config :
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters = new TokenValidationParameters {
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
},
});
ida:Audience value in web.config is the allowed audience .

Resources