Problem
/settings/security "ox CLI sessions" lists every PAT minted by ox login. Users with many machines (laptop, desktop, devcontainer, CI) cannot tell which row maps to which machine — only Created/Last-used/Expires timestamps are shown.
Underlying cause: PAT names are timestamp-only.
// apps/api-go/internal/service/gitlab.go:473 (sageox-monorepo)
tokenName := "sageox-cli-" + time.Now().Format("20060102-150405")
// → "sageox-cli-20260527-143022"
DB schema has no name column; wire (cliSessionResponse) omits one even if added.
Goal
User can scan the CLI sessions list and immediately identify the machine to revoke.
Proposed shape
ox CLI (this repo)
During ox login device-flow token exchange, send a device_label field:
// internal/auth/device_flow.go (or login.go)
hostname, _ := os.Hostname() // e.g. "tacoma"
user, _ := user.Current() // e.g. "ryan"
label := fmt.Sprintf("%s@%s", user.Username, hostname)
// → "ryan@tacoma"
Privacy:
- Opt-out via
SAGEOX_NO_DEVICE_LABEL=1
- Hostname can leak project codename / employer name on shared boxes — document this
- Recommend hostname-only as default if user opt-out feels too coarse; full
user@host if explicit
Backend (sageox-monorepo)
- Migration: add
name text to gitlab_pats (nullable for back-compat)
- Accept
device_label in device-flow token exchange endpoint
- Compose tokenName:
sageox-cli-<label>-<timestamp> → sageox-cli-ryan@tacoma-20260527-143022
- Persist label in
gitlab_pats.name, mirror to GitLab PAT name
- Add
name string \json:"name"`tocliSessionResponse`
Web UI (sageox-monorepo)
apps/web/src/components/settings/security/CliSessionsList.tsx:
- Display
session.name as primary heading
- Fallback to existing "Last used X ago" when
name is null (covers old rows — back-compat)
Backward compatibility
Trivially safe. UI today shows no name → old rows continue showing nothing → upgrade adds name only for new logins. No migration needed for existing PATs (display fallback covers).
Scope split
- This issue: CLI sends
device_label during ox login
- Backend work (sageox-monorepo): DB migration + endpoint accepts field + response includes
name + UI renders
- File as separate sageox-monorepo issue once CLI shape agreed
Out of scope
Origin
Spun out of #577 triage 2026-05-27.
Problem
/settings/security"ox CLI sessions" lists every PAT minted byox login. Users with many machines (laptop, desktop, devcontainer, CI) cannot tell which row maps to which machine — only Created/Last-used/Expires timestamps are shown.Underlying cause: PAT names are timestamp-only.
DB schema has no
namecolumn; wire (cliSessionResponse) omits one even if added.Goal
User can scan the CLI sessions list and immediately identify the machine to revoke.
Proposed shape
ox CLI (this repo)
During
ox logindevice-flow token exchange, send adevice_labelfield:Privacy:
SAGEOX_NO_DEVICE_LABEL=1user@hostif explicitBackend (sageox-monorepo)
name texttogitlab_pats(nullable for back-compat)device_labelin device-flow token exchange endpointsageox-cli-<label>-<timestamp>→sageox-cli-ryan@tacoma-20260527-143022gitlab_pats.name, mirror to GitLab PAT namename string \json:"name"`tocliSessionResponse`Web UI (sageox-monorepo)
apps/web/src/components/settings/security/CliSessionsList.tsx:session.nameas primary headingnameis null (covers old rows — back-compat)Backward compatibility
Trivially safe. UI today shows no name → old rows continue showing nothing → upgrade adds name only for new logins. No migration needed for existing PATs (display fallback covers).
Scope split
device_labelduringox loginname+ UI rendersOut of scope
Origin
Spun out of #577 triage 2026-05-27.