Performing Azure AD OAuth2 Authorization Code Grant flow with PKCE in PostMan

Proof Key for Code Exchange (PKCE) is a mechanism, typically used together with an OAuth2 Authorization Code Grant flow to provide an enhanced level of security when authenticating to an Identity Provider (IDP) to get an access token. In fact for Single Page Applications (SPA), Authorization Code Grant flow with PKCE is now the recommended OAuth2 authentication protocol over its predecessor, the Implicit Grant flow, for acquiring an access token. For other client types, including Native and Confidential, that use Authorization Code Grant flow, it’s still recommended use this flow with PKCE if possible.

Let’s talk about the protocol…

I’ll assume that you already have an understanding of how OAuth2 Authorization Code Grant works, so I won’t cover that in great detail. I’ll attempt to simplify how PKCE can be used on top of Authorization Code grant to make the protocol more secure with the following diagram:

Everything in the above diagram except for the red addition for PKCE is how the Authorization Code grant flow works.

  1. In Step 1, the client application creates a “secret” string, called a “Code Verifier”. It then uses an algorithm to hash this secret string and then sends the hash of this secret string known as the “Code Challenge” in the Authentication request. The currently supported hashing algorithm are:
    1. plain – there is no hashing. The secret is sent as is
    2. S256 – The secret is hashed using SHA256 Algorithm
  2. Upon verifying the credentials, Azure AD sends back to the client an Authorization Code
  3. The client redeems the Authorization Code for an Access Token. In this step the client also needs to send the “secret” string aka the “Code Verifier”
  4. Azure AD verifies that the “secret” string’s hash matches what it receives in step 1 and issues a token

PKCE helps mitigate the Authorization Code interception security attack which can happen in step 2 where a malicious app can intercept the Authorization Code. Without knowing the “secret” the malicious app won’t be able to exchange the Authorization Code for an access token. Without a valid “code verifier”, Azure AD may return the following error:

AADSTS50148: The code_verifier does not match the code_challenge supplied in the authorization request for PKCE

Let’s use PostMan to perform this flow

You need to have at least PostMan version 7.23 installed and a registered application in Azure AD. If you want to create a new App Registration for this, you can create a new app with the following setting:

  1. Use ‘Accounts in this organizational directory only – Single tenant’ for supported account types.
  2. Add ‘https://localhost’ as a Web Platform redirect URI
  3. Create a secret in the ‘Certificates & secrets’ blade – take note of the secret as you won’t be able to see this secret once navigating away from the pane.
  4. Take note of the Application (client) ID of the app in the Overview blade

Configuring PostMan…

Launch PostMan and click on the ‘Authorization’ section. Choose ‘OAuth 2.0’ in the drop down under Type. Click on ‘Get New Access Token’ button.

In the Get New Access Token dialog:

  1. For Grant Type, choose ‘Authorization Code (With PKCE)’ from the drop down
  2. Callback URL – this is the redirect URL configured earlier in the App Registration, so use ‘https://localhost’
  3. For Auth URL, use ‘https://login.microsoftonline.com/<Directory ID>/oauth2/v2.0/authorize’
  4. For Access Token URL, use ‘https://login.microsoftonline.com/<Directory ID>/oauth2/v2.0/token’
  5. Code Challenge Method – use SHA-256
  6. Code Verifier – you can leave blank and PostMan will generate one for you. Alternatively you can use your own secret string or use this Online PKCE Generator Tool to create one for you. Note that PostMan will automatically create a “Code Challenge” based on the supplied “Code Verifier”.
  7. Fill in the Client ID and Client Secret info from your App Registration
  8. You can use ‘https://graph.microsoft.com/.default’ for scope. When creating a new App Registration in the portal, the Microsoft Graph permission “User.Read” should already be configured.

Here is what things should look like in PostMan:

Clicking on “Request Token” should prompt you for login and returning an access token.

Doing it manually…

  1. Get the Authorization Code:

GET https://login.microsoftonline.com/<tenant>/oauth2/v2.0/authorize?
response_type=code
&client_id=<your App ID>
&scope=openid
&redirect_uri=https%3A%2F%2Flocalhost
&code_challenge=<your code challenge>
&code_challenge_method=S256

This step can be tried by using a web browser. Paste in the URL above with your parameter and authenticate. Once you successfully authenticate, you can get the Authorization Code from the the browser’s address bar

  1. Exchange the Authorization Code for an Access Token

POST https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token
POST Request Body:
grant_type : authorization_code
code : <Authorization Code from step 1>
redirect_uri : https://localhost
client_id : <your App ID>
client_secret : <your App Secret>
code_verifier : <your code verifier>

You can try this step in either PostMan or Fiddler. Note that if you use ‘plain’ for ‘code_challenge_method’ in step 1 then the ‘code_challenge’ is the same as the ‘code_verifier’.

The Code Verifier

The PKCE specification requires that the Code Verifier be a random string of these characters: {[A-Z] / [a-z] / [0-9] / “-” / “.” / “_” / “~”} and that its length be between 43 characters and 128 characters. At the time of this writing, Azure AD does not seem to impose the length limit.

The Code Challenge

Per PKCE specification, the Code Challenge is defined as below:

For S256 transformation, the Code Challenge is the Base64URL-Encoding of the SHA256 hash of the Code Verifier.

Borrowing the code snippet from https://medium.com/the-new-control-plane/using-proof-key-for-code-exchange-pkce-in-adfs-for-windows-server-2019-a457172e28c3, I made some modification to generate a random “Code Verifier” string. Below is the .Net code to create both a Code Verifier and Code Challenge:

using IdentityModel;
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace PKCEConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            var random = new Random();
            int cvlength = random.Next(43, 128);
            const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
            var codeVerifier = new string (Enumerable.Repeat(chars, cvlength).Select(s => s[random.Next(s.Length)]).ToArray());

            string codeChallenge;
            using (var sha256 = SHA256.Create())
            {
                var a = Encoding.UTF8.GetBytes(codeVerifier);
                var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
                codeChallenge = Base64Url.Encode(challengeBytes);

/* Alternatively instead of using Base64Url.Encode method, the code below can accomplish the same result:

                var result = Convert.ToBase64String(challengeBytes)
                    .Replace('+', '-') // replace URL unsafe characters with safe ones
                    .Replace('/', '_') // replace URL unsafe characters with safe ones
                    .Replace("=", ""); // no padding
*/
            }

            Console.WriteLine("codeVerifier " + codeVerifier + "\n");
            Console.WriteLine("codeChallenge " + codeChallenge + "\n");

            Console.ReadLine();
        }
    }
}

For nodejs application, take a look at this npm package, and to see how to do it in javascript, refer to https://stackoverflow.com/questions/59777670/how-can-i-hash-a-string-with-sha256-in-js for some ideas.

Single Page Application (SPA) Apps

We recommend using MSAL.js v2 for performing Authorization Code Grant with PKCE for Azure AD Applications. Take a look at this tutorial and the code sample at https://github.com/Azure-Samples/ms-identity-javascript-v2 for more info.

Note that MSAL.js v1 is for Applications performing Implicit Grant flow and MSAL.Js v2 is for Authorization Code flow with PKCE.

Intelligent Tracking Protection (ITP) feature

Due to privacy concern, certain browsers, for instance Safari, may implement ITP feature to block 3rd party cookies. This results in breaking authentication for SPA apps using Implicit Grant flow. For this, it’s recommended that you use Authorization Code flow with PKCE for authentication. Refer to https://docs.microsoft.com/en-us/azure/active-directory/develop/reference-third-party-cookies-spas for more info.

References

OAuth 2.0: Implicit Flow is Dead, Try PKCE Instead

PKCE Specification

Implicit Flow vs. Code Flow with PKCE

Setup Postman to call Microsoft Graph using a Client Credentials Grant Access Token from the v2 endpoint

To use the V1 endpoint, please refer to this post.  Our documentation for the client credentials grant type can be found here.

You can setup postman to make a client_credentials grant flow to obtain an access token and make a graph call ( or any other call that supports application permissions ). This is very useful for testing code you plan to run as a script or in a Daemon application where you do not want user interaction.

The first thing you need is an app registration in your Azure Tenant to perform this flow. Create a new application registration:

Note the application id as you will need it later – this is the client_id used in the setup for postman:

Click on the API permissions and assign application permissions. By default, Microsoft Graph is already selected with a delegated permission of User.Read. I will leave that there to demonstrate that permission will not be present in the access token when performing this flow. Lets add an application permission for Microsoft Graph of Group.Read.All :

Once added, you will now see your permission listed however, all application permissions always require a tenant admin to consent to these permissions:

Grant admin consent:

Next, the client_credentials flow requires a client secret. Go to the Certificates and Secrets blade and create a new client secret:

The value is only shown one time so be sure to copy it to the clipboard with the copy to clipboard button and store that somewhere safe. You don’t want that secret to get out!

The first method I will demonstrate to you for obtaining an access token with Postman is through the Authorization UI. Start a new request, then click on the Authorization tab and select OAuth 2.0 from the drop-down type list:

To configure the flow, select Client Credentials from the Grant Type drop-down box then plug in your values for the settings it requests. For the scope, I am using https://graph.microsoft.com/.default which will pull the default values configured for Microsoft Graph from the app registration – in this case, we are expecting the groups.read.all permission. Use https://login.microsoftonline.com/{your-tenant}/oauth2/v2.0/token/ for the Access token URL ( obtained from the portal “Endpoints” – see next image ), the client id from the app registration and of course, the client_secret you configured on the app registration.

The Access Token URL can be obtained from the portal in the App Registrations blade by clicking on the “Endpoints” button:

Grab the OAuth 2.0 token endpoint (v2). You can also use your tenant name in place of the tenant id ( guid ):

Save those values in the postman screen and then click on “Request Token”

You should get an access token like so:

To use this token, scroll to the bottom and click on the “Use Token” button:

You can now make a graph call ( based on the permissions you setup in the app registration – groups in this example ) – the rest endpoint in this example is https://graph.microsoft.com/v1.0/groups :

If you copy the access token and paste it in http://jwt.ms you can decode the token to see the claims it has. If you notice, our token only has permissions for group.read.all – which shows up as a “role”. Application permissions always show up as roles. Notice, there is not a delegated permission in this token because delegated permissions, even if consented to, will not appear in the token for a client_credentials grant type.

You can also just do a raw post request to the authority endpoint with the same values like this, again, you need to add the client_id, client_secret, scope but you also need to add grant_type when doing it this way and for that value, be sure to use “client_credentials”:

The values go in the body of the request in this scenario.

Summary:

You can use postman to obtain an access token for testing your api calls, etc. using the client_credentials flow as demonstrated.

Setup POSTMAN to get Azure access tokens automatically for you

Introduction

Postman is an HTTP request tool that is very handy for developing and testing your Azure requests. This is the Postman website: https://learning.getpostman.com/

Postman does make it easy to setup authentication and acquire access tokens but it normally is a multi-step process. The purpose of this blog post is to show you how you can setup Postman to automatically handle authentication for you so you don’t have to go get a new token manually to test with. This example will concentrate on using the Client_Credentials flow targeting Microsoft Identity Platform V2 endpoint.

Client credentials flow V1 endpoint

Client credentials flow V2 endpoint

Setup the Environment

The first step in this process is to setup your environment so you can create variables that will be used in your headers and or body. To do this, you can use the “New” button on the upper left corner of the screen. There is also a gear icon in the upper right hand corner of the screen where you can create the environment as well but lets start with the New button

