Summary
urlbox login writes the session token to the config file before it resolves the active org. When the org step fails, the command exits 1 as a usage error while the session is already persisted — so a login that reports total failure has actually half-succeeded, and the single-use device code has been consumed.
Reproduce
-
Have an account with two or more organisations.
-
Run login without a TTY and without --org (an agent, CI, or simply a pipe):
-
Approve the printed code in the browser.
-
The command prints:
Error: multiple organisations and no interactive terminal
Hint: Pass --org <name-or-id> to choose one non-interactively.
and exits 1.
Expected
Either the session is rolled back so exit 1 means "not signed in", or the command exits 0 with a warning that the org still needs picking.
Actual
Exit 1, but the session is live:
$ urlbox whoami
{"ok": true, "data": {"email": "…", "org": {...}, "project": null}}
~/.config/urlbox/config.json contains session_token but no active_org.
Because the device code is single-use, treating exit 1 as "it failed" and re-running urlbox login costs a second browser approval that was never necessary.
Cause
internal/cmd/login.go:133 persists the token:
if cliErr := updateProfile(profileName, func(p *config.Profile) { p.SessionToken = token }); cliErr != nil {
internal/cmd/login.go:138 then resolves the org, which is what fails:
org, orgErr := resolveActiveOrg(ctx, authed, f.org, promptPick)
The write is committed before the step that can fail.
Workaround
urlbox login --org <name-or-id> skips the picker. After hitting the failure, the session is usable — urlbox orgs select <name> finishes the job without re-authenticating.
Environment
urlbox 1.2.0 (commit 5530665), Linux.
Summary
urlbox loginwrites the session token to the config file before it resolves the active org. When the org step fails, the command exits 1 as a usage error while the session is already persisted — so a login that reports total failure has actually half-succeeded, and the single-use device code has been consumed.Reproduce
Have an account with two or more organisations.
Run login without a TTY and without
--org(an agent, CI, or simply a pipe):urlbox login | catApprove the printed code in the browser.
The command prints:
and exits 1.
Expected
Either the session is rolled back so exit 1 means "not signed in", or the command exits 0 with a warning that the org still needs picking.
Actual
Exit 1, but the session is live:
$ urlbox whoami {"ok": true, "data": {"email": "…", "org": {...}, "project": null}}~/.config/urlbox/config.jsoncontainssession_tokenbut noactive_org.Because the device code is single-use, treating exit 1 as "it failed" and re-running
urlbox logincosts a second browser approval that was never necessary.Cause
internal/cmd/login.go:133persists the token:internal/cmd/login.go:138then resolves the org, which is what fails:The write is committed before the step that can fail.
Workaround
urlbox login --org <name-or-id>skips the picker. After hitting the failure, the session is usable —urlbox orgs select <name>finishes the job without re-authenticating.Environment
urlbox 1.2.0(commit 5530665), Linux.