Admin API guide

TL;DR — Task-focused recipes for the Admin API (:9001) and the equivalent CLI. Every operation has a REST endpoint and an authserver admin ... CLI command that hit the same underlying service. This guide has the six most-used flows — register a client, register a resource, rotate keys, revoke tokens, inspect issuances, manage broker providers. Full OpenAPI reference in Reference: Admin API.

Setup

Every admin request needs the API key. Use it as a Bearer token:

export AUTHPLANE_ADMIN_API_KEY="$(cat /path/to/admin-key)"

curl -H "Authorization: Bearer $AUTHPLANE_ADMIN_API_KEY" \
     http://localhost:9001/admin/clients

CLI: same env var. Set once in your shell and every authserver admin ... command picks it up.

Every command in this guide can be run as either curl or CLI — they’re equivalent. The CLI is more ergonomic for humans; curl fits CI/CD better.

Register an MCP client (manual, not via DCR)

When you want a stable client_id (not DCR-generated) or a confidential client with a specific secret:

CLI:

authserver admin client create \
    --grant-types authorization_code,refresh_token \
    --redirect-uris https://app.example.com/oauth/callback \
    --scopes 'tools/read||Read tools' \
    --scopes 'tools/write||Write tools' \
    --auth-method client_secret_post \
    --name "My App"

REST:

curl -X POST http://localhost:9001/admin/clients \
  -H "Authorization: Bearer $AUTHPLANE_ADMIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "My App",
    "grant_types": ["authorization_code", "refresh_token"],
    "redirect_uris": ["https://app.example.com/oauth/callback"],
    "scope": "tools/read tools/write",
    "token_endpoint_auth_method": "client_secret_post"
  }'

Response includes client_id + (for confidential clients) client_secret. The secret is returned once and stored as a bcrypt hash — save it now or you’ll need to register a new client.

For public clients (PKCE-only), use --auth-method none (or omit client_secret_post).

Register a resource (Mint or Broker)

Mint resource (your MCP server):

authserver admin resource create \
    --slug my-mcp-server \
    --uri http://mcp.example.com/mcp \
    --backend-kind mint \
    --display-name "My MCP Server" \
    --scopes 'tools/read||Read the data' \
    --scopes 'tools/write||Modify the data'

Note the scope format: --scopes 'name|upstream|description' — pipe-delimited, repeat the flag for each scope. Leave upstream empty for Mint resources. The uri must match the resource string your MCP server publishes in its PRM byte-for-byte (see Configuration: Resources → URI matching).

Broker resource (upstream provider target):

authserver admin resource create \
    --slug github-repos \
    --backend-kind broker \
    --broker-provider github \
    --display-name "GitHub Repos" \
    --scopes 'repo:read|repo|Read repositories' \
    --scopes 'repo:write|repo|Push changes'

The Broker’s scope name is what MCP clients ask for; the underlying upstream scope (what AuthPlane asks GitHub) is configured separately. For multi-scope upstream mappings, see Guides: Upstream connections.

Rotate signing keys

Zero-downtime. Previous key stays in JWKS so outstanding tokens keep verifying.

# CLI
authserver admin key rotate

# REST
curl -X POST http://localhost:9001/admin/keys/rotate \
     -H "Authorization: Bearer $AUTHPLANE_ADMIN_API_KEY"

Response:

{
  "current_kid": "kid_new_abc",
  "previous_kid": "kid_old_xyz",
  "rotated_at": "2026-07-01T00:00:00Z"
}

On multi-instance deployments with postgres_key or vault_transit, propagation is automatic via LISTEN/NOTIFY (ms). Single-instance keyfile may want a SIGHUP after rotation for immediate reload:

docker kill -s HUP $(docker compose ps -q authplane)
# or
kill -HUP $(pidof authserver)

Rotation cadence + policy in Security: Key management.

Revoke a token / a whole client’s tokens

Revoke a specific token — use the OAuth revocation endpoint (public, not admin):

curl -X POST http://localhost:9000/oauth/revoke \
    -d "token=$ACCESS_OR_REFRESH_TOKEN" \
    -d "client_id=$CLIENT_ID" \
    -d "client_secret=$CLIENT_SECRET"

