fix(auth): honor BW_CLIENT_SECRET past login, not just at login - #51
Merged
Merged
Conversation
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.
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
matthewkmartin
approved these changes
Sep 25, 2026
joshraub-bw
approved these changes
Sep 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 writesconfig.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 vialoadConfigAndAuth(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 sameBW_CLIENT_SECRETthat worked for login.band auth statushas the same gap: it reportsauthenticated: falseunderBW_CLIENT_SECRETright before every other command would have worked using that same env var.Why
Found this running an internal PoC (agent-driven
bandCLI +mcp-serverusage against a live Bandwidth Build account, on a headless Linux box with no desktop environment). Getting pastauth loginrequired unpackingdbus-x11/gnome-keyring.debfiles 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 ofBW_CLIENT_ID/BW_CLIENT_SECRETas "no TTY required" / "headless and CI/CD"-friendly (see README's "Headless and CI/CD" section).What changed
internal/cmdutil/helpers.go—loadConfigAndAuthnow checksBW_CLIENT_SECRETbefore falling back to the keychain, mirroring howBW_CLIENT_IDis already overlaid byconfig.ActiveProfileConfig.cmd/auth/status.go—authenticatednow agrees with what every other command will actually do: true if either the keychain has the secret orBW_CLIENT_SECRETis set, not keychain-only.auth loginor the env vars).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_SECRETis present.Testing
go build ./...,go vet ./...,go test ./...— full suite passes, no regressions.BW_CLIENT_SECRETset,band app listnow 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.