Connecting to Microsoft Graph using the Authorization Code with PKCE Flow and PowerShell

I’ve authored numerous posts on using the Microsoft Authentication Libraries to connect to Microsoft Graph using PowerShell and Python. They cover using both public and confidential client methods. But what about a method that can be either? In this post I show how to use the Authorization Code with PKCE Flow and PowerShell to authenticate and authorize against Azure Active Directory for Microsoft Graph access. However, the details are portable to other IDPs as OAuth 2.0 that specifies the Authorization Code with Proof Key for Code Exchange (PKCE) Flow is a widely implemented standard.

Authorization Code with PKCE Flow Overview

Recently I posted about the PKCE PowerShell Module I just made public. It contains the key piece to performing authentication to Azure AD using the Authorization Code with PKCE Flow and PowerShell. That post also details the specifics around generating a PKCE code_verifier and the associated code_challenge. Those artefacts are then used in conjunction with an Authorization Code grant flow. The process as shown in the image below is;

  1. Initiate the Authorization Code with PKCE Flow by supplying the details of the Azure AD Registered Application (client_id, tenant_id, scopes, redirect_uri, PKCE code_challenge, PKCE algorithm). This part is also interactive whereby an interactive user AuthN/AuthZ flow is processed for the registered app. This is against the OAuth2.0 authorize endpoint.
  2. Receive an Authorization Code
  3. Request a token from the OAuth2.0 token endpoint by providing the authorization code received in step 1, client_id and client_secret of the registered Azure AD App and the code_verifier for the code_challenge sent in step 1. This is essentially the client credentials flow with the additional security of Proof Key for Code Exchange
  4. Receive an access_token
  5. Access permitted Microsoft Graph scopes

Prerequisites

You will need to register an Azure AD Application as detailed in the documentation here. Record the tenant_id and application (client) id for use in the script further below.

  • use “https://localhost/” as the Redirect URI
  • add Application based permissions to the application (e.g., User.Read.All) as used in the example below.
  • generate a client secret and record the value. The example in this post uses a client secret over a certificate. To modify for a certificate see this post to retrieve the certificate for use in the flow.
  • Install the PKCE PowerShell Module
  • (optional) Install my JWTDetails PowerShell Module to inspect the access_token including the lifetime of it (which will vary between 60 & 90 minutes but average 75 minutes).

Script Overview

Ideally, I would have leveraged the fantastic MSAL.PS PowerShell module to perform this process. However as PKCE was only introduced into the MSAL .NET library with version 4.30.0 MSAL.PS has not been updated for this support.

UPDATE: 8 March 2022
MSAL.NET uses PKCE by default. 
MSAL.PS uses MSAL.NET so PKCE is automatically implemented by the library. 

The script below is an example to then perform the steps shown in the graphic above. It has been tested and validated with both Windows PowerShell (5.1) and PowerShell 7.1.x on Windows. The Get-AuthCode function performs the interactive authentication in Step 1 to get an authorization code associated with the registered application. It will initiate a PowerShell forms-based window requesting user authentication.

After receiving an authorization code an access token is requested and if the request is valid for the registered application and the associated PKCE code_verifier and code_challenge it is received.

Microsoft Graph calls to the appropriate resource(s) as specified in the scope(s) requested. Results from Microsoft Graph returned.

Update the following lines in the script for;

  • clientID <your registered AAD App>
  • tenantID <the tenant id associated with your registered AAD app>
  • clientSecret <your registered AAD App client secret>
  • replyURL if different from ‘https://localhost/’
  • scopes if different from ‘user.read.all’ and then also the Microsoft Graph Users API call in line 71

The output of the script (following user interactive authentication) as shown in the overview section above is the following. Confirmation that an authorization code was received, decode of the access token and a Microsoft Graph Users API call and result.

Microsoft Graph using the Authorization Code with PKCE Flow and PowerShell Script Output

Summary

Using my PKCE PowerShell module we can generate a PKCE code_verifier and associated code_challenge for use in PowerShell to get an Authorization Code and exchange it for an Access Token using interactive authentication before dropping to a confidential client based client credentials flow. Using the application based permissions we can then query Microsoft Graph and get a response.