fix(cli): point logicsrc login at the real app + add device-code login
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run

`logicsrc login` defaulted to http://localhost:4010 — a dev origin that
doesn't exist on an installed machine, so the printed authorize URL went
nowhere. It now defaults to the hosted credentials app (apps/pwa), reads
the documented $LOGICSRC_API, and only reuses a stored apiUrl once that
identity has actually completed a login (which is how machines got stuck
pointing at localhost). Note logicsrc.com is the marketing site and has
no /cli routes.

The loopback flow is also unusable over SSH: redirect_uri is
http://127.0.0.1:<port>/callback, which resolves to the *browser's*
machine, not the CLI's. Added a device-authorization flow — the CLI
prints a short user_code, the human approves it from any browser:

  POST /cli/device/code   mint device_code + user_code (10 min TTL)
  GET  /cli/device        approve page (login required; typo-tolerant)
  POST /cli/device        approve/deny (CSRF-guarded browser form)
  POST /cli/device/token  CLI polls -> lsk_ API key

device_code is stored sha256-hashed, single-use, with authorization_pending
/ slow_down / access_denied / expired_token poll semantics. The CLI picks
the flow automatically (SSH/CI/no-DISPLAY -> device), with --device/--web
to force it and a fallback to loopback against servers without /cli/device.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Anthony Ettinger 2026-07-28 18:07:49 +00:00
parent eaf0a6162b
commit cf475f0f4c
7 changed files with 311 additions and 16 deletions

View file

@ -0,0 +1,15 @@
-- Device-authorization codes for `logicsrc login` on machines with no browser
-- (SSH sessions, droplets, containers). The CLI polls /cli/device/token with the
-- device_code while the human approves the short user_code in a browser anywhere.
CREATE TABLE IF NOT EXISTS cli_device_codes (
device_code_hash TEXT PRIMARY KEY, -- sha256 of the CLI's secret device_code
user_code TEXT NOT NULL UNIQUE, -- short human-typed code (XXXX-XXXX)
user_id TEXT REFERENCES users(id) ON DELETE CASCADE,
name TEXT,
status TEXT NOT NULL DEFAULT 'pending', -- pending | approved | denied | used
created_at INTEGER NOT NULL,
expires_at INTEGER NOT NULL,
last_polled_at INTEGER
);
CREATE INDEX IF NOT EXISTS idx_cli_device_user_code ON cli_device_codes(user_code)