Click on “New” à “Environment” and give it a meaningful name. In my example, I am using a dummy tenant name.

Lets add some environment variables in the Variable chart for that environment. You could add the variables on the collection side but I prefer using the environment so I can switch values easily just by selecting the environment.

Add the following variables:

  • client_id
  • client_secret
  • token_endpoint
  • scope
  • access_token

Set the initial and current values on the variables. Make sure you have a properly setup app registration with Microsoft Graph application permissions for User.Read.All to test this script and you have performed admin consent on those permissions. Also, note that all variables are case sensitive!

The V2 endpoint would look like this: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token/ (where {tenant} is where you would also add the tenant id – you cannot use a variable here )

Note: If you’re going to hit the v1 endpoint, you will not be using a scope parameter and would instead, need the resource parameter.

The scope would obviously depend on the resource you’re needing a token for. For Microsoft Graph, it would be: https://graph.microsoft.com/.default — just pulling the Microsoft graph permissions off your app registration. Your access token would then be for Microsoft Graph.

Next, create a collection to save your scripts to

Click on “New” à Collection. Give your collection a meaningful name and description if you like, then on the Pre-requests Scripts tab, add this script:

[gist id=”9bb52b6f4c4df275a7b6350e1a10fbd4″]

Then click update.

Build a simple Test Request

Now, build a simple request and save it into the Collection folder you have created. You can build a new request by right clicking on the new collection you’ve just created and then selecting “Add Request” and it will automatically be added to the collection.

See how I’ve used my variable names in key places for this request.

My URL for the GET request is: https://graph.microsoft.com/beta/users

I’ve added one simple Header for “Authorization” and set the value to: “Bearer {{access_token}}”

If you did not right click on the collection to add a new request, you can save the request setup to the collection by clicking on the Save drop-down box, then Save As:

Be sure to select the collection you created that has the pre request script on it and then save:

Run the request

When running your request now, make sure you have the correct environment selected to get the proper variable values

Click the send button and you should get the list of users in your tenant.

View the console for additional information

As you can see in the script, I am outputting some information for you into the console window. You can show the console window before running the script by clicking on View à Show Postman Console

You can see information in the console window such as the token that was generated and the calls that were made:

Summary

You can setup postman to make building requests for testing and troubleshooting purposes for the client_credentials flow by easily setting up a few variables, adding the pre-request script and then plugging the variables into your request. Each time the request is sent, you can get a new access token and use that as the bearer token for the request. You can open the console screen in postman (View/console) and see the token that was generated if you want to view that in http://jwt.ms as the script is outputting the token into the console, for additional troubleshooting purposes.

References

https://liftcodeplay.com/2018/03/18/how-to-automatically-set-a-bearer-token-for-your-postman-requests/

Implementing Service to Service Authorization and Getting the Access Token with Postman Utilizing Client Credential Grant Type

Introduction

This article is meant to show how one can set up a client application to obtain a service to service access token, to get access to a web API from a web App. This document will be following the grant type client credential flow to do this, and will utilize Postman to get the access token via client credentials. This tutorial will not set up the backend web API, and assumes that web API is validating the token, you can click this link on validating the JWT token here. Also in addition to that, the link included assumes that the Audience has the correct permissions. As the client credentials flow can get a different audience within your tenant, the end of this article will review what additional steps, to make sure that the access token has the correct permissions.

 

Creating the AAD Application Registrations in the Portal

First we are going to want to create the AAD Application registrations in the portal. For this we will implement the application to be able to work with Postman so that we can display getting the access token pretty easily. First we go to the Azure Active Directory Blade, go to App Registrations, and then create a new application registration.

 

 

2018-03-31 19_16_00-Create - Microsoft Azure - Internet Explorer

 

From there we are going to want to create a web app with any name. Here I have set the name as web app and then we want to set the callback url to : https://www.getpostman.com/oauth2/callback and set the application type to web app/ API.

 

image

 

