Decode JWT access and id tokens via PowerShell

JSON web tokens or JWTs are commonly used in modern websites and apps and Azure AD/Office 365 is no exception in this regard. Both the OAuth 2.0 and the OIDC protocols used by Azure AD issue some type of a JWT token as part of the authentication and authorization processes. Thus, knowing what a JWT token is and what’s contained inside it can help you with troubleshooting access issues.

There’s a lot of information about JWT tokens available online, including web-based decoder tools such as JWT.ms and JWT.io. Then again, with PowerShell we have the full strength of .NET at your fingertips, so why not simply do the decoding in the console?

So here’s a simple function that will decode Access or ID tokens issued by Azure AD. You can get the token via one of the methods exposed in the ADAL libraries, from the TokenCache on an already connected PowerShell session, via web request, by copying it from the browser URL and so on. Simply provide it as a parameter for the function.

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]
    #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-Verbose "Base64 encoded (padded) header:"
    Write-Verbose $tokenheader
    #Convert from Base64 encoded string to PSObject all at once
    Write-Verbose "Decoded header:"
    [System.Text.Encoding]::ASCII.GetString([system.convert]::FromBase64String($tokenheader)) | ConvertFrom-Json | fl | Out-Default

    #Payload
    $tokenPayload = $token.Split(".")[1]
    #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-Verbose "Base64 encoded (padded) payoad:"
    Write-Verbose $tokenPayload
    #Convert to Byte array
    $tokenByteArray = [System.Convert]::FromBase64String($tokenPayload)
    #Convert to string array
    $tokenArray = [System.Text.Encoding]::ASCII.GetString($tokenByteArray)
    Write-Verbose "Decoded array in JSON format:"
    Write-Verbose $tokenArray
    #Convert from JSON to PSObject
    $tokobj = $tokenArray | ConvertFrom-Json
    Write-Verbose "Decoded Payload:"
   
    return $tokobj
}

Some basic checks are put in place, but this is in no means a complete solution that can handle all types of tokens. In addition, no attempt is made to verify the token signature.

Here’s an example of running the function:

You can also use the –Verbose switch to expose the steps taken to decode the token:

The function will return the token payload as a PSObject, which you can then reuse as needed:

$token = Parse-JWTtoken $test

Have fun 🙂

This entry was posted in Azure AD, Office 365, PowerShell. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *