Skip to main content

CLI Authentication

Two flows end up issuing a token the CLI can use:
  • For Humansbkey auth login uses RFC 8628 device authorization: display a code, scan a QR on your phone, approve with biometrics.
  • For Agentsbkey auth setup-agent mints OAuth client_credentials so a headless agent or CI job can authenticate without a human in the loop on every request.
Agents still need a human to create them. You have to bkey auth login once as a human before you can run setup-agent — the new agent is gated on a biometric approval from your phone before the credentials are issued.

For Humans

Interactive login from any terminal. Uses the device authorization flow so you can log in on a machine that has no browser (SSH, CI debug shell, IoT device, etc.) by approving on your phone.

Usage

bkey auth login
The CLI prints a short user code and a verification URL, opens the URL in your browser with the code pre-filled, and starts polling. On your phone:
  1. Open the BKey app (or follow the URL on a phone browser).
  2. Confirm the user code matches.
  3. Approve with facial biometrics.
The CLI unblocks the moment the phone completes approval and saves the session as a human profile in ~/.bkey/profiles.json (default identifier: default). Subsequent bkey … commands use it automatically. Multiple profiles can coexist — pass bkey auth login --profile work to save under a different name, then select with bkey <cmd> --profile work or BKEY_PROFILE=work bkey <cmd>.

Flow at the protocol level

  1. Client calls POST /oauth/device_authorization and receives device_code, user_code, verification_uri.
  2. User visits the URL on their phone and enters the code, or scans the QR.
  3. User approves with facial biometrics.
  4. Client polls POST /oauth/token with grant_type=urn:ietf:params:oauth:grant-type:device_code until it gets an access token.
Use cases:
  • CLI tools (bkey auth login)
  • SSH sessions and CI debug shells
  • IoT devices with no browser

For Agents

Agents authenticate with the OAuth 2.1 client credentials grant — one client_id + client_secret per agent, no phone roundtrip on every call. The credentials are minted by a human running bkey auth setup-agent after they’re logged in.

Minting agent credentials

# Requires a prior `bkey auth login` (human must be logged in)
bkey auth setup-agent --name "My Deploy Bot" --save
  • Pushes an approval prompt to the logged-in human’s phone if the requested scopes are elevated (biometric approval). Baseline-scope agents (e.g. approve:action only) may be created without a phone prompt — all subsequent bkey approve calls still go through CIBA at the phone.
  • On approval, BKey returns the agent’s client_id + client_secret.
  • --save stores them as an agent profile in ~/.bkey/profiles.json. The profile identifier is slugified from --name (e.g. "My Deploy Bot"my-deploy-bot); override explicitly with --profile <slug>. Collisions error unless --overwrite is passed.
  • --json prints the creds to stdout instead (for CI secret setup, env vars, etc.).

Running as an agent

Since 0.3.0 agent mode is opt-in — a saved agent profile no longer silently overrides your user session. Select agent mode explicitly:
# Approve as the default agent profile
bkey approve "Deploy api-gateway@abc123 to prod" --agent \
  --scope approve:action \
  --user-did did:bkey:...

# Or pin a specific agent profile by name
bkey approve "…" --agent --profile my-deploy-bot

# Or via env vars (CI/CD, Docker)
export BKEY_MODE=agent
bkey approve "…"

# Direct client_credentials — bypasses profiles entirely
export BKEY_CLIENT_ID=bkey_client_xxx
export BKEY_CLIENT_SECRET=bkey_secret_xxx
bkey approve "…"

In code (Python / TypeScript)

import { BKey } from '@bkey/sdk';

const bkey = new BKey({
  clientId: process.env.BKEY_CLIENT_ID!,
  clientSecret: process.env.BKEY_CLIENT_SECRET!,
});

// Token is exchanged + refreshed automatically.
from bkey import BKeyClient

client = BKeyClient(
    client_id=os.environ["BKEY_CLIENT_ID"],
    client_secret=os.environ["BKEY_CLIENT_SECRET"],
)

Default scopes

bkey auth setup-agent includes a sensible default scope set (vault:access, vault:store, signing:create, signing:read, identity:read, approve:action, approve:payment, payment:authorize, payment:address, payment:limits). Override with --scopes <comma-separated> to tighten or expand. Use cases:
  • Headless agents (e.g. a cron job that calls paid APIs)
  • Server-to-server communication
  • CI pipelines making authenticated calls
  • MCP servers verifying CIBA approval tokens

What agents can’t do on their own

Agent tokens from client_credentials don’t grant per-action authority by themselves. For anything sensitive (payments, vault access, deploys), the agent must still initiate a CIBA approval — the human gets a push and approves with biometrics, the agent gets a short-lived, scope-bound token proving that consent. See the CIBA guide for the one-line approve() pattern.

See also