Navigation
reference
OAuth Scopes
The three-tier catalog
Vault’s OAuth Resource Server publishes three scopes via RFC 9728 Protected Resource Metadata:
| Scope | What it grants | Typical caller |
|---|---|---|
vault:read | List credentials, read metadata, issue + redeem leases (the full “use a credential” flow) | Claude Code MCP, browser extension, CLI for read-only scripts |
vault:write | Everything in vault:read, plus store / archive / restore / rotate credentials, edit tags, edit folders | Operator scripts, sibling services storing their own keys, CLI for deploy automation |
vault:admin | Everything in vault:write, plus grant management and role assignments | Operator tooling only |
The hierarchy is strict: a token carrying vault:admin satisfies vault:write and vault:read requirements as well. You don’t have to enumerate every lower tier on the token.
Where vault advertises this
The PRM endpoints publish scopes_supported:
- MCP audience:
/.well-known/oauth-protected-resource - REST audience:
/api/v1/.well-known/oauth-protected-resource
Both serve application/json and are public + cacheable (5 minute TTL).
Identity’s view
Vault aligns with identity’s catalog. Identity advertises the same three scope names in its OAuth 2.1 discovery document at https://identity.ghoststack.app/.well-known/oauth-authorization-server. Token requests against identity’s /oauth/authorize should include the scopes you want; the consent screen surfaces each one to the user before they approve.
How vault enforces
Bearer-authenticated requests (JWT or PAT) must carry a scope claim that satisfies the required tier for the route or MCP tool. The hierarchy applies - vault:admin satisfies any check.
If the scope is insufficient, vault returns:
- REST: HTTP 403 with
WWW-Authenticate: Bearer error="insufficient_scope", scope="<required>", resource_metadata=<PRM URL>. Body:{ "error": { "code": "auth/insufficient-scope", "message": "...", "details": { "required": "vault:write" } } }. - MCP: same code mapped to the JSON-RPC error envelope.
Cookie-session requests (a human signed in to vault’s admin UI via identity’s gs_session) bypass scope checks - they’re gated by RBAC (per-credential grants) and tenant isolation. Scopes only apply when the caller authenticated by Bearer.
What each surface requires
MCP tools
| Tool | Required scope |
|---|---|
vault.list_credentials | vault:read |
vault.list_folders | vault:read |
vault.lease_credential | vault:read |
vault.read_credential | vault:read |
vault.list_my_leases | vault:read |
vault.revoke_lease | vault:read |
vault.store_credential | vault:write |
vault.archive_credential | vault:write |
vault.restore_credential | vault:write |
vault.rotate_credential | vault:write |
Each tool’s MCP description (returned by tools/list) carries a SCOPE: line so scope-aware clients can surface upgrade hints.
REST routes (by method)
GET /api/v1/credentials,/api/v1/folders,/api/v1/leases,/api/v1/audit,/api/v1/tags:vault:readPOST /api/v1/credentials/[key]/reveal,POST /api/v1/leases,POST /api/v1/leases/read:vault:readPOST /api/v1/credentials,POST /api/v1/credentials/[key]/archive | restore | rotate:vault:writePATCH | DELETE /api/v1/folders/[id],POST /api/v1/folders(create), tag rename/prune/merge:vault:write- Grant management (
/grants,/credentials/[key]/grants,/folders/[id]/grants,/tenants/[tenantId]/role-assignments):vault:admin
Requesting scopes at install time
The minimal client install for most agents:
claude mcp add --transport http vault https://vault.ghoststack.app/api/mcp \
--callback-port 8123 \
--scope "vault:read vault:write"
The OAuth flow routes through identity; the user consents to the two scopes once; subsequent calls reuse the cached token.
For read-only automation (CI lookup of a config value, audit-only tooling), request just vault:read:
claude mcp add --transport http vault https://vault.ghoststack.app/api/mcp \
--callback-port 8123 \
--scope "vault:read"
For operator tooling that needs to manage grants programmatically:
claude mcp add --transport http vault https://vault.ghoststack.app/api/mcp \
--callback-port 8123 \
--scope "vault:admin"
Comparison: scopes vs vault RBAC
OAuth scopes and vault’s RBAC operate on different axes:
- Scopes describe the universe of operations the token CAN authorize. They’re declared at token-mint time and travel with the token.
- RBAC describes which credentials the user has access to. It’s stored in vault’s
MembershipGranttable and applies to every request from that user, regardless of how they authenticated.
A token with vault:write lets you POST /api/v1/credentials from a scope-permission standpoint. Whether the resulting store succeeds depends on whether your user has the canStore permission on the target folder (RBAC). Both gates must pass.
Why the three-tier shape (and not a fine-grained per-action list)
Read / write / admin is the industry-standard OAuth shape (AWS, GitHub, Stripe). The earlier vault.list / vault.read / vault.lease / vault.rotate four-verb spelling was internal-only and never reached an issued token; phase 36 consolidates to the published three-tier catalog so every customer integration uses familiar shapes.
Related
- MCP server reference for the per-tool surface.
vault exec(phase 35 Mechanism A) for the plaintext-out-of-chat-log flow.- Audit log - every scoped operation records an audit row.
- RFC 6750 §3 for the WWW-Authenticate
insufficient_scopeerror. - RFC 9728 for the PRM shape vault publishes.