powershell-jwt.psm1

Function New-JWT {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $True)]
        [string]
        $Algorithm,

        [string]
        $Type = 'JWT',

        [hashtable]
        $HeaderClaims = @{},

        [string]
        $Issuer,

        [int]
        $ExpiryTimestamp,

        [hashtable]
        $PayloadClaims = @{},

        [Parameter(Mandatory = $True)]
        [System.Byte[]]
        $SecretKey
    )

    $header = New-JwtHeader -Algorithm $Algorithm -Type $Type -ExtraClaims $HeaderClaims
    $payload = New-JwtPayload -Issuer $Issuer -ExpiryTimestamp $ExpiryTimestamp -ExtraClaims $PayloadClaims

    $headerBase64 = Convert-HashtableToJsonBase64 -Hashtable $header
    $payloadBase64 = Convert-HashtableToJsonBase64 -Hashtable $payload

    $ToBeSigned = $headerBase64 + "." + $payloadBase64
    $signature = switch -Wildcard ($Algorithm) {
        'HS???' { Get-SignatureHS -Algorithm $Algorithm -SecretKey $SecretKey -ToBeSigned $ToBeSigned }
        'RS???' { Get-SignatureRS -Algorithm $Algorithm -SecretKey $SecretKey -ToBeSigned $ToBeSigned }
        Default { Write-Error -Message ('Unsupported algorithm: ' + $Algorithm) }
    }

    $token = $ToBeSigned + "." + $signature
    $token
}

Function Confirm-JWT {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $True)]
        [ValidatePattern('^[^.]+\.[^.]+\.[^.]+$')]
        [string]
        $JWT,

        [string]
        $AcceptedAlgorithm,

        [Parameter(Mandatory = $True)]
        [System.Byte[]]
        $Key
    )

    $JwtHeaderB64,$JwtPayloadB64,$JwtSignatureB64 = $JWT -split '\.'
    $SignedData = $JwtHeaderB64 + "." + $JwtPayloadB64

    $JwtHeader = Convert-JsonBase64ToHashtable -JsonBase64 $JwtHeaderB64
    $JwtPayload = Convert-JsonBase64ToHashtable -JsonBase64 $JwtPayloadB64

    $Algorithm = $JwtHeader.alg

    $isAlgorithmAccepted = $null -eq $AcceptedAlgorithm -or $AcceptedAlgorithm -eq $Algorithm

    $isSignatureValid = switch -Wildcard ($Algorithm) {
        'HS???' { Confirm-SignatureHS -Algorithm $Algorithm -SecretKey $Key -SignedData $SignedData -Signature $JwtSignatureB64 }
        'RS???' { Confirm-SignatureRS -Algorithm $Algorithm -PublicKey $Key -SignedData $SignedData -Signature $JwtSignatureB64 }
        Default { Write-Error -Message ('Unsupported algorithm: ' + $Algorithm) }
    }

    @{
        'header' = $JwtHeader
        'payload' = $JwtPayload
        'isSignatureValid' = $isAlgorithmAccepted -and $isSignatureValid
    }
}

Function New-JwtHeader {
    param (
        [Parameter(Mandatory = $True)]
        [string]
        $Algorithm,

        [string]
        $Type = 'JWT',

        [hashtable]
        $ExtraClaims = @{}
    )

    $header = @{
        alg = $Algorithm
        typ = $Type
    } + $ExtraClaims

    $header
}

Function New-JwtPayload {
    [CmdletBinding()]
    param (
        [string]
        $Issuer,

        [int]
        $ExpiryTimestamp,

        [hashtable]
        $ExtraClaims = @{}
    )

    $payload = @{}
    if ($Issuer -ne $null) {
        $payload['iss'] = $Issuer
    }
    if ($ExpiryTimestamp -ne $null) {
        $payload['exp'] = $ExpiryTimestamp
    }

    $payload += $ExtraClaims

    $payload
}

Export-ModuleMember -Function 'New-JWT'
Export-ModuleMember -Function 'Confirm-JWT'