Credential Prefixes
Every Trench credential carries a prefix, so you can assert on the shape of a value before storing it.The
Authorization header is checked against the trench_at_ prefix before any database lookup happens. Sending a refresh token where an access token belongs therefore fails as 401 invalid_token rather than as an expiry or scope error.Lifetimes
Because each refresh issues a new 60-day token, an actively used connection never lapses, and your users are not asked to reconnect on a schedule.
Storing Tokens
Store the pair against your own user record.Exchanging the Code
Exchange the code from your backend, authenticating with HTTP Basic. Your API key should never reach a browser.Response
client_id and client_secret form fields if Basic auth is awkward in your HTTP client. Responses are returned with cache-control: no-store.
The redirect_uri must match the one stored with the code, and the code_verifier must hash to the code_challenge you sent. Only S256 is accepted, and the verifier must be 43 to 128 characters of [A-Za-z0-9_-].
Refreshing
cURL
- Refresh lazily, on a
401or when your stored expiry has passed, rather than on a timer. - Never refresh concurrently for the same user. Two refreshes of the same token at the same instant count as reuse, so one wins and the connection is revoked. If several of your workers can refresh the same user, take a lock or funnel refreshes through one place. The same applies to exchanging an authorization code, which should happen once, from one process.
- Never retry a
401in a loop. Refresh once, and if that fails, send the user back through authorization.
Only the refresh token rotates. The previous access token is not revoked and remains valid until its own 30-minute expiry, so for a short window both tokens work. This is convenient for requests already in flight during a refresh, but it does mean refreshing is not a way to cut off a leaked access token. To do that, revoke it explicitly.
Tokens and Your API Key
Every token records the API key that minted it. A refresh rebinds the new pair to whichever key you present, so an app that has rotated ends up with tokens tied to the key it still holds rather than the original.Revoking
cURL
To disconnect a user properly, send the refresh token. Sending the access token only forces an early refresh. Revocation returns
200 with an empty body in either case, including for tokens that were already dead.
Users can also disconnect your app from their Trench settings, Trench can suspend an app, and revoking an API key ends every connection made through it. All three take effect on the next request and surface as 401 invalid_token.
Every authentication failure returns the same
401 invalid_token with no distinguishing detail, so expired, revoked, malformed, unknown, and suspended-client cases all look identical from the outside. Since you cannot branch on the reason, we recommend refreshing once and treating a second failure as a lost connection.Checking the Connection
cURL
walletSolana and twitterHandle may be null. The scopes array reflects what the token can actually do, which may differ from what you requested at authorize time, so we recommend treating it as the source of truth.
A value of
tradingEnabled: false means the user has not delegated their wallet for 1-click trading. Trades and governance writes will fail with delegation_missing until they do, so send them back through the authorize flow.