Entra ID / Azure AD authentication and authorization are important components for service access within any environment and one of the common questions I’ve been asked is what is the difference between application and delegated permissions in the context of App Registration permissions. The short answer is that application permissions will have the application authenticate as itself, while delegated is where the application will authenticate on behalf of a user. The following Microsoft document provides a great walkthrough of the differences between the two: https://learn.microsoft.com/en-us/graph/auth/auth-concepts. These two types of authentication and authorization can have impactful security consequences when designing applications so it is important to use the correct model. What I’ve found to be most effective in explaining this is demonstrate how to perform both authentication with Postman so the purpose of this post will be a demonstration of setting up the authentication to retrieve the Bearer token, and then calling an API using the token with the appropriate authorization.
One point I would like to highlight is that Postman provides a built-in OAuth 2.0 provider authentication tab that makes the process of retrieving the JWT token much simpler than manually configuring an API GET call to the endpoint but this in turn means you won’t know the details of what is sent to the API endpoint. With that, I will show both methods as there are benefits of knowing exactly what header and body content are being sent if you’re writing an application or script to retrieve a token.
Setting up an App Registration in Entra ID
Before we set up Postman, we will need to create an App Registration to represent the Postman so it can be used to authenticate against Entra ID / Azure AD and use its authorized permissions to perform activities such as use the Graph API.
Begin by setting up an App Registration in Entra ID:
Provide a name for the App Registration, adjust the supported account types for either single tenant or multitenant, leave the Redirect URI as blank for now, and create the instance:
With the App Registration created, we can now copy the property values that we’ll use within Postman to authenticate against Entra ID / Azure AD. Navigate to the Overview blade and copy the following values:
- Application (client) ID
- Directory (tenant) ID
Proceed to create a secret for the App Registration and make sure you copy the value of the secret before navigating away as you cannot retrieve the secret after leaving the page:
Permissions need to be configured for this App Registration to allow our Postman to call the Graph API either on behalf of the user using Postman, or as an application identity configured for Postman. Proceed to navigate to the API Permissions blade and note the default User.Read permission already granted to the App Registration.
Let’s proceed to grant 2 additional permissions to the App Registration for testing both Application and Delegated permissions by clicking on Add a permissions:
Click on Microsoft Graph:
Note that this is where you configure Delegated permissions or Application permissions for the application using this App Registration to authenticate against Entra ID / Azure AD:
We’re going to configure both for the purpose of this walkthrough so select Delegated permissions, search for User.Read, select User.Read.All and then add the permission:
Repeat the process for Application permissions:
Some permissions will need consent granted by an admin and the 2 that were configured require this so click on Grant admin consent for <Company Name> to grant the consent:
A green check box will be displayed once consent has been granted:
The last step is to configure the Redirect URI we left as blank during the creation of the App Registration. Navigate to the Authentication blade and look for the following field:
Web
Redirect URIs
The URIs we will accept as destinations when returning authentication responses (tokens) after successfully authenticating or signing out users. The redirect URI you send in the request to the login server should match one listed here. Also referred to as reply URLs. Learn more about Redirect URIs and their restrictions
The purpose of the redirect URI, or reply URL, is for Entra ID to know where to send the authentication response once the App Registration has been successfully authorized and granted an authorization code / access token. In the case of this example, we are sending the code back to Postman and the URL to use is:
https://oauth.pstmn.io/v1/callback
For more information about the Redirect URI, see the following documentation: https://learn.microsoft.com/en-us/entra/identity-platform/reply-url#redirect-uris-in-application-vs-service-principal-objects
The configuration for the App Registration representing Postman is now complete.
Setting up Postman
Having a nicely organized setup of Postman collections and variables will save you time during testing and improve the handling of sensitive values. Start by creating a Collection for this exercise.
Next, navigate to the Environments menu to configure the following secret and variables that were saved earlier during the App Registration creation that we be using for our API calls.
- client_id
- client_secret
- tenant_id
Application Permissions
Let’s start with the simpler application permissions configuration.
Using Postman’s Authorization Feature to get Token
Begin by clicking on the ellipsis icon and select Add request:
Then navigate to the Authorization tab and fill in the following:
Type: OAuth 2.0
Add authorization data to: Request Headers
Token: Available Tokens
Header Prefix: Bearer
Token Name: <Name of preference>
Grant type: Client Credentials
Access Token URL: https://login.microsoftonline.com/{{tenant_id}}/oauth2/v2.0/token
Client ID: {{client_id}}
Client Secret: {{client_secret}}
Scope: https://graph.microsoft.com/.default
Client Authentication: Send as Basic Auth header
Leave the rest as default and click on Get New Access Token:
The operation should return the information as shown in the screenshots below:
Proceed to copy the Access Token value and with this, we can navigate to https://jwt.io/, paste the value to inspect the details of the token and confirm that the App Registration ID and permissions are displayed for this token:
Next, we can use this token to perform a Graph API call and confirm that we are allowed retrieve the information. Create a new request and configure the following parameters:
GET https://graph.microsoft.com/v1.0/users
Under Headers, fill in the following Key and Value:
Authorization: <Paste the token created in the previous step>
Content-Type: application/json
Proceed to click on the Send button:
The list of users in Entra ID should be displayed:
As this is an application authentication, there are certain Graph APIs that it would unable to call and an example of this is the /ME where the following error would be thrown:
{
“error”: {
“code”: “BadRequest”,
“message”: “/me request is only valid with delegated authentication flow.”,
“innerError”: {
“date”: “2023-11-11T16:03:48”,
“request-id”: “8840028e-9a93-4e89-9818-fbcd77e19b60”,
“client-request-id”: “8840028e-xxxx-xxxx-xxxx-fbcd77e19b60”
}
}
}
I’ll show how we can make this call this with delegated permissions later in this post.
Directly calling API Endpoint to get Token
Retrieving an OAuth token via the Postman Authorization feature was easy but there are scenarios where we want to call the API endpoint instead because we will be using the same header and body settings in an application. The following are the header and body configuration for Postman.
Begin by clicking on the ellipsis icon and select Add request, then navigate to the Headers tab and fill in the following:
GET https://login.microsoftonline.com/{{tenant_id}}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
Navigate to the Body tab, select form-data and fill in the following:
grant_type: client_credentials
client_id: {{client_id}}
client_secret: {{client_secret}}
Scope: https://graph.microsoft.com/.default
Client on the Send button to submit the request and confirm that the access token is returned:
Pasting the token into https://jwt.io/ will return the same results as the previous Postman Authorization request:
Repeat the steps above to call the GET https://graph.microsoft.com/v1.0/users API endpoint will return the same results.
Delegated Permissions
Let’s continue moving onto delegated permissions where the App Registration will call the Graph API on behalf of the user.
Using Postman’s Authorization Feature
Begin by clicking on the ellipsis icon and select Add request:
Then navigate to the Authorization tab and fill in the following:
Type: OAuth 2.0
Add authorization data to: Request Headers
Token: Available Tokens
Header Prefix: Bearer
Token Name: <Name of preference>
Grant type: Authorization Code
Callback URL: https://oauth.pstmn.io/v1/callback
Authorize using browser: Enabled
Auth URL: https://login.microsoftonline.com/{{tenant_id}}/oauth2/v2.0/authorize
Access Token URL: https://login.microsoftonline.com/{{tenant_id}}/oauth2/v2.0/token
Client ID: {{client_id}}
Client Secret: {{client_secret}}
Scope: https://graph.microsoft.com/.default
Client Authentication: Send as Basic Auth header
**Note the default Callback URL is set as https://oauth.pstmn.io/v1/callback, which is the URL we configured earlier for the App Registration’s Redirect URI.
Leave the rest as default and click on Get New Access Token:
The following Get new access token prompt will be displayed with a browser directing you to the login.microsoftonline.com to log into Entra. Proceed to log into Entra ID to retrieve the token:
The following will be displayed upon successfully authenticated. Note the URL displayed in the browser:
https://oauth.pstmn.io/v1/callback?code=0.AVEAC0f0hB4_iUiflasPUUMCT1d_QBUsqGVPhgiMkNV16uVRANQ.AgABAAIAAAAmoFfGtYxvRrNriQdPKIZ-AgDs_wUA9P-CoVXQzw9BTb3FWH1dw6QqHEhjwSMkqJy1t5HGBarSFJY2Ckt4VaBvEF8-wBc3iirPRCA-Eo44cVWUBspus3IsPj521nlt9KqQbNjs0Ub8QMZJbRuocDMoHEyG3v6VGxH-MM_ll5NX34ys5wwTt8v01wjx0ZhAv9I-hUovaikvHFAup5BA19MJNaNmrNZS7tD9PEfw_F-Vs84tGaVJ0NXTfSLZIZnSmlVg1nsnk9-94P3W2x_mzdIwX3eho4p2yFiHK803pZrJKN7BaQnrgK5RfYL1mdYKMUCE7dfH0w1rQsYgREVYK6_KMOEYCzX_Z8D8vMJQl2Nd3xG9zCQPdVY-tcVxmUXNf3R29OlRvAqq3w-ZlGuwTCxIFdvX0ljOt5xWpzVo5oAqR7UQKjwIo-F2aVkJ4KcTIdjbg8TWcX7lOsjBuR8ZkdGIYBVtRTzrWskElP-Dxx6NP_LpDI4VInu7j4Uxs4ebIxMAF9YsGoS0M6vvY6cSvoFZcG_PXJYYk2I4tgqDS7FrEQ9ihk26x86–YRiwEO26tExgsxee0IfJVhuIqFNMqc-3FmGalsXnZxeDzYpppJpZarmAmnr2GjXVELWJhjB5bjt-Wsg9aCHAx_eb8rAKrxveOWEqGMLp9cBp5M&session_state=378b4cdc-e06b-4624-9618-047c3f12d5fc#
… and the value of code= in the URL. While this is not important for using Postman’s Authorization tab for retrieving the token, this is the code that is passed back to Postman to generate a token for the user who has just logged in:
The token will be displayed:
Copying the token and pasting it into https://jwt.io/ will return details and we can see that this token is issued in the content of the user who has just authenticated. The user details are provided and because this account is synchronized from an on-premise Active Directory, the onprem_sid is also provided:
This token can then be used to call the Get Users API endpoint as well as the /ME endpoint because the App Registration is now calling on behalf of a user and not itself:
Directly calling API endpoint to get Token
Using the Postman’s Authorization Feature is very easy but manually calling the endpoint requires a few extra steps. As shown in the previous steps, delegated permissions will require the user to interactively log in to retrieve a code that will then be used by the application to retrieve a token for the user. There isn’t a way for us to automatically launch a browser when sending a request to the API endpoint but we can manually retrieve it by using a browser.
To obtain the code for a user identity we’ll need to launch browser and navigate to a URL with specific parameters. The components we’ll need are:
Tenant ID: <The tenant ID of Azure AD>
App Registration Client ID: <The client ID of the App Registration>
Redirect URI: <This is where you will use the code generated to retrieve a token for the user>
Scope: <The scope in which we’ll be using this token for>
Here is how the browser URL string should be configured:
https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/authorize?client_id=<appRegistrationClienID>&response_type=code&redirect_uri=<URLwhereTheTokenIsReturned>&response_mode=query&scope=<scope>
Here is a sample of what the browser URL string would look like:
https://login.microsoftonline.com/84f4470b-3f1e-xxxx-xxxx-ab0fxxxx024f/oauth2/v2.0/authorize?client_id=154xxxx7-xxxx-4f65-xxxx-8c90d575eae5&response_type=code&redirect_uri=https://oauth.pstmn.io/v1/callback&response_mode=query&scope=https://graph.microsoft.com/.default
Customize the tenant ID and client ID, and use the following for:
Redirect URI: https://oauth.pstmn.io/v1/callback
Scope: https://graph.microsoft.com/.default
Paste the URL into the browser, authenticate into Entra ID and a string similar to the following will be displayed in the browser navigation bar upon successfully authenticating as the user:
https://oauth.pstmn.io/v1/callback?code=0.AVEAC0f0hB4_iUiflasPUUMCT1d_QBUsqGVPhgiMkNV16uVRAOA.AgABAAIAAAAmoFfGtYxvRrNriQdPKIZ-AgDs_wUA9P-gz3Qp7LOLK9NV2bmKKD5T1KzlW2EwwHmIyq-a0AXhwSpil3quUTpV_dW7ruHNnenPskMN4hOoTaMY0lkTzRoMM58Ta95ayQXvNUt-yPttTUkkpYTISCrcSo29LRMX2RcKdx7opKABxxSAOwQAp1D9eIkJlTltkDjS70yv86r1Agl7MDawQx8YYcXUj1tP8wevrvFMcKPJQNPhq83YepJOypSB0nl3EYq7mPZmyjV9BWh3IMnV4t4qbfa4y14iQyMpkSuGLSudZh2JNNfZxirT56Y8B9una2oBjFHMMBvDIdSY-caXUJe1qytIXUs1jFeljMhtv9gKuBiWMMdk8aPUt-7twIpgpBjktdIJ8ihsK1MdGy0jBz0zd96eG8bSJTRGgXkQv87dsX0O761XSP_tqd8EqzthkDGR5iixvuZcBuQeaIs4YJ_tb9pVtWLSufrbmka1Rqz0ghbZiFk1TA1bqKr-S3_LJsoiUaCCKdYH_lohvfRBlzdtHXLhxx8y8iGddw82Mlj-Bzk_gc_N-Vq7YLa71CL1r__aJ89AfM_klt_ouGy_vHx_9BxPc3VRXTrjsuB9tDoqIlb9UA91JMe9oRySMQASCErucmFVZ_G7JJGYUchpNsuu4HP0kzHakuGGLTBJGHRV8gRowj63X4B4QEARL-4Khqo&session_state=c78c420a-d68a-4713-bcf5-e04910dc3902
The code we need for our Postman call is in between code= and &session_state as highlighted above.
Navigate to the Body tab, select form-data and fill in the following:
grant_type: authorization_code
code: <paste the code retrieved from the browser URL after authentication>
client_id: {{client_id}}
client_secret: {{client_secret}}
redirect_uri: https://oauth.pstmn.io/v1/callback
Client on the Send button to submit the request and confirm that the access token is returned:
The token retrieval should complete:
With the token successfully retrieved, we can navigate to the JWT Token portal: https://jwt.io/ and paste the token into the text field to confirm that the expected User (not App Registration) and roles are configured:
With this token successfully retrieved, we can repeat the steps from the previous examples to perform a Graph API calls.
I hope this provides a bit more clarity on the differences between application and delegated permissions as well as how to set up Postman to perform both types of authentication and authorization.