Skip to content

fix(auth): clear the previous account's persisted state when a different account signs in - #1287

Open
JamieRuderman wants to merge 7 commits into
mainfrom
fix/account-switch-stale-state
Open

JamieRuderman wants to merge 7 commits into
mainfrom
fix/account-switch-stale-state

Conversation

@JamieRuderman

@JamieRuderman JamieRuderman commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Problem

Sign-out resets every persisted model, but switching accounts never signs out. Activating a saved account, the add-account chooser, the desktop deep-link callback and a support launch all reload or redirect without calling signedOut. redux-persist then rehydrates the previous account's devices, accounts, selected organization, connections, announcements and more under the new account until each fetch replaces them.

Seen in practice: after switching from jamie@remote.it to a test account in the same browser, the test account ran on Jamie's persisted state.

Change

  • Owner check at sign-in: auth.fetchUser compares the persisted user.id with the account that just signed in. When they differ, or when no owner was recorded, it runs resetAccountData() before auth.user is set, so nothing renders from another account's data. Every switch path reaches this point.
  • Waits for rehydration: auth.init isn't gated on redux-persist, so the check waits for the persistor to bootstrap before reading the owner.
  • Owner stamped immediately: user.id is written at sign-in instead of when the cloud sync's user.fetch lands. A second quick switch still sees an owner.
  • One reset list: resetAccountData() resets every persisted model, chat included, and signedOut uses it too. The persist whitelist moved to PERSISTED_MODELS, and a test fails if the two drift apart.
  • Chat popouts: whenever the check resets, the sign-out broadcast closes open chat popouts without a handback, so the old account's transcript can't be handed to the new one.
  • Main windows only: popouts and support tabs persist nothing, so they skip the check. Their empty store says nothing about other windows, and they must not close other windows' popouts. persistsState in store.ts is the one flag for both the storage choice and the check.
  • Support tabs: a support tab no longer persists. It was writing the customer's data into the operator's own stored state, and a support sign-out purged the operator's cache.

Not covered

Other already-open web tabs keep the previous account's in-memory state until they reload, because sign-in tokens are shared across the browser. That predates this change and would need tabs to signal each other.

Testing

  • New auth model tests cover the owner mismatch, same owner, empty owner, the rehydration wait and the reset coverage. The rehydration test was checked to fail without the wait.
  • npm test -w=frontend and npm run typecheck pass.

@JamieRuderman

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-09T20:13:38.337810Z 2fc85fd Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

…ale-state

# Conflicts:
#	frontend/src/models/auth.test.ts
@aws-amplify-us-west-1

Copy link
Copy Markdown

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-1287.d20k671nqqv4kl.amplifyapp.com

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c643950bef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread frontend/src/models/auth.ts Outdated
// Switching accounts reloads without signing out, so persisted state and open chat popouts can be the last account's.
await rehydrated()
const owner = store.getState().user.id
if (owner && user?.id && owner !== user.id) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Clear persisted state when the owner marker is empty

When the previous account's user.fetch failed or never completed, user.id remains empty even though independently fetched models such as accounts, devices, and organizations can already be persisted. This condition treats that cache as safe, skips every reset, and then line 312 stamps the new account's ID onto it, so the previous account's data can render under the new account and future boots will no longer detect the mismatch. An absent owner must be treated as untrusted persisted state rather than implicitly belonging to the signing-in account.

Useful? React with 👍 / 👎.

@JamieRuderman

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d21a913c2e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread frontend/src/models/auth.ts Outdated
const owner = store.getState().user.id
if (user?.id && owner !== user.id) {
auth.resetAccountData()
if (owner) broadcastChatSignout()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Close popouts when replacing an unowned cache

When the previous account's user.fetch failed or had not completed, user.id can be empty even though that account already opened a chat popout. This branch now resets the main window but suppresses the sign-out broadcast, so after the account-switch reload the old popout remains paired through the main tab's session-storage owner ID and can later hand its previous account's transcript back into the new account. Distinguish main windows from support/popout windows when deciding whether to broadcast rather than using owner truthiness.

Useful? React with 👍 / 👎.

@JamieRuderman

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: 2fc85fdec0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

This branch has not been deployed

No deployments
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.

1 participant