Skip to content

fix(identity): ask for credentials on the next sign-in after signing out - #3231

Merged
loganj merged 3 commits into
mainfrom
larry/signout-force-login
Nov 11, 2026
Merged

loganj merged 3 commits into
mainfrom
larry/signout-force-login

Conversation

@loganj

@loganj loganj commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • After Sign out of an organization server, or Switch account (which signs out first), the next sign-in went through the browser's live session at that server. It finished in one click as the same account, so the user couldn't choose another one.
  • The sign-in start URL added prompt=login only when the caller asked for it, and only first run's Use a different account did.
  • Now native owns the rule: an explicit sign-out marks that server, and its next sign-in sends prompt=login whatever the caller passes, which asks the sign-in provider to authenticate again. The provider decides what the browser shows; this doesn't end the browser's session there. Only a completed browser sign-in clears the mark. The mark survives a restart, so sign out, quit, then sign in still asks for credentials. Expiry, refusals and close don't set it, so renewing the same account stays one click. No UI change.

Details

  • src-tauri/src/federated_identity/mod.rs:
    • State::force_login holds the mark. begin_sign_out sets it, in the same lock as the retirement. Both explicit sign-out paths use it: the plain one and AgentTokens::sign_out.
    • Only a completed browser sign-in clears it (finish_login, in the same lock). A session restored from another Buzz copy takes the mark from the file as it is (reread_signed_out): that session may have been checked before another copy's sign-out, so a restore never erases the mark. A sign-in that a sign-out superseded never installs, so it never clears a newer mark. A failed or canceled sign-in keeps it.
    • sign_in applies it when it admits the attempt (State::asking). The caller's signup hint stays.
    • The mark is kept in <account>.signed-out beside the server's FI records, the same pattern as the .customers list. It is written or removed in the state lock, so the file follows the order of sign-outs and installs. A launch reads it in build. Tests pass no path, as with Customers.
    • A failed write still asks for credentials until the app quits or restores a session. A failed removal asks once more after a restart or restore. Neither changes the session.
  • docs/identity.md and docs/buzz-help.md describe the rule.
  • Tests:
    • A sign-out marks the server and keeps the caller's sign-up hint. A restarted server still asks, and a completed sign-in clears the mark and the file.
    • A session restored from another copy keeps the mark and the file. A copy that signed out stops asking once another copy's browser sign-in has removed the file.
    • Race: copy B reads the shared session, copy A signs out, then B's verification answers. B installs the session, the mark stays, and a fresh launch's production sign-in URL has prompt=login.
    • The production sign_in start URL has prompt=login after a sign-out and after a restart, and not before a sign-out.
    • Expiry and close leave the next sign-in without prompt=login.

Known limits

  • Sign out of Buzz removes the FI records but leaves an existing mark, so a sign-in after it still asks for credentials. It doesn't add a mark (out of scope here).
  • Other Buzz copies with the same profile share the file but each holds its own in-memory mark, so a copy that was already running learns about another copy's sign-out at its next launch.
  • Not tried against a live sign-in server. The test fixtures check the mark, and the existing login-start test checks that force_login adds prompt=login.

🤖 Generated with Claude Code

loganj and others added 2 commits November 10, 2026 15:04
An explicit sign-out of an organization server now marks it, and its next
sign-in sends prompt=login whatever the caller passes, so the browser's
session can't finish it as the account just signed out. A completed
sign-in clears the mark. The mark is kept beside the server's records, so
it survives a restart. Expiry, refusals and close don't set it.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Logan Johnson <[email protected]>
A session restored from another Buzz copy is also the chosen account, so
it clears the mark too; before, the next renewal still asked for
credentials. The docs now say prompt=login asks the provider to
authenticate again, which doesn't end the browser's session.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Logan Johnson <[email protected]>
@loganj
loganj marked this pull request as ready for review November 11, 2026 18:55
@loganj
loganj requested a review from a team as a code owner November 11, 2026 18:55
kalvinnchau

This comment was marked as resolved.

Review: copy B could read the shared session, copy A then signed out and
wrote the mark, and B's late verification installed the session and
removed A's mark. The next launch then had no session and no mark, so
its sign-in skipped prompt=login.

Only a completed browser sign-in now removes the mark. A restored
session takes the mark from the file as it is. Tests cover that race and
the production sign-in URL after a sign-out and a restart.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Logan Johnson <[email protected]>

@kalvinnchau kalvinnchau left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Reviewed at 77d63c6. Both previous findings are resolved; no new actionable findings.

Restoring an existing session now preserves and rereads the sign-out marker, while guarded completion of a browser login owns clearing it. The added regressions exercise the production sign-in URL and the stale-restore/sign-out interleaving. All 151 identity tests passed; controls that reintroduced marker deletion, bypassed request policy, or removed clearing/rereading failed as expected. Eight isolated host-integration probes also passed.

The documented already-running-copy cache limitation remains. Full local package validation was incomplete due to a terminal-environment failure and subsequent SIGSEGV, with attribution to this change unestablished. Native UI, real provider/OS credential storage, and actual process restart/concurrency remain unverified. Approved with these validation limitations noted.

@loganj
loganj merged commit 8b07ca6 into main Nov 11, 2026
46 checks passed
@loganj
loganj deleted the larry/signout-force-login branch November 11, 2026 21:12
joahg added a commit to joahg/buzz-app that referenced this pull request Nov 11, 2026
* origin/main:
  fix(identity): show a backed-up key as backed up, and drop dead retries (block#3223)
  fix(browser): open Builderlab account connections in the system browser (block#3287)
  Expose exact captured-message reads (block#3264)
  docs(agents): keep internal discussion out of public repo content (block#3258)
  fix(identity): clear a copied private key, name restore failures, fix storage copy (block#3236)
  fix(channels): list workspaces that load after `#` opens (block#3277)
  feat(profiles): show a larger avatar in the hover profile preview (block#3232)
  fix(identity): ask for credentials on the next sign-in after signing out (block#3231)
  fix(relay): keep saved channels when the community refuses sign-in (block#3215)

Signed-off-by: Joah Gerstenberg <[email protected]>
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.

2 participants