How to consume or access Azure AD exposed API(MyApis)? - azure

I have my confidential client and resource client registered in AAD.
The confidential client has API permissions to access the resource client.
After I logged in from the confidential client with my credentials how can I can make a request to the resource client?
Based on the ms docs
For example, if your web API's application ID URI is https://contoso.com/api and your scope name is Employees.Read.All, the full scope is:
https://contoso.com/api/Employees.Read.All
The example is not enough for me to understand like where's the access token?

You could use auth code flow to obtain the access token.
First, get code by the url in your browser. You need to login in this step.
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id={your-client-id}
&response_type=code
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&response_mode=query
&scope=https://contoso.com/api/Employees.Read.All
&state=12345
Then, get access_token with the code.
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
client_id={your-client-id}
&scope=https://contoso.com/api/Employees.Read.All
&code={the code from the previous step}
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&grant_type=authorization_code
&client_secret={your-client-secret}
About implicit grant flow:
This flow is usually used for single-page apps, and the implicit grant presents more risks than other grants. Please check if the implicit grant is suitable for your app, see here. If not, I still recommend you use auth code flow.
Note: To let it work, you need to select access tokens under the Implicit grant section in the portal first, navigate to App registrations -> your application -> Authentication.
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id={your-client-id}
&response_type=token
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&scope=https://contoso.com/api/Employees.Read.All
&response_mode=fragment
&state=12345
&nonce=678910
&prompt=none

Related

For IMAP.AccessAsUser.All Scope ADSTS65001: The user or administrator has not consented to use the application

In my java web application I want to get access to user's mailbox by using jakarta mail. For that purpose I followed https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth for OAuth2 authorization code flow.
On Azure port I setup my app and added API permissions as below
Now user is redirecting to below authorize endpoint:
https://login.microsoftonline.com/5426ee07-9b73-4a9e-8075-395ab439c6fa/oauth2/v2.0/authorize?client_id=b6067ad9-7195-430b-a35d-97b7aa7beb8f&response_type=code&redirect_uri=http://localhost:8080/callback/microsoft&response_mode=query&scope=offline_access%20https%3A%2F%2Fgraph.microsoft.com%2FIMAP.AccessAsUser.All%20https%3A%2F%2Fgraph.microsoft.com%2FSMTP.Send
After entering credentials and accepting the consent redirect_uri gets hit with auth code. Based on that auth code I formed token endpoint URL and hitting it from server, the token endpoint is as follow:
URL: https://login.microsoftonline.com/5426ee07-9b73-4a9e-8075-395ab439c6fa/oauth2/v2.0/token
Form Data:
client_id=b6067ad9-7195-430b-a35d-97b7aa7beb8f
scope=offline_access%20https%3A%2F%2Foutlook.office.com%2FIMAP.AccessAsUser.All
redirect_uri=http://localhost:8080/callback/microsoft
grant_type=authorization_code
client_secret=QUs8Q~aboLBiopTezMTKwzQjIwWsFFXjc2kCRaRs (I know I have shared the secret)
code={code received from authorize end point}
Response to this post request comes as:
{"error":"invalid_grant","error_description":"AADSTS65001: The user or administrator has not consented to use the application with ID 'b6067ad9-7195-430b-a35d-97b7aa7beb8f' named 'Email Connector'. Send an interactive authorization request for this user and resource.\r\nTrace ID: dc008ced-e23f-4919-bd45-b7ae7c68b000\r\nCorrelation ID: 9b6ede03-3c05-4a78-8975-036a3cb20773\r\nTimestamp: 2022-06-07 19:51:30Z","error_codes":[65001],"timestamp":"2022-06-07 19:51:30Z","trace_id":"dc008ced-e23f-4919-bd45-b7ae7c68b000","correlation_id":"9b6ede03-3c05-4a78-8975-036a3cb20773","suberror":"consent_required"}
Here, I don't understand why the error is saying The user or administrator has not consented to use the application, user has accepted the consent after entering credentials on authorize end point. Event more If we look at the screenshot above admin has already given grant to access the directory.
I tried to reproduce the same scenario in my environment and got the same error as below:
To resolve the error, please check the authorize endpoint you are using to get the code.
Avoid using Microsoft graph API scopes while getting the code.
Replace it with the scope you are using to get access token like below:
https://login.microsoftonline.com/Your_TenantID/oauth2/v2.0/authorize?
client_id=Your_ClientID
&response_type=code
&redirect_uri=http://localhost:8080/callback/microsoft
&response_mode=query
&scope= offline_access https://outlook.office.com/IMAP.AccessAsUser.All
&state=12345
Get the code from the above authorization endpoint.
I got the access token successfully after modifying the endpoint like below:
To validate the access token decode it in jwt.io and check the aud and scp claims like below:

