From 343e7c9b89efac62e0ada6f988975bed394694a8 Mon Sep 17 00:00:00 2001 From: lingniu Date: Sun, 19 Jul 2026 11:27:34 +0800 Subject: [PATCH] fix: hide expired session token errors on login --- .../apps/web/src/v2/auth/AuthGate.test.tsx | 13 +++++++++++++ .../apps/web/src/v2/auth/AuthGate.tsx | 7 ++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.test.tsx b/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.test.tsx index 5218874f..ccdf763b 100644 --- a/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.test.tsx +++ b/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.test.tsx @@ -105,6 +105,19 @@ test('exposes only account and password login on the public sign-in screen', asy expect(screen.getByRole('button', { name: '登录工作台' })).toBeDisabled(); }); +test('silently clears an expired stored session without exposing token errors on the account login page', async () => { + const client = new QueryClient({ defaultOptions: { queries: { retry: false } } }); + setAccessToken('expired-session-token'); + mocks.session.mockRejectedValue(new Error('需要有效的访问令牌')); + + render( undefined} />); + + expect(await screen.findByRole('form', { name: '账号密码登录' })).toBeInTheDocument(); + expect(screen.queryByRole('alert')).not.toBeInTheDocument(); + expect(screen.queryByText(/访问令牌/)).not.toBeInTheDocument(); + await waitFor(() => expect(getAccessToken()).toBe('')); +}); + test('an expired protected request returns to login and removes the active user cache', async () => { mocks.logout.mockResolvedValue({ loggedOut: true }); const client = new QueryClient({ defaultOptions: { queries: { retry: false } } }); diff --git a/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.tsx b/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.tsx index c77dc465..41baaad0 100644 --- a/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.tsx +++ b/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.tsx @@ -107,6 +107,11 @@ export function AuthGate({ children }: { children: ReactNode }) { window.addEventListener(PLATFORM_UNAUTHORIZED_EVENT, finishLogout); return () => window.removeEventListener(PLATFORM_UNAUTHORIZED_EVENT, finishLogout); }, [finishLogout]); + useEffect(() => { + if (!session.isError || loginPending || loginError || !getAccessToken()) return; + clearAccessToken(); + setAttempted(false); + }, [loginError, loginPending, session.isError]); const login = async (event: FormEvent) => { event.preventDefault(); @@ -129,7 +134,7 @@ export function AuthGate({ children }: { children: ReactNode }) { return ; } if (!session.data) { - const error = loginError || (attempted && session.error ? session.error.message : ''); + const error = loginError || (attempted && session.error && !getAccessToken() ? session.error.message : ''); return