From 0cc9d0e94e76902f606e19df3e110f034d290f9d Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Wed, 10 Dec 2025 15:18:37 +0700 Subject: [PATCH] hotfix: Centralize SSO redirection logic into a new helper with loop protection, integrate it into the HTTP client and `RequireAuth` component, and add an authentication failure UI. --- src/components/helper/RequireAuth.tsx | 48 ++++++++++++++++----------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/src/components/helper/RequireAuth.tsx b/src/components/helper/RequireAuth.tsx index 119d74cb..53853b96 100644 --- a/src/components/helper/RequireAuth.tsx +++ b/src/components/helper/RequireAuth.tsx @@ -1,54 +1,46 @@ 'use client'; import { ReactNode, useEffect } from 'react'; -import { useRouter } from 'next/navigation'; -import useSWRImmutable from 'swr/immutable'; +import useSWR from 'swr'; import { useAuth } from '@/services/hooks/useAuth'; import { httpClientFetcher, SWRHttpKey } from '@/services/http/client'; import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { BaseApiResponse, GetMeResponse } from '@/types/api/api-general'; import { AxiosError } from 'axios'; +import { redirectToSSO } from '@/lib/auth-helper'; interface RequireAuthProps { children?: ReactNode; } const RequireAuth = ({ children }: RequireAuthProps) => { - const router = useRouter(); const { setUser, setIsLoadingUser } = useAuth(); const { data: userResponse, isLoading: isLoadingUserResponse, error: userErrorResponse, - } = useSWRImmutable< + } = useSWR< GetMeResponse & { ok?: boolean }, AxiosError, SWRHttpKey >('/sso/userinfo', httpClientFetcher, { shouldRetryOnError: false, - revalidateOnFocus: false, - revalidateOnReconnect: false, - refreshInterval: 0, }); - useEffect(() => { - setIsLoadingUser(isLoadingUserResponse); - }, [isLoadingUserResponse, setIsLoadingUser]); - useEffect(() => { if (isResponseSuccess(userResponse)) { setUser(userResponse.data); - } else if ( - isResponseError(userErrorResponse?.response?.data) && - typeof window !== 'undefined' - ) { - router.replace( - `${process.env.NEXT_PUBLIC_SSO_LOGIN_URL as string}?redirect_url=${window.location.href}` - ); } - }, [userResponse, userErrorResponse, setIsLoadingUser, setUser]); + }, [userResponse, setUser]); + + // Explicitly handle 401 redirect from the component level + useEffect(() => { + if (userErrorResponse?.response?.status === 401) { + redirectToSSO(); + } + }, [userErrorResponse]); if (isLoadingUserResponse && !userResponse && !userErrorResponse) { return ( @@ -58,6 +50,24 @@ const RequireAuth = ({ children }: RequireAuthProps) => { ); } + if (userErrorResponse) { + return ( +
+

Authentication Failed

+

+ Please try refreshing the page or contact support if the problem + persists. +

+ +
+ ); + } + return <>{isResponseSuccess(userResponse) && children}; };