Calling Azure WebApi from Postman with specific scope

I use Postman to test my API hosted in Azure. First I get an Access Token like this
Since I use the grant_type ´client_credentialsI have to use the default scope like this api://my-app-id/.default` as explained here.
But one of the endpoint of my API requires a specific scope, so the call fails because my access token does not contain this scope.
How am I supposed to test from Postman with the required scope ?
If you use Client Credential Flow to obtain an access token for an api protected by Azure, you must create an application and grant application permissions to the application (this is because Client Credential flow has no user interaction).
Then you need to define the application permissions by editing the list of api applications.here is an example.
Next, grant application permissions to the application:
Refer to this document and use Client Credential flow to get access token here:
1.First you need to get the administrator's consent:
GET https://login.microsoftonline.com/{tenant}/adminconsent?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&state=12345
&redirect_uri=http://localhost/myapp/permissions
2.Then you can get the access token by sharing the secret:
POST /{tenant}/oauth2/v2.0/token HTTP/1.1 //Line breaks for clarity
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=535fb089-9ff3-47b6-9bfb-4f1264799865
&scope=api://your-app-id/.default
&client_secret=qWgdYAmab0YSkuL1qKv5bPX
&grant_type=client_credentials
Parse the token and you will see your custom roles:
Try using the token to access your API.
Update:
According to your mistakes, there is user interaction, so if you want to use a user token, you should not use Client Credential Flow but auth code flow, and grant client application Delegated permissions.
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&response_type=code
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&response_mode=query
&scope=api://11f5aca5-ba22-4b7b-8312-60a09aab7xxx/Files.Upload
&state=12345
POST /{tenant}/oauth2/v2.0/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&scope=api://11f5aca5-ba22-4b7b-8312-60a09aab7df5/Files.Upload
&code=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq3n8b2JRLk4OxVXr...
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&grant_type=authorization_code
&client_secret=JqQX2PNo9bpM0uEihUPzyrh
Parse the token and you will see your custom scp:

Why aren't the application permissions being added to my MS Graph token?

I'm trying to get a subscription created with the callRecord resource (https://learn.microsoft.com/en-us/graph/api/subscription-post-subscriptions?view=graph-rest-beta&tabs=http)
In the app registration section of the Azure portal, I've created a multi-tenant app with a client secret. That app has permissions for application-level "CallRecords.Read.All" as well as the default delegated "User.Read". The statuses also have a green checkbox for being granted against my organization by an admin.
I am able to get an access token with the following HTTP POST request to https://login.microsoftonline.com/common/oauth2/v2.0/token:
grant_type:authorization_code
scope:https://graph.microsoft.com/.default
client_secret:<client_secret>
client_id:<client_id>
code:<code>
redirect_uri:http://localhost:3000
However, that token is not able to generate a subscription to my callRecord resource. I get a response with this message: "Operation: Create; Exception: [Status Code: Forbidden; Reason: The request is not authorized for this user or application.]"
The message suggests that the app has not been granted admin-level authorization, but in fact it has. This used to work for me. I'm wondering if there has been a regression on the MS Graph side.
Further, when I examine the JWT, I see that the scope is "User.Read profile openid email". There is no mention of the application-level permission (specifically, CallRecords.Read.All)
Thanks.
Because when you use the auth code flow, just the Delegated permission will take effect. So even if you grant the Application permission, the token you got will not include the permission.
From the doc, to call this API Get callRecord, just the Application permission is supported.
To get the token which include the permission, your option is to use the client credential flow.
Note: You need to use <tenant-id> instead of common in this flow.
POST https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token
client_id=xxxxxxx
&scope=https://graph.microsoft.com/.default
&client_secret=xxxxxxx
&grant_type=client_credentials
Decode the token in https://jwt.io, the roles includes the CallRecords.Read.All permission:

Wrong access_token from AAD with OAuth2 flow

