From 4427ab1f85d1a172e0a024d7796953b6887bed58 Mon Sep 17 00:00:00 2001 From: chan Date: Tue, 21 Apr 2026 17:06:03 +0900 Subject: [PATCH] fix: resolve admin session infinite reload loop and sync auth state - Prevent infinite redirection loop by clearing oidc-client user state on 401 errors. - Sync apiClient request interceptor to use userManager.getUser() for reliable token retrieval. - Add extensive console logs for better session issue diagnosis. - Fix TS error in LoginPage by updating button variant. - Revert 'ae03fe1' (updated playwright fixtures to real domain) as requested. --- .../src/components/layout/AppLayout.tsx | 22 ++++++++++++-- .../src/features/auth/AuthCallbackPage.tsx | 10 +++++-- adminfront/src/features/auth/LoginPage.tsx | 12 ++++++-- adminfront/src/lib/apiClient.ts | 29 +++++++++++++++---- adminfront/src/lib/sessionSliding.ts | 24 +++++++++++++-- adminfront/tests/auth.spec.ts | 14 ++++----- adminfront/tests/bulk_actions.spec.ts | 4 +-- adminfront/tests/owners.spec.ts | 4 +-- adminfront/tests/tenants.spec.ts | 4 +-- adminfront/tests/users.spec.ts | 14 ++++----- adminfront/tests/users_bulk.spec.ts | 4 +-- adminfront/tests/users_schema.spec.ts | 14 ++++----- devfront/tests/helpers/devfront-fixtures.ts | 16 +++++----- 13 files changed, 119 insertions(+), 52 deletions(-) diff --git a/adminfront/src/components/layout/AppLayout.tsx b/adminfront/src/components/layout/AppLayout.tsx index 9f42e384..3cf40297 100644 --- a/adminfront/src/components/layout/AppLayout.tsx +++ b/adminfront/src/components/layout/AppLayout.tsx @@ -80,9 +80,19 @@ function AppLayout() { }; }, []); - const { data: profile } = useQuery({ + const { data: profile, isLoading: isProfileLoading, error: profileError } = useQuery({ queryKey: ["me"], - queryFn: fetchMe, + queryFn: async () => { + console.debug("[AppLayout] Fetching profile..."); + try { + const data = await fetchMe(); + console.debug("[AppLayout] Profile fetched successfully:", data.email); + return data; + } catch (err) { + console.error("[AppLayout] Failed to fetch profile:", err); + throw err; + } + }, enabled: (auth.isAuthenticated && !auth.isLoading) || import.meta.env.MODE === "development" || @@ -170,7 +180,15 @@ function AppLayout() { const isTest = (window as Window & typeof globalThis & { _IS_TEST_MODE?: boolean }) ._IS_TEST_MODE === true; + + console.debug("[AppLayout] Auth state check:", { + isLoading: auth.isLoading, + isAuthenticated: auth.isAuthenticated, + isTest + }); + if (!auth.isLoading && !auth.isAuthenticated && !isTest) { + console.warn("[AppLayout] Not authenticated, redirecting to /login"); navigate("/login"); } }, [auth.isLoading, auth.isAuthenticated, navigate]); diff --git a/adminfront/src/features/auth/AuthCallbackPage.tsx b/adminfront/src/features/auth/AuthCallbackPage.tsx index ed1e0630..b6c711d7 100644 --- a/adminfront/src/features/auth/AuthCallbackPage.tsx +++ b/adminfront/src/features/auth/AuthCallbackPage.tsx @@ -8,6 +8,11 @@ function AuthCallbackPage() { const navigate = useNavigate(); useEffect(() => { + console.debug("[AuthCallbackPage] State:", { + isAuthenticated: auth.isAuthenticated, + isLoading: auth.isLoading, + error: auth.error + }); if (auth.isAuthenticated) { // Save token to localStorage for existing API clients that might still use it const user = auth.user; @@ -21,12 +26,13 @@ function AuthCallbackPage() { typeof auth.user.state.returnTo === "string" ? auth.user.state.returnTo : "/"; + console.info("[AuthCallbackPage] Auth successful, navigating to", returnTo); navigate(returnTo, { replace: true }); } else if (auth.error) { - console.error("Auth Error:", auth.error); + console.error("[AuthCallbackPage] Auth Error:", auth.error); navigate("/login", { replace: true }); } - }, [auth.isAuthenticated, auth.error, navigate, auth.user]); + }, [auth.isAuthenticated, auth.error, navigate, auth.user, auth.isLoading]); return (
diff --git a/adminfront/src/features/auth/LoginPage.tsx b/adminfront/src/features/auth/LoginPage.tsx index 3c46ac63..42f560ad 100644 --- a/adminfront/src/features/auth/LoginPage.tsx +++ b/adminfront/src/features/auth/LoginPage.tsx @@ -20,10 +20,16 @@ function LoginPage() { const shouldAutoLogin = searchParams.get("auto") === "1"; useEffect(() => { + console.debug("[LoginPage] Auth state check:", { + isAuthenticated: auth.isAuthenticated, + isLoading: auth.isLoading, + returnTo + }); if (auth.isAuthenticated) { + console.info("[LoginPage] User is authenticated, redirecting to", returnTo); navigate(returnTo, { replace: true }); } - }, [auth.isAuthenticated, navigate, returnTo]); + }, [auth.isAuthenticated, navigate, returnTo, auth.isLoading]); useEffect(() => { if (!shouldAutoLogin) { @@ -72,8 +78,8 @@ function LoginPage() {

{auth.error.message}