[Bug] No way to sign into Buzz Desktop as a different account — browser session is reused and sign-out is local-only
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
> **Edited after further investigation.** The original report attributed a symptom I hit with an agent to this login path. I've since verified parts of it and disproven part of my own proposed fix, so I've split this into what I can demonstrate and what I only assumed. The unverified part is at the bottom. Sorry for the reshuffle — I'd rather correct it than leave a confident-sounding guess in the tracker.
## Verified: you cannot sign into Buzz Desktop as a different account
**1. The login URL carries no `prompt`, so the identity provider reuses the browser's existing session.**
```rust
// desktop/src-tauri/src/builderlab.rs:217
fn login_url(return_to: &str) -> Result {
let mut login_url = api_url("/v1/auth/login")?;
login_url
.query_pairs_mut()
.append_pair("type", "cli")
.append_pair("product", "buzz")
.append_pair("returnTo", return_to);
Ok(login_url)
}
```
Per OIDC, omitting `prompt` permits the provider to reuse an authenticated session. The URL is handed to the OS browser as-is (`builderlab.rs:279`), so whichever account that browser holds is the account you get, with no chooser.
**2. Signing out cannot fix it, because sign-out is local-only.**
```rust
// desktop/src-tauri/src/builderlab.rs:407
pub(crate) fn clear_builderlab_auth(
session: tauri::State<'_, BuilderlabSession>,
) -> Result<(), String> {
*session.0.lock().map_err(|error| error.to_string())? = None;
Ok(())
}
```
This drops Buzz's in-memory session and cannot touch the browser's IdP session. **Sign out → Sign in is therefore a no-op round trip** that re-authenticates the same account. There is no path in the app to land on a different one.
**3. The obvious client-side fix does not work — the parameter is stripped server-side.**
I tried the natural fix (send `prompt=select_account`) and verified against the live endpoint that it never arrives. `/v1/auth/login` builds its own Auth0 URL and allowlists what it forwards:
| sent to `/v1/auth/login` | reaches Auth0 |
|---|---|
| `screen_hint=signup` | ✅ |
| `prompt=select_account` | ❌ |
| `prompt=login` | ❌ |
| `login_hint=…` | ❌ |
```
$ curl -sI "https://app.builderlab.xyz/api/goose/v1/auth/login?type=cli&product=buzz&prompt=select_account&returnTo=http%3A%2F%2F127.0.0.1%3A9999%2Fcb" | grep -i location
location: https://login.builderlab.xyz/authorize?client_id=…&scope=openid+profile+email&state=…&code_challenge_method=S256&organization=org_…&ext-product=buzz
```
`screen_hint` being the one that passes is presumably why `login_defaults_to_auth0_login` asserts on its absence today.
**So a Desktop-only fix isn't possible here.** `prompt` needs adding to that server-side passthrough first; after that the Desktop change is small, and I have it written already.
**4. Same gap, no server in the way, in `buzz-agent`.** `browser_pkce_flow` builds its authorize URL with no `prompt` and no way for a caller to add one (`crates/buzz-agent/src/auth.rs:589`), and `PkceOAuthConfig` has no field for extra authorization parameters. This one is fixable client-side because it hits the provider's authorization endpoint directly — #2821 does that.
**5. The OAuth token cache can't hold two accounts.** `cache_path_for` keys on `sha256(discovery_url|client_id|scopes)` (`crates/buzz-agent/src/auth.rs:445`); the authenticated account isn't part of the key, so even once a chooser exists, one machine can't keep tokens for two accounts of the same provider.
## Repro (items 1–2)
1. In a browser signed into account A, sign in to Buzz Desktop via **Settings → Hosted communities → Sign in with Builderlab**.
2. Click **Sign out**, then **Sign in with Builderlab** again.
3. You're back as account A. No chooser appears at any point.
## Environment
- macOS 26.5.2 (Apple silicon), Buzz Desktop 0.4.25
- Runtime: `buzz-acp` + `claude-agent-acp`
## Unverified: what originally sent me looking
I hit this while trying to get an agent to reach Google APIs under my company Workspace account, while my Buzz sign-in is tied to a personal Google account — every permission prompt bound to the personal one, with no chance to switch. I assumed the two were the same root cause. **I have not proven that**, and it may well be a separate problem: I never captured the `client_id` from the consent screen I saw, so I can't say which component requested it, and I haven't confirmed the Builderlab tenant offers a Google connection at all.
Items 1–5 above stand on their own regardless — they're read off the source and the live endpoint. Treat the agent scenario as the motivation for the report, not as a diagnosed cause. If it'd help, I can capture the actual consent URL next time it happens and file that separately.
Contributor guide
Research direction
Start with desktop/src-tauri/src/builderlab.rs at login_url and clear_builderlab_auth, then read crates/buzz-agent/src/auth.rs at browser_pkce_flow and cache_path_for. Reproduce the sign-out/sign-in flow and inspect the login_defaults_to_auth0_login assertion and endpoint behavior. Done should include an agreed account-switching flow across the affected clients and verification that token caching does not prevent separate accounts.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- authentication, backend-api-design, desktop
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100