Skip to content

API keys

The bcdock CLI authenticates with API keys (bdk_…) almost everywhere. Long-lived (until revoked), scope-bounded, no refresh-token gymnastics. Mint them in the portal at Profile → API keys.

For the JWT vs API-key mental model, see authentication.

Scopes

Pick the smallest set that lets the consumer do what it needs.

Scope Allows Don't grant if…
env:read List environments, inspect details, read logs Always include - required for almost every other action to surface useful errors
env:write Create / delete / hibernate / resume environments; publish AL extensions The consumer is read-only (status dashboards, billing reports)
usage:read Read company usage and billing data (bcdock usage, bcdock env usage <name>) The consumer doesn't need cost data

API keys minted via bcdock auth login (the OTP exchange path) automatically receive these three scopes. Platform-admin operations (pool management, image building, cross-tenant env operations, billing inspection) are staff-only and aren't reachable from the public bcdock CLI or via customer-facing API keys.

How to mint

From the portal

  1. Profile → API keys → Create
  2. Name the key (e.g. ci-pipeline, claude-agent, release-bot)
  3. Pick scopes
  4. Click Create
  5. Copy the bdk_… token - you can't view it again

The portal stores only the prefix and a hash; the bytes you copy are the only way to use the key.

From an existing JWT

Used today for minting admin-scoped keys (which auth login won't produce). Until bcdock auth create-key --scopes admin ships:

JWT=$(bcdock companies switch <admin-company> -o json | jq -r .token)
curl -X POST https://api.bcdock.io/api/v1/api-keys \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{"name":"ops","scopes":["admin","env:read","env:write"]}'

Returns the bdk_… token; pipe to bcdock auth set-token to persist locally.

How to use

Three paths, in order of preference:

Path When Persistence
BCDOCK_TOKEN env var CI, agents, ephemeral runners none - dies with the process
bcdock auth login Daily dev on a personal laptop ~/.config/bcdock/credentials.json (mode 0600)
bcdock auth set-token <bdk_…> When you have a key already and want to persist (e.g. admin-scoped key minted via curl) same as auth login

Rule of thumb: never persist secrets to disk in CI - use BCDOCK_TOKEN.

Verify what a key has

bcdock auth whoami

Prints the token's identity (email, role, company). Doesn't print the scopes directly today; if you need that, list keys in the portal - the row shows the scopes you picked at creation.

Revoke

Portal

Profile → API keys → Revoke on the row. Takes effect immediately for new requests; in-flight requests complete.

Programmatic

curl -X DELETE https://api.bcdock.io/api/v1/api-keys/<keyId> \
  -H "Authorization: Bearer <jwt-or-key-with-admin-scope>"

The keyId is shown in the portal row; not the same as the bdk_… token bytes.

Rotation

We don't auto-rotate keys. When a contributor leaves or a runner is decommissioned:

  1. Mint a fresh key with the same scopes
  2. Update the consumer's secret store
  3. Revoke the old key

Both keys work in parallel during the swap, so there's no service interruption.

Common pitfalls

  • Pasting bdk_… into chat history (Slack, agent conversation log, Discord). Treat it like a password.
  • Granting admin "for safety". The whole point of scopes is the smallest grant that works. admin is for BCDock operators, not customer pipelines.
  • Reusing one key across multiple unrelated repos / pipelines. Hard to attribute audit-log entries; rotation has higher blast radius. One key per consumer is the right shape.
  • Storing keys in ~/.config/bcdock/credentials.json on shared servers. Every user with read access on that file can act as that key. Use BCDOCK_TOKEN per-process for shared infrastructure.
  • Authentication - API key vs JWT, the three credential paths
  • Exit codes - exit 3 is auth, exit 1 with "scope insufficient" is the wrong scopes
  • Agent quickstart - BCDOCK_TOKEN is the right shape for agent loops