C

Capgo · Engineering

CLI Web Login — Architecture Overview

Proposal · 3 June 2026 · how a developer logs the Capgo CLI in from the browser

In one sentence

A developer runs capgo login, a browser opens to a Capgo page where they pick which organisation, app and permissions to grant, click Authorize, and a brand-new API key is created and delivered straight back to their terminal — no copy-pasting keys by hand.

~2

new backend endpoints

1

new web page

0

changes to how keys/permissions work

The problem today

The only way to log the CLI in is to manually find an API key in the dashboard and paste it. There is no "log in with your browser" button. It's clunky and error-prone, and nudges people toward reusing long-lived keys.

The approach

We reuse the proven login choreography that GitHub, Stripe and Tailscale CLIs use — the OAuth Device Flow — but it hands back a normal Capgo API key. It's a recognised, auditable industry standard, not a bespoke design.

How it works, step by step

● CLI (developer's terminal) ● Capgo backend ● Browser page
  1. 1

    Developer runs capgo login CLI

    The CLI asks the backend to start a login session and receives a short confirmation phrase, e.g. enjoy-enough-outwit-win.

  2. 2

    Browser opens to the authorize page Browser

    The page shows the same phrase, so the developer can confirm they are on the genuine page for their terminal. They pick the organisation, app and permission level.

  3. 3

    Developer clicks "Authorize" Browserbackend

    The backend checks the user is allowed and creates the key right away (stored only as a hash, so it is never visible in the dashboard), keeping a one-time copy to hand to the terminal.

  4. 4

    CLI receives the key over HTTPS CLI

    The terminal has been quietly checking with the backend; once approved it collects the one-time key, saves it locally, the temporary copy is burned, and only the hash remains on the server. Done.

Why it's safe

🔒

Key never travels in a link or browser history. It only moves over the same encrypted channel the CLI already uses for every command.

👁️

Visual confirmation. The matching word-phrase in the terminal and the browser proves the developer is authorising their own session.

⏱️

Short-lived & single-use. A login session expires in ~10 minutes, is rate-limited against guessing, and the key can only be collected once.

Same permissions model. Authorising reuses our existing role/permission checks — it introduces no new way to grant access.

For security review: this is the OAuth 2.0 Device Authorization Grant (RFC 8628) — the same recognised flow used by the GitHub, Stripe and Tailscale CLIs — which makes it far easier to audit and defend than a custom-built scheme.

Why this design over the alternative

 Device flow (chosen)Local-server redirect
Key exposureEncrypted channel onlyBriefly in browser history
ReliabilityNo local network port neededDepends on browser rules that keep tightening
Security reviewRecognised standardBespoke surface to defend
Build cost~2 small endpoints + 1 pageNo backend, but trickier client