Personal Access Tokens
A Personal Access Token (PAT) is a credential you mint from the dashboard for the TxNod MCP server and developer tooling. PATs are scoped, expiring, and revocable; the secret is shown exactly once at creation. This page covers the two decisions you make every time you mint one.
Scopes
PAT scopes are read/write permissions over the API surface. The nine scopes are:
| Scope | What it allows |
|---|---|
invoices:read | Read invoices |
invoices:write | Create, cancel invoices |
projects:read | Read projects |
projects:write | Modify projects |
transactions:read | Read payments |
webhooks:read | View events |
webhooks:manage | Retry, resend |
admin:all | All admin operations |
sandbox:simulate | Create, drive, reset, and delete sandbox projects (sandbox-mode only). |
The default selection in the dashboard’s create-PAT dialog is invoices:read + projects:read + transactions:read — a read-only baseline that covers most agent integrations. Add write or admin scopes only when the consumer actually needs them.
admin:all is gated to the account owner role; non-owner users cannot mint a PAT with that scope, and the checkbox is hidden for them. Even for owners, prefer the narrowest combination of explicit scopes over admin:all — the latter is intended for one-off rescue/migration work, not as a daily-driver permission set.
Expiry
Every PAT must have an expiry date. There is no “never expires” option. The reason is straightforward: a leaked token cannot be used indefinitely if it expires soon, regardless of whether you ever notice the leak.
The create-PAT dialog offers four presets:
- 7 days — short-lived, suitable for one-off scripted work.
- 30 days — the default for routine agent setups; long enough to avoid weekly rotations but short enough to limit a leak’s blast radius.
- 90 days — longer-lived, suitable for stable agent setups.
- Custom date — pick any date in the future.
Pick the shortest window that fits the job. Re-issuing a token is a 30-second flow; carrying a 90-day token when 7 would have done is unnecessary blast radius. When a PAT expires, the dashboard surfaces the expiry inline in the tokens list; you can re-mint a replacement before the old one expires and rotate without downtime.
The no-never-expires policy is enforced at the schema layer via the pat_expires_future_at_creation CHECK constraint on personal_access_tokens — not just in the dashboard UI.
Format
PAT secrets have a stable wire format:
txnod_pat_<32 base62 chars>The full regex is /^txnod_pat_[A-Za-z0-9]{32}$/. The txnod_pat_ prefix is a stable contract — log-redaction patterns, secret-scanner rules, and .env-leak detectors can match on it.
The plaintext secret is shown exactly once, in a one-shot dialog at the end of the create flow. Once you dismiss the dialog the secret cannot be retrieved — only re-minted. PATs are the canonical credential for the TxNod MCP server; for integration walkthroughs see MCP — Claude Code, Claude Desktop, or Cursor.
Storage and revocation
The dashboard never stores plaintext PATs. At mint time the server hashes the 32-char body with SHA-256 and stores the raw 32-byte digest in the secret_hash column. At verify time the bearer token is hashed with the same function and compared via timingSafeEqual from node:crypto — a constant-time compare that closes timing oracles. The plaintext is never reconstructible.
Five schema-level CHECK constraints back the policy:
pat_secret_hash_len—octet_length(secret_hash) = 32. Any non-SHA-256 digest is rejected at write time.pat_last_4_len—char_length(last_4) = 4. The display-onlylast_4column is what the dashboard renders next to each token name so you recognize the right one when revoking; it is never used as a query filter (timing side-channel).pat_scopes_nonempty— at least one scope is required.pat_expires_future_at_creation—expires_at > created_at. The no-never-expires policy is enforced at the DB, not just in the UI.pat_id_ulid_len—char_length(id) = 26. Each token row is keyed by a ULID.
To revoke a PAT, open the Developer → Tokens page and click Revoke. Revocation sets revoked_at to now(); the row is retained for audit. The active-token index is partial — defined WHERE revoked_at IS NULL — so revoked rows fall off the verify hot path immediately. Revoking 1 token or 1000 tokens has the same impact on per-request verify latency.
Project allowlist
You can optionally restrict a PAT to a subset of your projects via the Restrict to specific projects option in the create dialog.
- Leave it unset and
project_allowlistisnull— the PAT can act on any project the owner controls. - Pick one or more projects and
project_allowlistis an array of project ULIDs — the PAT is rejected on any other project.
The verifier enforces the allowlist on every request: a PAT presenting a project id outside its allowlist receives 403 insufficient_scope — the same error code used for missing scopes. Use this when handing a PAT to an agent or third-party tool that should only ever see one project.