From c276f165f49621729f19d1f442c7eed50e301d18 Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 6 Apr 2026 00:16:52 -0400 Subject: [PATCH] Enhance authentication handling --- inventory-server/auth/server.js | 7 ++++- inventory/src/contexts/AuthContext.tsx | 42 +++++++++++++++++++------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/inventory-server/auth/server.js b/inventory-server/auth/server.js index d8d3a2e..203ee5e 100644 --- a/inventory-server/auth/server.js +++ b/inventory-server/auth/server.js @@ -123,7 +123,12 @@ app.get('/me', async (req, res) => { } const user = userResult.rows[0]; - + + // Check if user is active + if (!user.is_active) { + return res.status(403).json({ error: 'Account is inactive' }); + } + // Get user permissions let permissions = []; if (!user.is_admin) { diff --git a/inventory/src/contexts/AuthContext.tsx b/inventory/src/contexts/AuthContext.tsx index 5b20bc7..1a743b7 100644 --- a/inventory/src/contexts/AuthContext.tsx +++ b/inventory/src/contexts/AuthContext.tsx @@ -1,4 +1,4 @@ -import { createContext, useState, useEffect, ReactNode, useCallback } from 'react'; +import { createContext, useState, useEffect, useRef, ReactNode, useCallback } from 'react'; import config from '@/config'; export interface Permission { @@ -61,14 +61,17 @@ export function AuthProvider({ children }: { children: ReactNode }) { if (!response.ok) { const errorData = await response.json().catch(() => ({})); - throw new Error(errorData.error || 'Failed to fetch user data'); + console.error('Auth check failed:', response.status, errorData); + // Any failed /me response means the session is invalid — logout + logout(); + return; } const userData = await response.json(); console.log("Fetched current user data:", userData); console.log("User permissions:", userData.permissions); console.log("User rocket_chat_user_id:", userData.rocket_chat_user_id); - + setUser(userData); // Ensure we have the sessionStorage isLoggedIn flag set sessionStorage.setItem('isLoggedIn', 'true'); @@ -76,14 +79,7 @@ export function AuthProvider({ children }: { children: ReactNode }) { const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred'; setError(errorMessage); console.error('Auth error:', errorMessage); - - // Clear token if authentication failed - if (err instanceof Error && - (err.message.includes('authentication') || - err.message.includes('token') || - err.message.includes('401'))) { - logout(); - } + // Network errors (server down, etc.) — don't logout, just show error } finally { setIsLoading(false); } @@ -99,6 +95,30 @@ export function AuthProvider({ children }: { children: ReactNode }) { } }, [token, fetchCurrentUser]); + // Re-validate auth when user returns to the tab after being away + const lastCheckRef = useRef(Date.now()); + useEffect(() => { + const onVisibilityChange = () => { + if (document.visibilityState === 'visible' && token) { + const elapsed = Date.now() - lastCheckRef.current; + // Only re-check if at least 5 minutes have passed + if (elapsed > 5 * 60 * 1000) { + lastCheckRef.current = Date.now(); + fetchCurrentUser(); + } + } + }; + document.addEventListener('visibilitychange', onVisibilityChange); + return () => document.removeEventListener('visibilitychange', onVisibilityChange); + }, [token, fetchCurrentUser]); + + // Listen for auth:logout events from anywhere in the app (e.g. failed API calls) + useEffect(() => { + const onForceLogout = () => logout(); + window.addEventListener('auth:logout', onForceLogout); + return () => window.removeEventListener('auth:logout', onForceLogout); + }, []); + const login = async (username: string, password: string) => { try { setIsLoading(true);