Private/Parse-JwtToken.ps1

<#
.SYNOPSIS
Decode a JWT token and return the payload as a PSObject.
 
.DESCRIPTION
Splits a JWT token string, Base64-decodes the payload segment (with padding correction), and converts the JSON payload to a PSObject. Only works with access and ID tokens; refresh tokens are not supported.
 
.PARAMETER token
The JWT token string to decode.
 
.EXAMPLE
PS> Parse-JwtToken -token "eyJhbGciOi..."
Returns the decoded token payload as a PSObject with claims like exp, iss, sub, etc.
#>

function Parse-JwtToken {
    [CmdletBinding()]
    param([Parameter(Mandatory=$true)][string]$token)
 
    #Validate as per https://tools.ietf.org/html/rfc7519
    #Access and ID tokens are fine, Refresh tokens will not work
    if (!$token.Contains(".") -or !$token.StartsWith("eyJ")) { Write-Error "Invalid token" -ErrorAction Stop }
 
    #Header
    $tokenheader = $token.Split(".")[0].Replace('-', '+').Replace('_', '/')
    #Fix padding as needed, keep adding "=" until string length modulus 4 reaches 0
    while ($tokenheader.Length % 4) { Write-Verbose "Invalid length for a Base-64 char array or string, adding ="; $tokenheader += "=" }
    Write-Debug "Base64 encoded (padded) header: $tokenheader"
    #Convert from Base64 encoded string to PSObject all at once
    Write-Debug "Decoded header: $([System.Text.Encoding]::ASCII.GetString([system.convert]::FromBase64String($tokenheader)) | ConvertFrom-Json)"
 
    #Payload
    $tokenPayload = $token.Split(".")[1].Replace('-', '+').Replace('_', '/')
    #Fix padding as needed, keep adding "=" until string length modulus 4 reaches 0
    while ($tokenPayload.Length % 4) { Write-Verbose "Invalid length for a Base-64 char array or string, adding ="; $tokenPayload += "=" }
    Write-Debug "Base64 encoded (padded) payoad: $tokenPayload"
    #Convert to Byte array
    $tokenByteArray = [System.Convert]::FromBase64String($tokenPayload)
    #Convert to string array
    $tokenArray = [System.Text.Encoding]::ASCII.GetString($tokenByteArray)
    Write-Debug "Decoded array in JSON format: $tokenArray"
    #Convert from JSON to PSObject
    $tokobj = $tokenArray | ConvertFrom-Json    
    return $tokobj
}