PowerShell and JSON Web Token Handler

Yesterday, I've been trying to to get Google Admin SDK Directory API (which replaces Google Apps Provisioning API) to work with PowerShell and JSON Web Token (JWT) Handler.

Unfortunately, JWT Handler did not like certificate generated by Google APIs console. I kept receiving the following error:

Exception calling "WriteToken" with "1" argument(s): "Jwt10530: The 'System.IdentityModel.Tokens.X509AsymmetricSecurityKey' for signing cannot be smaller than '2048' bits. Parameter name: key.KeySize Actual value was 1024."

Google APIs console generates a private key of 1024 bits and JWT Handler requires the private key to be at least 2048 bits. The only way I saw to get around this was not to use JWT Handler when connecting to Google's new APIs. (A future post will demonstrate this.)

If you are working with JWT-enabled web services that support private keys 2048 bits and greater, then you can use the PowerShell code below.

Tested using Windows 8, PowerShell 3.0, .NET Framework 4.5, JSON Web Token Handler For the Microsoft .Net Framework 4.5 1.0, Win32 OpenSSL 1.0.1eNuGet Command-Line Utility 2.7.

  1. Download NuGet Command-Line Utility.
  2. Install the JWT Handler:
    nuget.exe Install System.IdentityModel.Tokens.Jwt
  3. Generate test certificate:
    set OPENSSL_CONF=C:\OpenSSL-Win64\bin\openssl.cfg

    C:\OpenSSL-Win64\bin\openssl.exe req -x509 -nodes -days 365 -newkey rsa:2048 -keyout D:\myapp.key -out D:\myapp.crt

    C:\OpenSSL-Win64\bin\openssl.exe pkcs12 -export -in D:\myapp.crt -inkey D:\myapp.key -out D:\myapp.pfx
  1. Add-Type -Path 'D:\Downloads\System.IdentityModel.Tokens.Jwt.dll'  
  2.   
  3. function Jwt-CreateToken {  
  4.     Param(  
  5.         [string] $issuer,  
  6.         [string] $audience,  
  7.         [string] $certificate,  
  8.         [string] $certificatePassword,  
  9.         [System.Collections.Generic.List[System.Security.Claims.Claim]] $claims = $null  
  10.     )  
  11.   
  12.     # Make our token valid from now to the next hour.  
  13.     $createDate = Get-Date  
  14.     $lifetime = New-Object System.IdentityModel.Protocols.WSTrust.Lifetime($createDate$createDate.AddHours(1))  
  15.   
  16.     # Load our certificate.  
  17.     $signingCertificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certificate$certificatePassword"Export")  
  18.     $signingCredentials = New-Object System.IdentityModel.Tokens.X509SigningCredentials($signingCertificate)  
  19.   
  20.     # Create our JSON web token.  
  21.     $token = New-Object System.IdentityModel.Tokens.JwtSecurityToken($issuer$audience$claims$lifetime$signingCredentials)  
  22.     return (New-Object System.IdentityModel.Tokens.JwtSecurityTokenHandler).WriteToken($token)  
  23. }  
  24.   
  25. # Example creating/reading a token  
  26. $claims = New-Object System.Collections.Generic.List[System.Security.Claims.Claim]  
  27. $claims.Add((New-Object System.Security.Claims.Claim("scope""https://www.contoso.com/api/users")))  
  28. $encToken = Jwt-CreateToken -issuer "20130829-2236@developer.contoso.com" -audience "https://accounts.contoso.com/oauth2/token" -certificate "D:\myapp.pfx" -certificatePassword "notasecret" -claims $claims  
  29. Write-Host $encToken  
  30.   
  31. $decToken = (New-Object System.IdentityModel.Tokens.JwtSecurityTokenHandler).ReadToken($encToken)  
  32. $decToken | Format-List