Repository navigation
Sign Ghost Admin API tokens per request from the Admin API key - #1615
Merged
Merged
Conversation
The Ghost adapter asked users for a JWT they generated by hand. Ghost expires those after 5 minutes, so every Ghost connector stopped working minutes after setup. HMAC signatures can now carry a jwt block: the engine signs a fresh HS256 token per request (kid from the id:secret key, hex-decoded secret, aud /admin/) and sends Authorization: Ghost. The adapter now asks for GHOST_ADMIN_API_KEY with a format check and probes an authenticated endpoint.
helpcodeai
enabled auto-merge (squash)
November 9, 2026 17:23
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
The Ghost adapter asked for
GHOST_ADMIN_JWT, a token the user had to generate by hand. Ghost refuses Admin API tokens older than 5 minutes, so every Ghost connector stopped working a few minutes after setup. A Cloud customer hit it today: three calls worked, the next one failed withINVALID_JWT, he pasted a new token, and then he asked how to cancel.authType: "HMAC"signatures can now carry ajwtblock (hmac-jwt.util.ts). The engine signs a new HS256/384/512 token for every request and every retry and sends it in a configurable header. The connector stores the key only.kid= the id half of theid:secretAdmin API key, signed with the hex-decoded secret,aud: "/admin/", 5-minute lifetime,Authorization: Ghost <token>.GHOST_ADMIN_API_KEY. It has a format check that turns away a Content API key, a URL pattern that requires/ghost/api/admin, verify hints for 401/403/404, and a probe onghost_list_posts:/site/answers without authentication, so it passed any key.docs/tool-definition.mddocuments thejwtblock.Installed connectors
Resync doesn't touch
authType/authConfig, so the two installed Ghost connectors on Cloud need their auth moved to the new config after deploy (targeted update), and their owners need to paste the Admin API key. The oldGHOST_ADMIN_JWTnever stayed valid anyway.Cloud and self-hosted
Same in both: the engine change and the adapter JSON are shared. No schema change and no new auth type: it is an option on the existing
HMACtype.Tests
Working directory
packages/backend, afternpx prisma generate:npx jest --maxWorkers=4 src/connectors/engines/hmac-jwt.util.spec.ts src/connectors/engines/rest.engine.hmac-jwt.spec.ts src/adapters/intl/ghost.live.spec.ts src/connectors/engines/rest.engine.hmac-pin.spec.ts: 26 passed, 1 skipped (live, gated byRUN_GHOST_LIVE=1).npx jest --maxWorkers=4(full suite): 1062 suites passed. Two suites failed:rest.engine.shopee.spec.ts: a list of all HMAC adapters didn't include Ghost. Fixed in this PR to leave JWT-signed adapters out; 8 of 8 pass now.auth/jwt-or-management-key.guard.spec.ts: it needs a live PostgreSQL, which my local worktree didn't have. Environment, not this change; CI runs it with its database.npm run lint: 0 errors (11 warnings, all in files this PR doesn't touch).npx tsc --noEmit -p tsconfig.json: clean.node scripts/validate-adapters.mjs --warn: the Ghost warnings are the existing short tool descriptions, none new.node scripts/regenerate-catalog.mjs: no catalog diff.Not tested against a real Ghost site (no Ghost instance at hand). The token format is checked with
jsonwebtoken.verifyagainst Ghost's documented claims.