TryGhost / TryGhost/ActivityPub

Let a site owner read their own interactions without a 5-minute session token

Open
#2,168 0 comments 0 reactions 0 assignees View on GitHub

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.ts verifies a JWT signed by Ghost (RS256) against the site's /ghost/.well-known/jwks.json, and returns 403 ROLE_MISSING otherwise.
  • That token comes from GET /ghost/api/admin/identities/, whose handler reads frame.user — a staff user, not an integration.
  • The fixtures grant identity: read to the Administrator role only. A Custom Integration authenticates as an integration, so it can never obtain one.
  • identity-token-service.ts signs it with expiresIn: '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:

  1. Grant identity: read to the Admin Integration role, so an Admin API key can mint an identity token for the ActivityPub service. Smallest change, reuses everything that exists.
  2. Accept Admin API key authentication directly on /.ghost/activitypub/v1/*, alongside the identity token.
  3. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.