Skip to content

Get Threads posting credentials

Let keryx auth threads capture a token so keryx publish can post a text-and-image announcement to a Threads account (spec 0060 D15). Threads lives on the same Meta app as Instagram and Facebook but, like Instagram Login, its use case mints an app id and secret of its own; the Meta app's id and the Instagram pair are both rejected. Ten minutes.

1. Add the Threads use case

In the app dashboard: Use cases → Add use cases → Access the Threads API (the name varies slightly). Once added, open it and:

  1. Under its Settings, note the Threads app ID and Threads app secret. platforms.threads.app_id (config, non-secret) and THREADS_APP_SECRET (environment, never committed).
  2. Add the loopback redirects keryx uses for Threads. Not localhost: Threads' token endpoint refuses that hostname at the code exchange (error 191, "Invalid redirect_uri") even though the consent page accepts it, so keryx uses keryx.localhost, which every current browser resolves to 127.0.0.1 without a hosts entry: https://keryx.localhost:3764/ … https://keryx.localhost:3769/. A project can name any host it points at the loopback instead with platforms.threads.redirect_host.
  3. Under its Permissions, make threads_basic and threads_content_publish available.
  4. Under Roles, add the Threads account as a Threads Tester while the app is in development, and accept the invitation in the Threads app (Settings → Account → Website permissions → Invites).

2. Sign keryx in

keryx auth threads

It opens the consent window (or prints the URL), captures the code on the https loopback, swaps it for a short-lived token, that for a 60-day one, and stores the token (keychain, else the accounts file) with its expiry and platforms.threads.{user_id,enabled,redirect_uri}. In CI, THREADS_ACCESS_TOKEN in the environment is the token.

3. What a post looks like there

  • Text, held to 500 characters. Threads has no in-text hashtags, only one topic tag per post, so the first hashtag is sent as the topic and none go in the text (a #tag in the text would become the topic and leave a bare word behind).
  • Without an image: a text post with the link as a link attachment, which Threads renders as a card.
  • With an image: an image post. Threads fetches the JPEG or PNG (under 8 MB) from its public URL, so the article must be live and announce.public_base_url set. A link attachment is not allowed with media, so the link is written into the text. keryx counts the link against the 500 either way, so an approval never turns into a refusal at send time.
  • Alt text is sent when the post has it. No video.

Refresh

The 60-day token refreshes in place: keryx auth refresh exchanges it once it is within 20 days of expiry and records the new expiry; a token under 24 hours old cannot be refreshed, which is why it waits.