Skip to content

[Bug] No way to choose which account Buzz signs in with — browser-handoff auth silently reuses the existing browser session #2802

Description

@AirZona

Describe the bug

Buzz Desktop's browser-handoff sign-in gives no way to choose which account you authenticate as. The login URL is opened in the default browser with no prompt parameter, so the identity provider silently reuses whatever session the browser already has and returns straight to Buzz — the Google account chooser never appears.

I hit this with an agent that is supposed to reach Google APIs under my company Workspace account. My Buzz sign-in is tied to my personal Gmail, that is the session my default browser holds, and every subsequent permission prompt silently binds to the personal account. There is no in-app way to say "use the other account".

Signing out does not help, because sign-out is local-only: clear_builderlab_auth just drops the in-memory session, and nothing clears (or bypasses) the IdP session in the browser.

// 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(())
}

So Sign out → Sign in is a no-op round trip: the browser re-authenticates the same account without ever showing a picker.

To Reproduce:

  1. In a browser profile signed into a personal Google account, sign in to Buzz Desktop (Settings → Hosted communities → Sign in with Builderlab). Complete the flow with the personal account.
  2. Set up an agent that needs Google API access under a different (company Workspace) account.
  3. Trigger the authorization prompt.
  4. The browser goes straight through on the personal account. No account chooser is shown.
  5. Click Sign out in Buzz, then Sign in with Builderlab again → still the personal account, still no chooser.

Expected behavior:

  • Authentication offers an account chooser rather than inheriting the browser session, or at minimum Buzz exposes an explicit "Use a different account" affordance that forces one.
  • Sign out → Sign in lets you land on a different account.
  • The account an agent authorizes against is not implicitly pinned to the account the Buzz app itself was signed in with.

Root cause (code references)

login_url() builds the authorization URL with only type, product and returnTo — no prompt, so the IdP applies its default of reusing an existing session:

// desktop/src-tauri/src/builderlab.rs:217
fn login_url(return_to: &str) -> Result<Url, String> {
    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)
}

It is handed to the OS browser as-is at desktop/src-tauri/src/builderlab.rs:279:

if let Err(error) = app.opener().open_url(login_url.as_str(), None::<&str>) {

The same gap exists in the generic PKCE flow used by buzz-agent, which builds its authorize URL with no prompt and no way for a caller to add one:

// crates/buzz-agent/src/auth.rs:589
"{}?response_type=code&client_id={}&redirect_uri={}&scope={}&state={}&code_challenge={}&code_challenge_method=S256",

PkceOAuthConfig (crates/buzz-agent/src/auth.rs:98) has no field for extra authorization parameters, so no caller can opt into an account chooser. Its on-disk token cache is also keyed on sha256(discovery_url|client_id|scopes) (cache_path_for, crates/buzz-agent/src/auth.rs:445) — the authenticated account is not part of the key, so one machine cannot hold tokens for two accounts of the same provider even once a chooser exists.

Proposed fix

  1. Add prompt=select_account to the authorization URL when the user explicitly asks to switch accounts, and surface that as a "Use a different account" action next to Sign out in HostedCommunitiesSettingsCard.
  2. Give PkceOAuthConfig an optional set of extra authorization-endpoint parameters so a provider can request prompt=select_account, and have interactive_login() (an explicit, user-initiated re-auth) request it by default.
  3. Longer term: include the authenticated account identity in the OAuth cache key so tokens for two accounts of the same provider can coexist.

Happy to open a PR for 1 and 2 — 3 is a larger change and probably wants a maintainer opinion on cache-key migration first.

Environment (please complete the following information):

  • OS: macOS 26.5.2 (Apple silicon)
  • Buzz Desktop: 0.4.25
  • Runtime: buzz-acp + claude-agent-acp

Additional context

The IdP in this path is Auth0 in front of Google, so the exact parameter that reaches Google may depend on Builderlab's upstream connection config — prompt=select_account needs to be forwarded to the Google connection to have the intended effect. Flagging that in case the fix needs a server-side counterpart rather than only a Desktop change.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions