Skip to content

fix(auth): honor BW_CLIENT_SECRET past login, not just at login - #51

Merged
michaela-band merged 1 commit into
mainfrom
fix/headless-auth-env-var-secret
Sep 25, 2026
Merged

michaela-band merged 1 commit into
mainfrom
fix/headless-auth-env-var-secret

Conversation

@michaela-band

Copy link
Copy Markdown
Contributor

What

band auth login --client-id X --client-secret Y (or the equivalent env vars) succeeds with no OS keychain available — it verifies the credentials and writes config.json; storing the secret in the keychain is a separate, best-effort step. But every command after login reads the secret exclusively from the keychain via loadConfigAndAuth (internal/cmdutil/helpers.go), with no env var fallback.

On a host with no D-Bus/keyring stack (containers, most headless CI runners), that means: login succeeds, and then every single subsequent command fails with credentials not found in keychain — even though the caller still has the same BW_CLIENT_SECRET that worked for login. band auth status has the same gap: it reports authenticated: false under BW_CLIENT_SECRET right before every other command would have worked using that same env var.

Why

Found this running an internal PoC (agent-driven band CLI + mcp-server usage against a live Bandwidth Build account, on a headless Linux box with no desktop environment). Getting past auth login required unpacking dbus-x11/gnome-keyring .deb files and hand-rolling a local D-Bus session + keyring daemon just to get one command to fully round-trip — which undercuts the CLI's own pitch of BW_CLIENT_ID/BW_CLIENT_SECRET as "no TTY required" / "headless and CI/CD"-friendly (see README's "Headless and CI/CD" section).

What changed

  • internal/cmdutil/helpers.go — loadConfigAndAuth now checks BW_CLIENT_SECRET before falling back to the keychain, mirroring how BW_CLIENT_ID is already overlaid by config.ActiveProfileConfig.
  • cmd/auth/status.go — authenticated now agrees with what every other command will actually do: true if either the keychain has the secret or BW_CLIENT_SECRET is set, not keychain-only.
  • Failure error message now mentions both remediation paths (auth login or the env vars).
  • Added tests for both: TestLoadConfigAndAuth_BW_CLIENT_SECRET_SkipsKeychain, TestLoadConfigAndAuth_NoSecretNoKeychain_ReturnsActionableError, TestStatusPlainAuthenticatedViaEnvSecret.

No behavior change for the normal desktop keychain flow — this only changes what happens when the keychain lookup fails and BW_CLIENT_SECRET is present.

Testing

  • go build ./..., go vet ./..., go test ./... — full suite passes, no regressions.
  • Manually reproduced the bug and confirmed the fix on a real headless box: with a fake client ID that has no keychain entry and BW_CLIENT_SECRET set, band app list now reaches Bandwidth's token endpoint (and correctly gets a 401 for the fake secret) instead of failing on the keychain lookup before ever making a network call.

Flagging for review rather than assuming this is the right shape of fix — happy to adjust if there's a reason the keychain-only behavior for post-login commands was intentional beyond the login-time verification.

band auth login accepts BW_CLIENT_ID/BW_CLIENT_SECRET and works fine with
no OS keychain available — it verifies credentials and writes config.json,
and keychain storage is a separate, best-effort step. But every command
after login (including auth status) reads the secret exclusively from the
keychain via loadConfigAndAuth, with no env var fallback. On a host with
no D-Bus/keyring stack (any container, most headless CI runners, this box),
that means login succeeds and then every single subsequent command fails
with 'credentials not found in keychain' -- even though the caller still
has the same BW_CLIENT_SECRET that worked for login.

Found while running an internal PoC against a real Bandwidth Build account
on a headless Linux host: auth login needed hand-rolling a local D-Bus
session + gnome-keyring daemon from unpacked .deb files just to get past
step one, and even then band auth status reported authenticated:false
with BW_CLIENT_SECRET correctly set, right before every other command
would have worked using that same env var.

- loadConfigAndAuth (internal/cmdutil/helpers.go): check BW_CLIENT_SECRET
  before falling back to the keychain, mirroring how BW_CLIENT_ID is
  already overlaid by config.ActiveProfileConfig.
- auth status (cmd/auth/status.go): authenticated now agrees with what
  every other command will actually do -- true if either the keychain
  has the secret or BW_CLIENT_SECRET is set, not keychain-only.
- Error message on failure now mentions both remediation paths.

No behavior change for the normal desktop keychain flow.
@michaela-band
michaela-band requested review from a team as code owners September 24, 2026 14:39
@bwappsec

bwappsec commented Sep 24, 2026 •

Copy link
Copy Markdown

✅ Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
✅ Open Source Security 0 0 0 0 0 issues
✅ Licenses 0 0 0 0 0 issues
✅ Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@michaela-band
michaela-band merged commit 704602c into main Sep 25, 2026
8 checks passed
@michaela-band
michaela-band deleted the fix/headless-auth-env-var-secret branch September 25, 2026 15:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants