DEV Community

Jesse Houwing for Xebia Microsoft Services

Posted on • Originally published at jessehouwing.net on

Update Ghost blogs and pages with PowerShell

Update Ghost blogs and pages with PowerShell

The samples provided by Ghost are in JavaScript, Curl and Python, all languages I'm not fluent in, so I set out to do the same from PowerShell or C#.

The hardest part turned out to be the code to create the correct JWT token to authenticate against Ghost. In their admin panel they provide a set of tokens, but it turns out you can't just use these tokens as-is.

Update Ghost blogs and pages with PowerShell
API Key provided by Ghost

The API key essentially makes up 2 parts:

  1. The Key Identifier, that's the part up to the :
  2. The Secret, that's the part after the :

In order to use this key, we first have to split it into its two parts:

$parts = $adminApiKey -split ":"
$id = $parts[0]
$secret = $parts[1]
Enter fullscreen mode Exit fullscreen mode

We then need to construct a JWT token from this key. I relied on the Posh-JWT package for that part:

Install-Module -Name JWT -force

$key = [Convert]::FromHexString($secret) # only works in PowerShell Core

$jwttoken = New-Jwt `
  -Header (
    @{
      "alg" = "HS256"
      "kid" = $id
      "typ" = "JWT"
    } | ConvertTo-Json
  ) `
  -PayloadJson (
    @{
      "exp" = ([DateTimeOffset](Get-Date).AddMinutes(2)).ToUnixTimeSeconds()
      "iat" = ([DateTimeOffset](Get-Date)).ToUnixTimeSeconds()
      "aud" = "/admin/"
    } | ConvertTo-Json) 
  -Secret $key
Enter fullscreen mode Exit fullscreen mode

With this token, you can then invoke the Ghost API.

$headers = @{
  Authorization = "Ghost $jwttoken"
  "Content-Type" = "application/json"
}

$baseUri = "https://scrumbug.ghost.io/ghost/api"

$result = Invoke-RestMethod `
  -Uri "$baseUri/admin/pages/" `
  -Method GET `
  -Headers $headers     
Enter fullscreen mode Exit fullscreen mode

As I said, I used this code to automatically sync my Scrum.org classes to this blog. You can find the (private) Ghost update GitHub Action here. To keep my secrets secure I added a couple of extra lines of code to register my secrets with the runner:

Write-Output "::add-mask::$id"
...
Write-Output "::add-mask::$secret"
...
Write-Output "::add-mask::$key"
...
Write-Output "::add-mask::$jwttoken"
Enter fullscreen mode Exit fullscreen mode

Make sure to always register your secrets every time they change their shape or representation to prevent your secrets from leaking into the GitHub Action logs.

End result? My classes are automatically updated 🎉:

Update Ghost blogs and pages with PowerShell
Github actions workflow runs successfully

Top comments (0)