AIOps Bot Platform
Console

CLI Authentication

How the bot CLI authenticates humans (OAuth device flow), mints agent bootstrap tokens, and signs a local bot-agent into the control plane — without the dashboard.

The bot CLI is a Go client for the control plane. It lets you manage projects and agents, install and run a local bot-agent binary, and send messages — all from the terminal after a one-time device login.

This page covers authentication only. Install and everyday usage: CLI. For the OAuth wire protocol see OAuth 2.0 API. For runtime JWT details see Security.

Three trust boundaries

Keep these separate — they use different credentials and different servers:

#BoundaryActorCredentialUsed for
1CLI → control planeYou (human)OAuth access + refresh JWTs/api/cli/**, mint bootstrap tokens
2bot-agent → control planeAgent recordRuntime access + refresh JWTs/api/runtime/** (LLM proxy, workspace)
3Caller → local bot-agentYou / your appLocal API key (BOT_AGENT_API_KEY)http://127.0.0.1:4484/**

Passwords never enter the CLI. Layer 1 uses the OAuth 2.0 Device Authorization Grant (RFC 8628). Layer 2 starts from a short-lived bootstrap token. Layer 3 never leaves your machine.

  you  ──bot login──►  control plane /api/oauth/*
         (device flow)
         tokens.json

  you  ──bot agents / projects──►  control plane /api/cli/*
         (Bearer access JWT)

  you  ──bot runtime auth──►  local bot-agent /auth/session
         (bootstrap token + local API key)
                │
                └── exchanges ──► control plane /api/runtime/session/exchange
                                  (agent cloud session → cloud.json)

1. Human login (device flow)

Commands

bot login              # print code + URL; open browser
bot login --no-open   # print only (SSH, CI, remote desktops)
bot auth status        # who am I, expiry, server
bot auth status -o json
bot logout             # delete stored tokens

Step-by-step

  1. Authorize — CLI POST /api/oauth/device/authorize with { "client_id": "bot-platform-cli" }.
  2. Display — CLI shows a user code (e.g. WDJB-MQKG) and a verification URL. The URL is always built from the CLI’s configured server base (https://169.63.180.31.sslip.io/auth/device?code=…), not from the server’s raw verification_uri* fields (those can point at a wrong host if BETTER_AUTH_URL is mis-set).
  3. Approve — You open the URL, sign in with IBM W3 ID if needed, and approve the device. The device / user codes last 15 minutes.
  4. Poll — CLI polls POST /api/oauth/token about every 5 seconds until approved, denied, or expired.
  5. Store — Access + refresh JWTs are written to disk; subsequent /api/cli/* calls send Authorization: Bearer <access_token>.
$ bot login

AIOps Bot Platform — Login
  Server: https://169.63.180.31.sslip.io

  Open this URL in your browser:
   https://169.63.180.31.sslip.io/auth/device?code=WDJB-MQKG

  Then enter the code:
      WDJB-MQKG

✓ Logged in
  Signed in as you@example.com
  Role: whitelisted_user

Where state lives

PathPurposeMode
Config directorymacOS: ~/Library/Application Support/bot/ · Linux / others: ~/.config/bot/ (or $XDG_CONFIG_HOME/bot)0700
tokens.jsonaccess_token, refresh_token, token_type, expires_in0600
config.yamlserver_url, output, insecure, binary_repo0600
runtime.jsonLocal bot-agent pid, port, API key, home (after bot runtime start)0600

Override the directory with --config /path/to/dir (directory, not a file).

Token lifetimes

TokenLifetimeStorage / behavior
Device + user code15 minutesServer device_authorization table
CLI access JWT7 daysStateless JWT; Bearer on /api/cli/**
CLI refresh JWT30 daysJWT + SHA-256 hash in cli_refresh_token; rotated on every refresh
Agent bootstrap5 minutesSingle-use; response-only
Agent access JWT~30 minutesIn bot-agent cloud.json
Agent refresh JWT~30 daysRotated; hashed at rest on the server

All JWTs are HS256 with BETTER_AUTH_SECRET. The CLI never verifies signatures locally — it only decodes claims for bot auth status display. The control plane always verifies.

Automatic refresh

On HTTP 401 from /api/cli/*, the CLI:

  1. Calls POST /api/oauth/refresh with the stored refresh token.
  2. Persists the new access + refresh pair (old refresh is revoked).
  3. Retries the original request once.

bot auth status will also attempt a refresh if the access token’s exp is in the past, so the printed state stays honest.

Choosing the control-plane URL

bot config set server https://your-host.example.com
bot --server https://your-host.example.com login
bot config set insecure true   # self-signed lab TLS only

Registered OAuth client_id is always bot-platform-cli.

2. Agent bootstrap tokens (CLI → control plane → agent)

Once you are logged in as a human, you can create agents and mint bootstrap tokens without opening the dashboard:

bot projects create "my-app" -d "…"
bot agents create PROJECT_ID worker -d "…"
# create response already includes bootstrapToken + expiresIn

bot agents bootstrap-token PROJECT_ID AGENT_ID   # mint a fresh one later

Requirements:

  • Project role write or admin (or global admin) to create agents / mint tokens.
  • Bootstrap tokens are single-use, expire in 5 minutes, and cannot be retrieved again. Store them securely or exchange immediately.

3. Signing the local bot-agent into the cloud

The local binary does not use your human OAuth tokens. It needs its own cloud session:

bot runtime install    # zip / git release repo / --from-server
bot runtime start      # background process; generates local API key
bot runtime auth --project PROJECT_ID --agent AGENT_ID
# or: bot runtime auth --token "$BOOTSTRAP_TOKEN"
bot runtime status     # expect health.signedIn=true

What bot runtime auth does:

  1. (If --project + --agent) mints a fresh bootstrap token via /api/cli/….
  2. POST http://127.0.0.1:<port>/auth/session with { "cloudBaseUrl", "bootstrapToken" }, using the local API key.
  3. bot-agent calls POST /api/runtime/session/exchange and writes the result to <agent-home>/cloud.json.
  4. Workspace content is synced from the control plane (local state files such as cloud.json / runtime.json are never overwritten by that zip).

After this, bot runtime send "…" can reach the LLM proxy through the agent’s cloud session.

Local API key (layer 3)

bot runtime start --api-key my-secret   # optional; otherwise auto-generated

Callers (including the CLI) must send the key as:

  • Authorization: Bearer <key>, or
  • X-API-Key: <key>, or
  • ?api_key=<key> (WebSockets)

The key is stored in runtime.json next to the CLI config and never sent to the control plane.

End-to-end without the browser UI

bot login
bot projects create "demo"
bot agents create PROJECT_ID worker
bot runtime install --zip ./bot-agent-macos-universal.zip   # or --repo / --from-server
bot runtime start
bot runtime auth --project PROJECT_ID --agent AGENT_ID
bot runtime send "Hello" --wait 2m
bot runtime status
bot logout   # when finished on a shared machine

Interactive equivalent: bot tui → project → agent → u (runtime screen), or dashboard t for the global runtime screen.

Troubleshooting

SymptomCauseFix
not logged in: run bot login firstNo / expired CLI tokensbot login; confirm with bot auth status
Login URL shows an unexpected hostOld CLI or wrong server_urlbot config get server; upgrade CLI (URL is always derived from config)
Stuck on “Waiting for approval”Browser never approvedOpen the printed URL; finish W3 sign-in within 15 minutes
Refresh / invalid_grantRefresh rotated elsewhere or >30 days oldbot login again
runtime auth OK but later not signed inStale bot-agent overwrote cloud.json from workspace zipUse a current bot-agent build; re-run bot runtime auth
Local HTTP 401 from bot-agentAPI key mismatchAlign --api-key with runtime.json; restart with bot runtime start
TLS errors to the control planePrivate CA / self-signedLab only: bot config set insecure true

Security checklist

  • Treat tokens.json like a password (permissions 0600, never commit).
  • Bootstrap tokens are as powerful as a first agent login for five minutes — do not paste them into tickets or logs.
  • --insecure disables TLS verification to the control plane — not for production.
  • The CLI does not log access, refresh, or bootstrap token values.
  • Revoke access: bot logout (CLI), regenerate bootstrap + restart agent (runtime), or sign the agent out / delete it in the project.