The shortcut, and where my notes went wrong
The dashboard button is convenient: no redirect URI, no browser flow. My notes from the previous account said it returns a long-lived token directly and that the separate exchange step was optional. On the next setup the button returned a short-lived token. Whether Meta changed the behaviour or my earlier check was too shallow, I can't say. What I can say is that a token that looks fine is indistinguishable from a good one until you ask Meta about it.
Ask the token itself
Threads has a debug endpoint that takes the token as both the input and the credential:
GET https://graph.threads.net/debug_token?input_token=<TOKEN>&access_token=<TOKEN>
The response includes the scopes, the user id and expires_at as a Unix timestamp. Converting that timestamp is the whole test. Mine was about an hour and a half after generation.
The exchange
Meta's Threads documentation describes an exchange call that trades a short-lived user token for a long-lived one, using the th_exchange_token grant type together with the app's secret. Run it from the server, never from a browser or from a workflow that logs its inputs:
GET https://graph.threads.net/access_token?grant_type=th_exchange_token&client_secret=<APP_SECRET>&access_token=<SHORT_LIVED_TOKEN>
The response carries the long-lived token, and debug_token on it showed an expiry about 60 days out. That token went into an n8n HTTP query-auth credential and the short-lived one was discarded.
The Page token had the opposite surprise
For the Facebook Page side I assumed the token from the Page-accounts lookup was also a 60-day token. debug_token said expires_at: 0, which means it doesn't expire. Assuming 60 days would have put a pointless refresh job on the calendar. Assuming "forever" without checking would have been the more expensive mistake in the other direction.
What I do now
- Run debug_token on every token before it goes into a credential, and write the expiry date next to it.
- Schedule the refresh of a long-lived Threads token before it lapses (Meta documents a refresh call), rather than finding out on day 60 from a failed post.
- Keep the app secret out of any node that logs its parameters.
A different Threads failure, unrelated to tokens, is covered in a 500-character limit hiding behind a generic error.
n8n Automation Hub