Skip to Content
GuidesPersonal Access Tokens

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:

ScopeWhat it allows
invoices:readRead invoices
invoices:writeCreate, cancel invoices
projects:readRead projects
projects:writeModify projects
transactions:readRead payments
webhooks:readView events
webhooks:manageRetry, resend
admin:allAll admin operations
sandbox:simulateCreate, 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_lenoctet_length(secret_hash) = 32. Any non-SHA-256 digest is rejected at write time.
  • pat_last_4_lenchar_length(last_4) = 4. The display-only last_4 column 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_creationexpires_at > created_at. The no-never-expires policy is enforced at the DB, not just in the UI.
  • pat_id_ulid_lenchar_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_allowlist is null — the PAT can act on any project the owner controls.
  • Pick one or more projects and project_allowlist is 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.