Skip to main content
Navigation

reference

OAuth Scopes

The three-tier catalog

Vault’s OAuth Resource Server publishes three scopes via RFC 9728 Protected Resource Metadata:

ScopeWhat it grantsTypical caller
vault:readList credentials, read metadata, issue + redeem leases (the full “use a credential” flow)Claude Code MCP, browser extension, CLI for read-only scripts
vault:writeEverything in vault:read, plus store / archive / restore / rotate credentials, edit tags, edit foldersOperator scripts, sibling services storing their own keys, CLI for deploy automation
vault:adminEverything in vault:write, plus grant management and role assignmentsOperator 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:

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

ToolRequired scope
vault.list_credentialsvault:read
vault.list_foldersvault:read
vault.lease_credentialvault:read
vault.read_credentialvault:read
vault.list_my_leasesvault:read
vault.revoke_leasevault:read
vault.store_credentialvault:write
vault.archive_credentialvault:write
vault.restore_credentialvault:write
vault.rotate_credentialvault: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:read
  • POST /api/v1/credentials/[key]/reveal, POST /api/v1/leases, POST /api/v1/leases/read: vault:read
  • POST /api/v1/credentials, POST /api/v1/credentials/[key]/archive | restore | rotate: vault:write
  • PATCH | 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 MembershipGrant table 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.