From 1db931c94bbe06ac24f0d25c7736f1a10d29c8fa Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Thu, 13 Nov 2025 18:28:34 +0000 Subject: [PATCH] login expired --- .../public/locales/en-GB/translation.json | 1 + .../src/core/services/httpErrorHandler.ts | 22 +++++++++++++++---- frontend/src/proprietary/routes/Landing.tsx | 10 ++------- frontend/src/proprietary/routes/Login.tsx | 8 ++++++- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/frontend/public/locales/en-GB/translation.json b/frontend/public/locales/en-GB/translation.json index 9cfe5380b..dc9fb8fed 100644 --- a/frontend/public/locales/en-GB/translation.json +++ b/frontend/public/locales/en-GB/translation.json @@ -3177,6 +3177,7 @@ "rememberme": "Remember me", "invalid": "Invalid username or password.", "locked": "Your account has been locked.", + "sessionExpired": "Your session has expired. Please sign in again.", "signinTitle": "Please sign in", "ssoSignIn": "Login via Single Sign-on", "oAuth2AutoCreateDisabled": "OAUTH2 Auto-Create User Disabled", diff --git a/frontend/src/core/services/httpErrorHandler.ts b/frontend/src/core/services/httpErrorHandler.ts index 0640b480c..05706458f 100644 --- a/frontend/src/core/services/httpErrorHandler.ts +++ b/frontend/src/core/services/httpErrorHandler.ts @@ -93,18 +93,32 @@ export async function handleHttpError(error: any): Promise { return false; // Don't show global toast, but continue rejection } - // Suppress "Authentication required" 401 errors on auth pages + // Handle 401 authentication errors const status: number | undefined = error?.response?.status; if (status === 401) { const pathname = window.location.pathname; + const errorMessage = error?.response?.data?.error || error?.response?.data?.message || ''; + const isAuthenticationError = errorMessage.toLowerCase().includes('authentication'); + + // Check if we're already on an auth page const isAuthPage = pathname.includes('/login') || pathname.includes('/signup') || pathname.includes('/auth/') || pathname.includes('/invite/'); - if (isAuthPage) { - console.debug('[httpErrorHandler] Suppressing 401 on auth page:', pathname); - return true; // Suppress toast + + // If not on auth page, redirect to login with expired session message + if (!isAuthPage) { + console.debug('[httpErrorHandler] 401 detected, redirecting to login'); + // Store the current location so we can redirect back after login + const currentLocation = window.location.pathname + window.location.search; + // Redirect to login with state + window.location.href = `/login?expired=true&from=${encodeURIComponent(currentLocation)}`; + return true; // Suppress toast since we're redirecting } + + // On auth pages, suppress the toast (user is already trying to authenticate) + console.debug('[httpErrorHandler] Suppressing 401 on auth page:', pathname); + return true; } // Compute title/body (friendly) from the error object const { title, body } = extractAxiosErrorMessage(error); diff --git a/frontend/src/proprietary/routes/Landing.tsx b/frontend/src/proprietary/routes/Landing.tsx index 73b07063b..1831b8c2f 100644 --- a/frontend/src/proprietary/routes/Landing.tsx +++ b/frontend/src/proprietary/routes/Landing.tsx @@ -95,13 +95,7 @@ export default function Landing() { ); } - // If we're at home route ("/"), show login directly (marketing/landing page) - // Otherwise navigate to login (fixes URL mismatch for tool routes) - const isHome = location.pathname === '/' || location.pathname === ''; - if (isHome) { - return ; - } - - // For non-home routes without auth, navigate to login (preserves from location) + // No session - redirect to login page + // This ensures the URL always shows /login when not authenticated return ; } diff --git a/frontend/src/proprietary/routes/Login.tsx b/frontend/src/proprietary/routes/Login.tsx index ef03496b3..bbca13307 100644 --- a/frontend/src/proprietary/routes/Login.tsx +++ b/frontend/src/proprietary/routes/Login.tsx @@ -74,7 +74,7 @@ export default function Login() { } }, [enabledProviders]); - // Handle query params (email prefill and success messages) + // Handle query params (email prefill, success messages, and session expiry) useEffect(() => { try { const emailFromQuery = searchParams.get('email'); @@ -82,6 +82,12 @@ export default function Login() { setEmail(emailFromQuery); } + // Check if session expired (401 redirect) + const expired = searchParams.get('expired'); + if (expired === 'true') { + setError(t('login.sessionExpired', 'Your session has expired. Please sign in again.')); + } + const messageType = searchParams.get('messageType') if (messageType) { switch (messageType) {