C

Capgo · Engineering

CLI Web Login — Flow Diagram

OAuth Device Flow shape · who talks to whom, and in what order

● CLI (developer's terminal — not logged in) ● Capgo backend ● Browser (developer IS logged in → has JWT)

Sequence — start to finish

sequenceDiagram
    autonumber
    actor Dev as Developer
    participant CLI as CLI (terminal)
    participant BE as Capgo Backend
    participant Web as Browser (logged in)

    Dev->>CLI: runs `capgo login`
    CLI->>BE: POST /cli-auth/start (device name)
    BE-->>CLI: device_code (secret) + user_code
"enjoy-enough-outwit-win" + verify URL CLI-->>Dev: prints the phrase to confirm CLI->>Web: opens the verify URL rect rgb(238,245,255) note over CLI,BE: CLI quietly polls in the background loop every few seconds CLI->>BE: POST /cli-auth/poll (device_code) BE-->>CLI: "authorization_pending" end end Web->>BE: GET /cli-auth/session [JWT] BE-->>Web: device info + the same phrase Dev->>Web: confirms phrase matches,
picks org / app / permission Web->>BE: POST /cli-auth/authorize [JWT] BE->>BE: check permission + create key NOW (hashed),
stash one-time encrypted secret BE-->>Web: success → "return to your terminal" CLI->>BE: POST /cli-auth/poll (device_code) BE-->>CLI: "authorized" + api_key (delivered once)
secret burned, session destroyed CLI->>CLI: save key to ~/.capgo CLI-->>Dev: "Logged in!"

At a glance — the two credentials

flowchart LR
    Dev([Developer]) -->|runs capgo login| CLI[CLI · terminal]
    CLI <-->|device_code secret
start + poll| BE[(Capgo Backend)] CLI -->|opens browser| Web[Browser page] Web <-->|JWT session
session + authorize| BE BE -->|mint NEW key| Key{{New API key}} Key -.delivered once over HTTPS.-> CLI classDef cli fill:#eef5ff,stroke:#119eff,color:#0c6eb8; classDef be fill:#eef0f7,stroke:#515271,color:#515271; classDef web fill:#e8f7f4,stroke:#1FB2A5,color:#0e8a7e; classDef key fill:#fff4e8,stroke:#ff7211,color:#b8480a; class CLI cli; class BE be; class Web web; class Key key;

The CLI talks to the backend with a one-time device_code secret (it isn't logged in). The browser talks to the backend with the developer's JWT (their existing dashboard login). The backend is the bridge: the logged-in browser authorises, and the key flows back to the waiting terminal.