Identity and Access Management

Microsoft Graph using MSAL with PowerShell and Certificate Authentication

Close to 3 years ago I authored this post on using PowerShell for Certificate based Azure AD Authentication using ADAL (Active Directory Authentication Library). More recently I’ve published posts on using MSAL (MicroSoft Authentication Library) with PowerShell for Application and Delegated integration with the Microsoft Graph. MSAL is well on the way to replacing ADAL. so we need to update our ADAL based integration automations to use MSAL with PowerShell and Certificate Authentication.

NOTE: Microsoft recently updated their documentation. The FAQ here states that ADAL will not be receiving any new functionality as of 30 June 2020. It’s time to ditch ADAL and use MSAL.

In this post I update my post from 3 years ago to show how to use MSAL with PowerShell and Certificate Authentication to an Azure AD Registered Application to leverage Application based API permissions. The certificate replaces the client secret during authentication in a client credentials authentication flow.

The process is very similar to the ADAL method;

  • generate a self signed certificate
  • add the certificate to the Azure AD Registered Application
  • leverage the MSAL.NET library (via the MSAL.PS PowerShell Module) to authenticate to Microsoft Graph
  • use the Access Token for Microsoft Graph queries using PowerShell

You will need the MSAL.PS PowerShell Module installed. You can do that quickly from an Administrative PowerShell 5.1+ session using the following command:

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

This post also assumes you have an existing Azure AD Registered App that you will add a certificate to. If not register one in Azure AD Blade of the Azure Portal.

Generate a Self Signed Certificate

From an Administrative PowerShell session use the following script to generate a Self Signed 10 year certificate. Update the $certPassword, $certName,  $certPath and $certFileName variables for your Certificate Name, the password that will be associated with the Certificate when we export it from the Certificate Store, and where and what the certificate file will be named. Don’t use an extension for the file name.

$certPassword = "P@SSW0rd1"
$certName = "pwsh.darrenjrobinson.com"
$certPath = "C:\Users\darrenjrobinson\Certificates\SelfSigned\"
$certFileName = "AADAppCert"

$Params = @{
   "DnsName" = @($certName)
   "Subject" = "CN=$($certName)"
   "CertStoreLocation" = "Cert:\LocalMachine\My"
   "NotAfter" = (Get-Date).AddYears(10)
   "KeyAlgorithm" = "RSA"
   "KeyLength" = "2048"
}

$myCert = $null 
$myCert = New-SelfSignedCertificate @Params
$thumbPrint = $myCert.Thumbprint

The Certificate will be created in the Local Computer Certificate Store. Using the MMC Certificates snap-in connected to the Local Computer we can locate our new Self Signed Certificate under Certificates => Personal => Certificates.

Export the Certificate

Using PowerShell we will now export our self signed certificate from the local computer certificate store and password protect it.

# Password to be set on the exported Certificate
$pwd = ConvertTo-SecureString -String $certPassword -Force -AsPlainText

# Export the Certificate
Export-PfxCertificate -cert "cert:\LocalMachine\My\$($thumbPrint)" -FilePath "$($certPath)$($certFileName).pfx" -Password $pwd

Obtain the Raw Certificate Data

From the Exported Certificate will will extract the certificate data and output it to another file in a format for upload to an Azure AD Registered App (with the .cer extension).

$x509cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate("$($certPath)$($certFileName).pfx", (ConvertTo-SecureString -String $certPassword -Force -AsPlainText))
$keyValue = [System.Convert]::ToBase64String($x509cert.GetRawCertData())
$keyValue | out-file "$($certPath)$($certFileName).cer"

Inspect the Certificate

Using my x509Details PowerShell Module we can easily inspect the Raw Certificate details to verify we have the correct certificate.

Get-X509Details $keyValue

Upload the Certificate to the Azure Registered App

From the ‘Certificates and secrets‘ menu item of your Azure AD Registered App, select ‘Upload Certificate‘, locate the exported certification on your local computer and select Add.

The Certificate will then be present on the registered Azure AD Application and valid for as an authentication secret.

Use MSAL.PS and Get-MsalToken with the Self Signed Certificate to get an Access Token

We can now use the MSAL.PS PowerShell Module with our certificate to authenticate to Microsoft Graph using our registered Azure AD Application.

Import-Module MSAL.PS
$clientID = 'yourAADRegisteredAppClientID'
$tenantID = 'yourAADTenantID'
$ClientCertificate = Get-Item "Cert:\LocalMachine\My\$($thumbPrint)"
$myAccessToken = Get-MsalToken -ClientId $clientID -TenantId $tenantID -ClientCertificate $ClientCertificate
# Inspect the Access Token using JWTDetails PowerShell Module
$myAccessToken.AccessToken | Get-JWTDetails

MSAL with PowerShell and Certificate Authentication – 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 return a page of results for Azure AD Users and find those that contain ‘darren’ in the displayName attribute.

$users = (Invoke-RestMethod -Headers @{Authorization = "Bearer $($myAccessToken.AccessToken)" } `
  -Uri "https://graph.microsoft.com/beta/users" `
  -Method Get).value
$users | Select-Object | Where-Object {$_.displayName -like "*darren*"}

Refreshing the Access Token

To obtain a new Access Token we simply use Get-MsalToken with the same options as previously and if our existing token is close to expiring the refresh token will be used to obtain a new Access and Refresh Token.

$myAccessToken = Get-MsalToken -ClientId $clientID -TenantId $tenantID -ClientCertificate $ClientCertificate

To force a refresh of our Access and Refresh Tokens we simply add the -ForceRefresh switch to the Get-MsalToken cmdlet.

$myAccessToken = Get-MsalToken -ClientId $clientID -TenantId $tenantID -ClientCertificate $ClientCertificate -ForceRefresh

Summary

Using the MSAL.PS PowerShell Module we can quickly obtain an Azure AD Access Token with Application Permissions using a Self Signed Certificate and the Client Credentials flow, and then silently refresh our Access Token leveraging the MSAL.PS Module, the MSAL.NET library and the token cache.

Darren Robinson

Bespoke learnings from a Microsoft Identity and Access Management Architect using lots of Microsoft Identity Manager, Azure Active Directory, PowerShell, SailPoint IdentityNow and Lithnet products and services.

View Comments

Recent Posts

Visualising your IP Address using PowerShell and AI

A few weeks back the Microsoft AI Tour was in Sydney Australia. There was a…

3 weeks ago

Where the heck is the PowerShell Module loading from?

If you're anything like me you always have PowerShell open, and often both PowerShell and…

4 months ago

Express Verified ID Setup

Decentralised Identity is a technology I'm passionate about and have written many posts and tools…

5 months ago

Orchestrating 1Password with PowerShell

Over two years ago I authored a PowerShell Module that enabled the automation of 1Password.…

8 months ago

Entra ID Tenant ID & Custom Domains PowerShell Module

Buried in my PowerShell Snippets Vol 4 post from 2021 is the PowerShell script and…

8 months ago

Windows Subsystem for Linux instance has terminated

Short post on how to recovery from "The Windows Subsystem for Linux instance has terminated"…

9 months ago

This website uses cookies.