Skip to content

Commit f291919

Browse files
Programcodeclaude
andcommitted
Keep a newer sign-in when the restored stored account turns out dead
Follow-up review of 074c9fe (Low): the guard that keeps an account signed in during the stored session's check ran only for a live stored account. It now runs before the dead branch's drop as well. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 074c9fe commit f291919

2 files changed

Lines changed: 29 additions & 6 deletions

File tree

‎src/lib/supabase/AuthProvider.tsx‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -227,15 +227,15 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
227227
if (!mounted) return;
228228
const { data, error } = getSessionResult;
229229
if (error) console.warn('[Auth] getSession error:', error.message);
230-
if (data.session?.access_token && !(await confirmRestoredSession(data.session.access_token))) {
231-
if (!mounted) return;
232-
dropRestoredSession();
233-
return;
234-
}
230+
const alive = data.session?.access_token ? await confirmRestoredSession(data.session.access_token) : true;
235231
if (!mounted) return;
236-
// Someone else signed in while this was checked: theirs stands.
232+
// Someone else signed in while this was checked: theirs stands, alive or not.
237233
const current = currentUserIdRef.current;
238234
if (current && current !== data.session?.user.id) return;
235+
if (!alive) {
236+
dropRestoredSession();
237+
return;
238+
}
239239
if (data.session) {
240240
applySession(data.session);
241241
} else {

‎src/test/auth/AuthProvider.behavior.test.tsx‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,29 @@ describe('AuthProvider behavior', () => {
954954
expect(screen.getByTestId('user')).toHaveTextContent('new-user');
955955
});
956956

957+
it('does not drop an account signed in while a dead stored account was being checked', async () => {
958+
getSessionMock.mockResolvedValue({ data: { session: { user: { id: 'stored-user' }, access_token: 'stored' } }, error: null });
959+
let answerLookup!: (value: unknown) => void;
960+
getUserMock.mockImplementationOnce(() => new Promise((resolve) => { answerLookup = resolve; }));
961+
962+
render(
963+
<AuthProvider>
964+
<AuthConsumer />
965+
</AuthProvider>
966+
);
967+
968+
await waitFor(() => expect(getUserMock).toHaveBeenCalled());
969+
await act(async () => {
970+
callbackRef.current?.('SIGNED_IN', { user: { id: 'new-user' }, access_token: 'new-token' });
971+
});
972+
await act(async () => {
973+
answerLookup({ data: { user: null }, error: { status: 401, message: 'revoked' } });
974+
});
975+
976+
await waitFor(() => expect(screen.getByTestId('loading')).toHaveTextContent('false'));
977+
expect(screen.getByTestId('user')).toHaveTextContent('new-user');
978+
});
979+
957980
it('does not hold startup on a sign-out of a dead stored session that never answers', async () => {
958981
vi.useFakeTimers();
959982
try {

0 commit comments

Comments
 (0)