You will have to click out of the sign-on URL to make it check whether or not if it’s correct.

 

After that we have created our web app, we will want to create a secret. Please keep track of the secret as you won’t be able to see the secret again. You will have to press save in order for the secret to generate.

 

image

 

With this information in hand, we will be able to move forward and connect to this AAD registration. But without the correct permissions we won’t be able to connect to the web API registration with an access token from this web API.

 

image

 

So here I create the API registration, with the sign-on URL as the localhost. How you plan on setting up your application will change what the sign-on URL will be.

 

 

Modifying the Application Manifest to Add Your Own Permissions

Since we are utilizing Client Credentials, we will need to add the permission in the Web API as an Application Permission as the Client Credential doesn’t utilize the delegated permissions. In addition to that we will most likely want to define what sort of permissions the web app should have for the web API. In order to do this we will have to add these permissions directly into the web API’s application manifest. You can do this by going to the AAD Application registration, clicking on Manifest and then adding the field “approles” into it. This is shown below.

The approle I added here is below. By setting the allowedmembertypes to “Application” we are setting it as an application role.

 

“appRoles”: [
{
“allowedMemberTypes”: [
“Application”
],
“displayName”: “Test Application Permission”,
“id”: “3ea51f40-2ad7-4e79-aa18-12c45156dc6a”,
“isEnabled”: true,
“description”: “I am a Test Application Permission.”,
“value”: “Test.Application.Permission”
}
]

 

To learn more about these values you can go to the link here describing the application manifest :

https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-application-manifest

 

To learn more about the App roles for an application please go here:

https://docs.microsoft.com/en-us/azure/architecture/multitenant-identity/app-roles

 

That being said, the one thing to note is that the allowedmembertypes isn’t described fully in the documentation above. By setting it to User, we set it as a delegated permission and have to ability to do RBAC access with the delegated permission. By setting it to an Application, we are able to set it as an application permission, letting anyone who can access the application to be able to access web API with the permissions granted to the web app.

 

You can learn more about the differences between delegated and application permissions here.

 

If you are interested in utilizing RBAC to control access in a service to service scenario you can follow this guide :

https://azure.microsoft.com/en-us/resources/samples/active-directory-dotnet-webapp-roleclaims/

 

In addition to that, the ID is created by utilizing the method below in PowerShell.

[System.Guid]::NewGuid()

 

Adding the Permission into the Web App

After adding the application permission in the application manifest, we are able to add the required permission to the web app in order to get an access token with the correct claims saying that this web app has application access to the web api.

image

 

 

image

 

 

Now we have the Application permission and we will be able to get it in the claims when we authenticate with the web app. Make sure to grant permissions, otherwise you won’t see the role in the access token as the application technically hasn’t been given permission yet as it requires a global admin to give the application access to the permission. Notice how it says yes under require admin in the last picture.

 

 

image

 

 

 

 

Getting the Access Token with Postman

 

After granting permissions for the application, we are now able to authenticate with the application and get the correct claims and audience in the access token. We will utilize client credentials to get an access token from Web App’s application ID with the secret and then with the resource set as the app ID URI for the web API, we will get the audience as the app id uri, and the roles for whatever permissions were granted to the web app.

 

image

 

 

 

image

 

 

 

image

 

image

 

From here, you can access the web api, assuming that you have set it up to authorize based on the audience, role, iss, and signature is correct (i.e. the access token hasn’t been tampered with and it is issued from the AAD tenant with the AAD Application registration in it). For more information on validating a JWT token you can find that here.

 

Conclusion

 

We have now gone through all the steps to set up the AAD application registration, modify the application manifest in the web API to create the permissions, add permissions in the web app aad application registration, grant permissions, and get the Access token using Postman to see if all the claims in the JWT token are correct. After all of this your web api will need to still manually validate that the jwt token hasn’t been tampered with and that all the claims are correct. After doing all these steps you should have now setup a service to service authorization using client credentials.