API tokens
Long-lived scoped bearer tokens for service-to-service auth, CI/CD, automation tools, and AI agents.
API tokens are vaultbase’s long-lived bearer tokens for non-human principals — CI pipelines, cron scripts, integrations (n8n / Zapier / Make), AI agents, third-party tools. Distinct from short-lived user/admin JWTs which expire weekly.
Format on the wire:
Authorization: Bearer vbat_<jwt>The vbat_ prefix is stable so secret-scanning tools can detect leaked
tokens in source repos / logs. The underlying JWT is a standard signed
HS256 with audience: "api".
When to use API tokens vs user JWT
Section titled “When to use API tokens vs user JWT”| Use case | Choose |
|---|---|
| Browser SPA, mobile app, end-user session | User JWT (short-lived, refreshable) |
| CI / cron / service-to-service | API token |
| n8n / Zapier / Make / IFTTT integrations | API token |
| AI agents over MCP (Claude Desktop, Cursor) | API token |
| Read-only auditor / consultant access | API token with read scope |
| Admin SPA itself | Admin JWT (HttpOnly cookie) |
| Scripted admin work (collections, settings, hooks) | API token over MCP with mcp:* scopes, or an Admin JWT |
| Embedding in a public client app | Neither — never embed long-lived tokens client-side |
API tokens are for trusted automation. They’re not user identity.
Scopes
Section titled “Scopes”Phase-1 ships a coarse set; per-collection scopes (collection:posts:read)
are recognised in the wire format but enforcement lands in the RBAC sprint.
| Scope | What it grants |
|---|---|
admin | full admin on the data API (records, files, batch, realtime, custom routes), acting as the minting admin; implies every mcp:* scope — use sparingly |
read | any GET on the data API — all data, collection rules don’t apply (a read-only admin) |
write | POST/PATCH/DELETE on the data API as a signed-in non-admin (collection rules still apply) |
mcp:read | MCP server: read-only tools, over all data (collection rules don’t apply) |
mcp:write | MCP server: mutating tools (records, hooks, settings), acting as an admin — collection rules don’t apply |
mcp:admin | MCP server: full admin tools (implies all mcp:*) |
mcp:sql | MCP server: raw SQL tool, read-only (writes also need mcp:admin) |
admin implies every other scope. mcp:admin implies every mcp:*.
read and write are independent — a read token can’t write; a write
token can’t read.
Mint via CLI
Section titled “Mint via CLI”Fastest path. Reads the local DB directly, no HTTP round-trip.
vaultbase token mint --name "CI deploy bot" --scope write --scope read --ttl 1y# ✓ minted as ops@example.com# id: 7f9a3c1d-44e2-4b18-...# expires: 2027-05-03T10:30:00.000Z (365 days)# scopes: write, read## TOKEN — save this, it will NEVER be shown again:## vbat_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...The token is shown once. Save it to your password manager / CI secret store immediately. The DB stores only the metadata — vaultbase cannot recover the value.
Other CLI commands:
vaultbase token list # human-readable tablevaultbase token list --json # for scriptsvaultbase token revoke <id> # by id from `list`Mint via REST
Section titled “Mint via REST”For programmatic management. Needs an admin session (an API token can’t
mint tokens). Returns 201.
POST /api/v1/admin/api-tokensAuthorization: Bearer <admin-jwt>Content-Type: application/json
{ "name": "Cursor laptop", "scopes": ["mcp:read"], "ttl_seconds": 7776000}{ "data": { "id": "7f9a3c1d-...", "token": "vbat_eyJhbGc...", "expires_at": 1745000000, "warning": "Save this token now — it will never be shown again." }}Other endpoints:
GET /api/v1/admin/api-tokens — list metadata (no token values)GET /api/v1/admin/api-tokens/:id — singleGET /api/v1/admin/api-tokens/me — describe the current request's tokenDELETE /api/v1/admin/api-tokens/:id — revokeMint via admin UI
Section titled “Mint via admin UI”/_/api-tokens page lists existing tokens with name + scopes + status +
last-used. “Mint new token” dialog → name + scope multi-select + TTL
dropdown. Shown-once token modal with a “Copy” button.
Use a token
Section titled “Use a token”Same as any bearer auth:
curl -H "Authorization: Bearer vbat_eyJ..." \ https://api.example.com/api/v1/postsimport { Vaultbase } from "@vaultbase/sdk";
const vb = new Vaultbase({ baseUrl: "https://api.example.com" });vb.client.authStore.set({ token: "vbat_eyJ...", record: { id: "ci-bot" } });import osimport requestsr = requests.get( "https://api.example.com/api/v1/posts", headers={"Authorization": f"Bearer {os.environ['VB_TOKEN']}"},)Lifetime + rotation
Section titled “Lifetime + rotation”| Default | Min | Max |
|---|---|---|
| 90 days | 60 seconds | 10 years |
Best practices:
- Rotate annually for any production token. Mint new → update consumer → revoke old.
- Short-lived for CI: 90d is fine; CI tokens move with the project, so worst-case leak window is bounded.
- Long-lived for AI agents: 1y is reasonable. Revoke on laptop loss.
- Never ship in client apps: tokens in mobile/desktop binaries leak the moment one user reverse-engineers the bundle.
Audit trail
Section titled “Audit trail”MCP tool calls made with a token are written to the audit log as action
mcp.tool, with actor_id + actor_email of the minting admin and
token=<name> in the summary field — so “which automation did this” is one
query away.
Every state-changing admin call made with an admin session is audited too,
collections included (actions such as collections.create,
settings.update, hooks.create).
Record writes made with a token on the data API are not in the audit log.
The request log attributes them to api:<token id>.
Revoke
Section titled “Revoke”One click in the admin UI. Or:
vaultbase token revoke 7f9a3c1d-44e2-4b18-...DELETE /api/v1/admin/api-tokens/7f9a3c1d-... HTTP/1.1Authorization: Bearer <admin-jwt>Revocation is synchronous — the next request bearing that token is no
longer authenticated. There is no eventual-consistency window. On the data
API a revoked (or unknown) token is treated as an anonymous caller: admin-only
collections answer 403, public ones still answer 200.
Revoking a token does not force-log-out other sessions. Only the minting admin’s password reset (force-logout-all) does that, and it kills this token too as a side effect.
Last-used tracking
Section titled “Last-used tracking”Each row records:
last_used_at— most recent authenticated uselast_used_ip— most recent client IP (respectsVAULTBASE_TRUSTED_PROXIES)last_used_ua— most recent User-Agent (truncated to 200 chars)use_count— total successful authenticated requests
Updates are buffered in-memory and flushed every 30 s OR every 1000 events, whichever fires first. Worst-case data loss on hard crash: 30 s of usage telemetry — pure observability, never authoritative.
Storage + leakage protection
Section titled “Storage + leakage protection”- Vaultbase stores only the metadata (name, scopes, jti, expires_at). The token value never touches disk after the mint response is sent.
- The
vbat_prefix is grep-able. GitHub’s secret-scanning partner program (future) can auto-revoke tokens leaked to public repos. - Refuse to commit tokens. Use
.envin.gitignore, GitHub secrets, CI secret stores. - Consider IP allowlists per token (planned for v0.10).
What’s planned for later
Section titled “What’s planned for later”- Per-collection scopes (
collection:posts:read) - Per-token IP allowlist
- Per-token rate-limit override
- GitHub secret-scanning partner integration (auto-revoke on leak)
- Service-account principals (no minting admin)
- Token rotation API (mint new + revoke old in one call)
See also
Section titled “See also”- Authentication concept — user/admin auth model
- Security — overall trust boundaries
- SDK Authentication — using tokens via the SDK