Admin API guide
TL;DR — Task-focused recipes for the Admin API (
:9001) and the equivalent CLI. Every operation has a REST endpoint and anauthserver 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
Related
- Reference: Admin API — full OpenAPI spec (Rapidoc) + auth model
- Reference: Metrics & CLI — every
admin *command with all flags - Security: Threat model → T8 — admin API is threat T8; hardening notes
- Operate: Kubernetes → Ingress — how to restrict admin access with a separate ingress