I am making OAuth 2.0 auth code authentication flow with multi-tenant application.
Here is my authorize url:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=my_id&prompt=consent&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauthorize&response_type=code&scope=openid+offline_access&state=17
It goes fine and I receive auth_code. Then I make request with this auth_code to token_url and receive a lot of information, like:
token_type
scope
id_token
access_token
refresh_token
expires_at
ext_expires_in
Seems fine to me, but when I make request on API with access_token like:
https://management.azure.com/subscriptions/my_sub_id/locations?api-version=2016-06-01
with headers:
Content-Type:
- application/json
Authorization:
- Bearer EwBQA8l6BAAURSN/FHlDW5xN74t6GzbtsBBeBUYAAV1IHgHb4dOWblzfd/YsSuFicAMDYbua17QivnAT9/pIaeKAg3uKsK5VGqWLzjMOUQrCpd7R1RAM6RkzI0u8e4rpO7DISG7qLso5H5+U1jb+38/j1urcwlXMMxhy83ZXmdpkLXpZV+vcOV...
It responds with 401 error
body:
encoding: UTF-8
string: '{"error":{"code":"InvalidAuthenticationToken","message":"The access token is invalid."}}'
To be honest I think something wrong with my access_token. It seems not like JWT for me. Documentation says it looks like:
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCEV1Q..."
But my access_token looks like:
"access_token": "EwBYA8l6BAAURSN/FHlDW5xN74t6GzbtsBBeBUYAAZDe7JE/MPLoAi+Fr+1Xxq5eBe5N9l8Q+c4QjkY5PGEzRnBpPe7+v6h+PLdh1cceBQx+/JsB2QCrYSCt7x/zGsQAhwoY/"
Is it fine?
Here is my permissions for application:
Permissions
The main issue you have here is that you have only asked for an access token for the scopes openid offline_access. The resulting access token will be for Microsoft Graph (https://graph.microsoft.com), not for the Azure REST API (https://management.azure.com).
To indicate you would like a token for a given API, the scope parameter in your authorization request should include the delegated permission you would like the app to have for the API. In the case of Azure REST API, there's only one delegated permission: user_impersonation. The identifier URI for the Azure REST API is https://management.azure.com, so the scope value you want to use is:
openid offline_access https://management.azure.com/user_impersonation
Two more important notes:
As you've discovered, you will not always be issued an access token as a JWT which you can decode peek at. The format of the access token is an agreement between the service which issued the token (Azure AD or Microsoft Accounts, in this case), and the service for which the token was issued (Microsoft Graph, in this example).
You should not always include prompt=consent. prompt=consent should only be used if you have already tried signing in the user without the user needs to be re-prompted for consent for a new permission.
If you simply include the required scopes in the scopes parameter, the Microsoft Identity platform will take care of figuring out if it needs to prompt for consent or not. If you always include prompt=consent, you will find that many organizations will be blocked from accessing your app, because they've disabled the ability for users to grant consent themselves (and this parameter specifically states that you require the user to be prompted again).

Microsoft Graph - How to obtain token non-interactively?

I want to obtain a token on Microsoft Graph via a GET request.
If I use the following call, I get a login screen asking for username and password.
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?
client_id=f3992025-4d4d-XXXXX-bb2d-XXXXXXXXX
&client_secret=XXXXXXXXXXXXXXXXXXXXXXXXXX
&response_type=code
&redirect_uri=https://10.100.XXX.XXX:5858/authorize
&response_mode=query
&scope=openid%20offline_access%20https%3A%2F%2Fgraph.microsoft.com%2Fmail.read
&state=12345
if I do so, i do I get the code necessary to later obtain the token and I can use it no without issues
My problem is that I don't want to that login screen. I want the request to return the code without user interaction. I thought that the client_id and client_secret would take care of this.
I am following this directions: https://developer.microsoft.com/en-us/graph/docs/concepts/auth_overview
Thank you.
As far as I know, you can use OAuth 2.0 client credentials grant to access web-hosted resources by using the identity of an application.It's is used for server-to-server interactions.For more information, please click https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow.
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
client_id=f3992025-4d4d-XXXXX-bb2d-XXXXXXXXX
&scope=https://graph.microsoft.com/.default
&client_secret=XXXXXXXXXXXXXXXXXXXXXXXXXX
&grant_type=client_credentials

Resources