Microsoft Graph using MSAL with PowerShell and Delegated Permissions

In October last year I authored this post that provided a getting started guide to using MSAL with PowerShell. That post also hinted at future posts expanding on additional functionality. Finally, I’m delivering on that with this post that will dive into using MSAL with PowerShell and delegated permissions. See this post for using MSAL with PowerShell and Certificate base authentication. Most recently I’ve also primarily been using PowerShell (7.x) over the earlier PowerShell Desktop (5.x) / Windows PowerShell version. The details in this post have been successfully validated with both PowerShell and Windows PowerShell.

Delegated permissions in Azure AD requires authorization from the consumer of the registered Azure AD Application versus Application permissions assigned to a registered Azure AD Application. Delegated permissions are often required when an application is acting on behalf of a user or as in the case that prompted this blog post, a specific Graph API only supports delegated permissions.

The particular API in question (as of 8 July 2020) is the Beta version of the Azure AD Authentication Methods API. What that documentation link doesn’t say, is that the Authentication Methods API only supports Delegated Permissions. With some digging that can be found in the GitHub Repo version of the documentation here. Why is this confusing? Because on the Registered Apps Blade in Azure AD you have the option to assign Application level permissions for the Authentication Methods API as shown in the screenshot below. The option is presented, but not currently implemented.

Keep in mind this API is currently Beta and hopefully by the time you’re reading this later in 2020+ App level permissions will be available, and the API will be out of Beta.

Azure AD Registered Application Application Permissions UserAuthenticationMethod

MSAL with PowerShell and Delegated Permissions

Here then is the quick start guide to again using the fantastic MSAL.PS PowerShell module against an Azure AD Registered Application configured with Delegated Permissions. Since my previous post on using MSAL.PS, the module has been updated numerous times to keep current with releases of the MSAL Authentication Libraries.

If you aren’t already using it, install it from the PowerShell Gallery from an administrative PowerShell session:

Install-Module -name MSAL.PS -Force -AcceptLicense

Obtaining an Access Token

From your Azure AD Registered Application that contains Delegated Permissions to which you have Admin Consented (if you are using it on tenant wide resources),  record your TenantID and AppID. Using those with MSAL.PS we can initiate a Device Code Authentication Flow and receive an Access Token for our API calls.

The following example with your substituted ClientID and TenantID (and assuming your registered app has a reply URL configured of https://localhost) will prompt you to navigate to https://microsoft.com/devicelogin

NOTE: This part of the process is only required once in order to authorize delegated access to the Registered App and receive the initial Access Token. 

Import-Module MSAL.PS
$clientID = "myClientID"
$tenantID = "myTenantID"
$myAccessToken = Get-MsalToken -DeviceCode -ClientId $clientID -TenantId $tenantID -RedirectUri "https://localhost"

Device Code Auth Flow Authentication

Enter the code provided with the URL link

Enter Device Code for Authentication

Provide your Username and Password and MFA (if required)  and your JWT Token will be returned to the $myAccessToken variable.

Using my JWTDetails PowerShell Module we can investigate the Access Token.

Import-Module JWTDetails
$myAccessToken.AccessToken | Get-JWTDetails

JWT Access Token from Device Code Auth

Obtaining a new Access Token using the Refresh Token

The MSAL.NET library which the MSAL.PS Module leverages (via Microsoft.Identity.Client.dll) doesn’t reveal the Refresh Token. If you look at $myAccessToken you will see the Access Token and IdToken but no RefreshToken.

Access & ID Token Only

However, whilst you can’t see the Refresh Token the MSAL cache has the refresh token and it can be used by MSAL.PS to SILENTLY obtain a new Access Token. And the MSAL.PS Module handles that for you, if you use the following options to obtain a new Access Token:

$myAccessToken = Get-MsalToken -ClientId $clientID -TenantId $tenantId -Silent -RedirectUri "https://localhost"

You will notice we don’t need to use the DeviceCode flow now and we can replace it with ‘-Silent’. The Access Token will only be refreshed if it is close to expiry.

If you want to force a refresh to obtain a new Access Token use the ‘-ForceRefresh’ option:

$myAccessToken = Get-MsalToken -ClientId $clientID -TenantId $tenantId -Silent -RedirectUri "https://localhost" -ForceRefresh

Using the Access Token

We can simply use our Access Token in the header of an Invoke-RestMethod request to the Microsoft Graph API as shown below to query the Authentication Methods for the current authorized user.

$myAuthMethods = (Invoke-RestMethod -Headers @{Authorization = "Bearer $($myAccessToken.AccessToken)" } `
   -Uri "https://graph.microsoft.com/beta/me/authentication/methods" `
   -Method Get).value
$myAuthMethods

The screenshot below shows the query and the returned user Authentication Methods as returned from the Microsoft Graph API.

My Azure AD Authentication Methods via Graph API using MSAL and Delegated Authentication

Summary

Using the MSAL.PS PowerShell Module we can quickly obtain an Azure AD Access Token with Delegated Permissions using the Interactive Device Code flow, and then silently refresh our Access Token leveraging the MSAL.PS Module, the MSAL.NET library and the token cache.