Returns 200 per RFC 7009 spec.

Revoke everything issued for a client — suspend the client (via admin REST API; no CLI subcommand):

curl -s -X PATCH http://localhost:9001/admin/clients/$CLIENT_ID/suspend \
    -H "Authorization: Bearer $AUTHPLANE_ADMIN_API_KEY"

While suspended, the client can’t get new tokens; existing tokens continue to verify until they expire (JWTs are stateless), UNLESS you also enable introspection revocation checks on your MCP server (SDK revocation_checker).

Reactivate:

curl -s -X PATCH http://localhost:9001/admin/clients/$CLIENT_ID/reactivate \
    -H "Authorization: Bearer $AUTHPLANE_ADMIN_API_KEY"

Revoke a user’s consent — the client can’t get new tokens for this user until the user consents again:

authserver admin grant list-user-grants --user $USER_ID
# find the consent_grant id
authserver admin grant revoke-consent --id $CONSENT_GRANT_ID

Cascades onto live Mint issuances — those tokens are revoked immediately.

Inspect issuances (forensic audit)

Every token issuance writes a row to issuances — queryable by user, client, resource, or time range:

# Last 50 issuances for a user
authserver admin issuance list --user user-42 --limit 50

# Everything issued for a client in the last day
authserver admin issuance list --client my-client --since 24h

# Filter by resource
authserver admin issuance list --resource github-repos --limit 20

# Full detail on one issuance (all claims, DPoP jkt, act chain)
authserver admin issuance get --id iss_abc123

REST equivalent: GET /admin/issuances?user_id=...&client_id=...&resource=...&since=...&limit=....

Combined with audit_events (which includes non-issuance actions like consent granted, key rotated, provider added), issuances are the forensic long-term record. Retention is until you purge machine-tokens — issuances aren’t purged automatically.

Manage broker providers

Manage upstream OAuth providers used by Broker resources.

Register — the --config-data flag takes a path to a JSON file with the provider config:

cat > github-provider.json <<'EOF'
{
  "client_id": "github-oauth-app-client-id",
  "client_secret_ref": "CONNECTOR_GITHUB_SECRET",
  "authorize_url": "https://github.com/login/oauth/authorize",
  "token_url": "https://github.com/login/oauth/access_token"
}
EOF

authserver admin provider create \
    --slug github \
    --protocol oauth \
    --display-name "GitHub" \
    --config-data ./github-provider.json

Update — e.g., rotating credentials (edit the JSON file, then re-apply):

authserver admin provider update --id $PROVIDER_ID \
    --config-data ./github-provider.json

Delete — fails if any resource still references this provider:

authserver admin provider delete --id $PROVIDER_ID

Details on the config_data shape per protocol in Guides: Upstream connections.

Bulk operations from JSON

Every subcommand accepts --json flag for JSON output, and CLI can read from stdin via -:

# Dump every client
authserver admin client list --json > clients-backup.json

# Restore (per-item — no batch endpoint yet)
jq -c '.[]' clients-backup.json | while read c; do
    echo "$c" | authserver admin client create --json -
done

For real backup, back up the underlying storage (SQLite file or pg_dump). See Operate: Backup, upgrade, purge.

Admin UI (/admin/ui/)

Every action above has a UI equivalent. Open http://localhost:9001/admin/ui/ and paste $AUTHPLANE_ADMIN_API_KEY when prompted. Stored in sessionStorage — clears on tab close.

The UI mirrors the API’s structure: sidebar with Clients / Users / Resources / Providers / Grants / Issuances / Signing Keys / Audit / System, table view for lists, drawer for details + edit. Same underlying REST endpoints — API-only ops just aren’t in the UI (yet).

Common failure modes

SymptomCauseFix
401 Unauthorized on every admin requestAPI key wrong or missingSet AUTHPLANE_ADMIN_API_KEY; check admin.api_key in config
409 conflict on client createDuplicate client_namePick unique names or use auto-generated IDs
409 conflict on resource createDuplicate slugSlugs are unique per instance
403 access_denied on provider deleteA resource still references this providerDelete/update the resource first
Admin UI shows “Failed to fetch”CORS not set for the admin originSet AUTHPLANE_SERVER_ALLOWED_ORIGINS