TryGhost / TryGhost/ActivityPub
Let a site owner read their own interactions without a 5-minute session token
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 237
- Forks
- 35
- Avg merge
- 1d 16h
- Merged PRs (30d)
- 60
Description
What I'm trying to do
Keep a durable, local record of what my published notes actually produced — who replied, and what they said — so that months later I can tell which kinds of posts got taken up and which fell flat.
I already do this for Bluesky through its public API. For my own Ghost site's fediverse presence, the outbox is public and gives me what I published and when, which is genuinely useful. But the replies are only reachable through /.ghost/activitypub/v1/notifications, and that endpoint is effectively closed to automation.
Why an Admin API key doesn't work today
I traced this through the code rather than guessing:
role-guard.tsverifies a JWT signed by Ghost (RS256) against the site's/ghost/.well-known/jwks.json, and returns403 ROLE_MISSINGotherwise.- That token comes from
GET /ghost/api/admin/identities/, whose handler readsframe.user— a staff user, not an integration. - The fixtures grant
identity: readto theAdministratorrole only. A Custom Integration authenticates as an integration, so it can never obtain one. identity-token-service.tssigns it withexpiresIn: '5m'.
So the only way to read my own interactions programmatically is to log into Ghost Admin in a browser, copy a token out of a session, and use it within five minutes. That rules out any scheduled or scripted use.
What I'd like
Any one of these would solve it — listed from least to most invasive:
- Grant
identity: readto the Admin Integration role, so an Admin API key can mint an identity token for the ActivityPub service. Smallest change, reuses everything that exists. - Accept Admin API key authentication directly on
/.ghost/activitypub/v1/*, alongside the identity token. - Expose the interactions through the Admin API proper, e.g.
GET /ghost/api/admin/activitypub/notifications/, so it sits with the rest of the content API and inherits its auth.
Why this matters beyond my case
Ghost 6 pairs the social web with native analytics, and the analytics are queryable. Interactions aren't — which means the one thing that says whether a post landed is the one thing you can't take with you. For anyone keeping an editorial record outside Ghost, or migrating one, that's the gap.
I'm not asking for interactions to be public: they arrive in an authenticated inbox and that's correct. Only for the site owner to be able to read their own, with the credential they already use for everything else.
I'm on Ghost(Pro), so I can't run a patched instance — but I'm happy to try any of this against my own site as soon as it lands there, and to report back with what a real editorial use looks like.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading role-guard.ts, identity-token-service.ts, the GET /ghost/api/admin/identities/ handler, and the notifications endpoint; inspect the Administrator and Custom Integration fixtures to understand existing authorization. Decide which of the three authentication or API directions is accepted, then add coverage showing that an owner can read their own interactions without weakening access controls.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, authentication, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100