block / block/buzz

[Bug] No way to sign into Buzz Desktop as a different account — browser session is reused and sign-out is local-only

Open
#2,802 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.