This post will show you how to authenticate for the client credentials flow in PowerShell with MSAL.Net using the .pfx file for the certificate authentication instead of loading the certificate from the certificate store. This post is in part based on this: Using PowerShell to Configure a signing certificate for a SAML-based SSO enterprise application Also, special thanks to my team members Bac Hoang and Will Fiddes for assisting with this sample. I am assuming that you already know the proper steps to create a self signed certificate and also you’re familiar with the client credentials flow. Please note that the public key cer file of the same certificate (of which the private key is used in this post) should be configured on the same app registration. Please refer to this blog post for the requirements.

Reference

Methods in this powershell script

  • Load-MSAL – ensures that the proper version of MSAL is installed for the version of PowerShell you’re using.
  • GetX509Certificate_FromPfx – this will return the certificate from the .Pfx file. You will need the full path to the .pfx file and the password for the pfx.
  • Get-GraphAccessTokenFromMSAL – This will Authenticate and retrieve an access token for the graph endpoint.
$ClientID           = "{client_id}"
$loginURL           = "https://login.microsoftonline.com"
$tenantdomain       = "{tenant_id}" 
$CertPassWord       = "{password_for_cert}"
$certPath           = "C:\temp\Certs\testCert_01.pfx"

[string[]] $Scopes  = "https://graph.microsoft.com/.default"

Function Load-MSAL {
    if ($PSVersionTable.PSVersion.Major -gt 5)
    { 
        $core = $true
        $foldername =  "netcoreapp2.1"
    }
    else
    { 
        $core = $false
        $foldername = "net45"
    }

    # Download MSAL.Net module to a local folder if it does not exist there
    if ( ! (Get-ChildItem $HOME/MSAL/lib/Microsoft.Identity.Client.* -erroraction ignore) ) {
        install-package -Source nuget.org -ProviderName nuget -SkipDependencies Microsoft.Identity.Client -Destination $HOME/MSAL/lib -force -forcebootstrap | out-null
    }
  
    # Load the MSAL assembly -- needed once per PowerShell session
    [System.Reflection.Assembly]::LoadFrom((Get-ChildItem $HOME/MSAL/lib/Microsoft.Identity.Client.*/lib/$foldername/Microsoft.Identity.Client.dll).fullname) | out-null
  }
 
Function Get-GraphAccessTokenFromMSAL {

    Load-MSAL

    $global:app = $null

    $x509cert = [System.Security.Cryptography.X509Certificates.X509Certificate2] (GetX509Certificate_FromPfx -CertificatePath $certPath -CertificatePassword $CertPassWord)
    write-host "Cert = {$x509cert}"

    $ClientApplicationBuilder = [Microsoft.Identity.Client.ConfidentialClientApplicationBuilder]::Create($ClientID)
        [void]$ClientApplicationBuilder.WithAuthority($("$loginURL/$tenantdomain"))
        [void]$ClientApplicationBuilder.WithCertificate($x509cert)
    $global:app = $ClientApplicationBuilder.Build()

    [Microsoft.Identity.Client.AuthenticationResult] $authResult  = $null
    $AquireTokenParameters = $global:app.AcquireTokenForClient($Scopes)
    try {
        $authResult = $AquireTokenParameters.ExecuteAsync().GetAwaiter().GetResult()
    }
    catch {
        $ErrorMessage = $_.Exception.Message
        Write-Host $ErrorMessage
    }
    
    return $authResult
}

function GetX509Certificate_FromPfx($CertificatePath, $CertificatePassword){
    #write-host "Path: '$CertificatePath'"
   
    if(![System.IO.Path]::IsPathRooted($CertificatePath))
    {
        $LocalPath = Get-Location
        $CertificatePath = "$LocalPath\$CertificatePath"
    }

    #Write-Host "Looking for '$CertificatePath'"

    $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($CertificatePath, $CertificatePassword)
    
    Return $certificate
}

$myvar = Get-GraphAccessTokenFromMSAL
Write-Host "Access Token: " $myvar.AccessToken

Summary

Loading the certificate from a .pfx file in PowerShell can make it easier for an admin to manage certificates without having to install the certificate in the certificate store. However, this should not be done on a client machine as the user could potentially discover the file and also the password for it, as well as the method to authenticate. The client credentials flow is only intended to be ran in a back-end service to service type of scenario where only admins have access to the machine.

0 0 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments