Documentation › Integrator guides
Mint and manage API tokens
The full lifecycle for personal access tokens — mint, rotate, revoke. Operational reference for someone building or maintaining an integration against the Steward API.
Background: Using the Steward API covers the why-and-when of the API; this guide covers the how-to-manage-credentials.
Where to mint
The API tokens surface lives at:
/app/account → API tokens
You must be signed in via a browser session (GitHub OAuth
or OpenID Connect) to mint a token. A token can't mint
another token — calling CreateApiToken with a Bearer token
in the Authorization header returns:
{
"error": {
"code": "PERMISSION_DENIED",
"message": "API tokens can only be created from a signed-in browser session, not from another API token."
}
}
This is the privilege-escalation backstop: a leaked low-scope token can't bootstrap a higher-scope one.
Mint your first token
Sign in at https://steward-dev.ai.
Navigate to
/app/account→ API tokens.Click Mint a token.
Name — a free-text label for your tracking. Max 100 characters. Examples:
ci-build-poll,prod-status-dashboard,local-dev-alice. Use names that make the revoke decision obvious six months later.Scopes — pick at least one. See Scopes table in the API concept doc. Pick narrowly; widening later means revoking + reminting.
Click Mint. Steward returns the plaintext value:
stwd_pat_<long random string>Copy the plaintext now. The server stores only the SHA-256 hash + the display prefix. There is no "show plaintext again" button. If you close the page without copying, you mint a new one.
Store the plaintext securely
The plaintext is a credential. Treat it like a password:
- CI: write it to your CI provider's secrets manager (GitHub Actions secrets, GitLab CI variables, CircleCI environment variables). Reference it as an env var in your job; never echo it.
- Local development: keep it in a
.envfile that's in.gitignore, or in your shell's keychain (security add-generic-passwordon macOS,secret-toolon Linux with libsecret). - Shared scripts: don't commit the token to a repo. Even in a private repo, a token in the git history is exposed to anyone with read access.
Steward's audit log records api_token.minted with name +
scopes — but not the plaintext (the server never had it
after the response was sent). If the plaintext leaks, the
audit log can't tell you who took it.
Use it
Send the plaintext on every API call as a Bearer token:
curl -X POST https://steward-dev.ai/api/steward.api.v1.MeService/Get \
-H "Authorization: Bearer stwd_pat_..." \
-H "Content-Type: application/json" \
-d '{}'
The first call lands an api_token.used audit event. Steward
dedups this event to first-call-per-hour-per-token, so a
CI script polling once per minute doesn't drown the log.
Verify the token works
A quick way to confirm the token is good + the scopes are right:
curl -X POST https://steward-dev.ai/api/steward.api.v1.MeService/Get \
-H "Authorization: Bearer $STEWARD_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'
The response includes your login + permissions map.
Status 200 means the token authenticates; the body shows the
identity it acts as.
If the response is 401 Unauthorized, the token is missing,
malformed, revoked, or unknown — re-check the env var
substitution. If it's 200 but the permissions map looks
sparser than expected, the scopes might not match what you
think you minted (see "List your tokens" below).
List your tokens
/app/account → API tokens shows every active token:
| Column | Meaning |
|---|---|
| Name | The label you set at mint. |
| Prefix | First few characters of the plaintext (the part Steward stores for display). Useful for matching against a token in your CI secrets manager. |
| Scopes | The scopes the token carries. Picked at mint, immutable. |
| Last used | Timestamp of the most recent call (via the audit event). |
| Created | Mint timestamp. |
| Revoke | The revoke button. |
The list is the source of truth for "what credentials do my integrations hold." Audit it periodically — every six months is a reasonable cadence — and revoke anything you no longer recognise.
Rotate
There's no scope-edit RPC by design. To rotate (change scopes, change name, replace a stale token):
- Mint the new token with the desired scopes + a name
that distinguishes it from the old one
(e.g.,
ci-build-poll-2026q3). - Update your secrets manager to point at the new plaintext.
- Deploy your integration with the new credential.
- Verify it works — let it run for a poll cycle.
- Revoke the old token.
The reason for the mint-first / revoke-last order is to keep the integration up during the transition. Revoking first breaks every running job for the rotation window.
For automated rotation: there's no API for self-rotation (see "tokens can't mint tokens" above). Automated rotation would need to drive the browser flow — typically via a human-driven cron, or by accepting the manual touchpoint every N months.
Revoke
From /app/account → API tokens → Revoke on the
row:
- Confirm the revoke modal.
- Steward writes the
api_token.revokedaudit event immediately. - The token is rejected on the next API call — typically within seconds, since the auth check is the first thing on every request.
Revocation is immediate and irreversible. There's no "undo"; if you revoke by mistake, mint a fresh token.
When to revoke
- Leak suspected — even partial leak (a token printed to a log, a debugging session that captured it, a compromised developer machine). The bar for revoking is low; the cost of reminting is low.
- Integration retired — when you remove the CI workflow or shut down the dashboard that used the token, revoke the credential.
- Six-month sweep — a periodic audit. Tokens you can't explain are tokens that should go.
What happens on revoke
- The audit row lands (
api_token.revokedwithtarget_id = api_token.id). - The
api_tokensrow stays in the DB withrevoked_at = now()— the row is kept for the attribution trail, butlast_used_atstops updating and the token's hash no longer authenticates. - Subsequent calls with the revoked plaintext get
401 Unauthorized.
Account deletion cascades
When you delete your Steward account (Your account + your data), every token you minted is hard-deleted as part of the tombstone flow. The deletion summary surfaces the count:
Account deleted.
API tokens deleted: 4
...
No manual cleanup needed for tokens before nuking the account.
What's next
- Using the Steward API — the concept doc covering when to reach for the API.
/docs/api— the per-RPC reference for the four shipped read endpoints.- Integrate Steward with CI — worked example of using a token from a CI job (forthcoming in slice 2).
- Handle errors + rate limits — the error envelope catalogue + backoff strategy (forthcoming in slice 3).
Steward