feat(frontend): Implement silent refresh logic
This commit is contained in:
@@ -10,6 +10,7 @@ import { type Conversation } from "./components/layout/HistorySidebar"
|
||||
import { registerUnauthorizedCallback } from "./services/api"
|
||||
import { Button } from "./components/ui/button"
|
||||
import { ThemeProvider, useTheme } from "./components/theme-provider"
|
||||
import { useSilentRefresh } from "./hooks/use-silent-refresh"
|
||||
|
||||
// --- Auth Context ---
|
||||
interface AuthContextType {
|
||||
@@ -52,6 +53,8 @@ function AppContent() {
|
||||
const { setThemeLocal } = useTheme()
|
||||
const { isAuthenticated, setIsAuthenticated, user, setUser } = useAuth()
|
||||
|
||||
useSilentRefresh(isAuthenticated)
|
||||
|
||||
const [authMode, setAuthMode] = useState<"login" | "register">("login")
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [selectedThreadId, setSelectedThreadId] = useState<string | null>(null)
|
||||
|
||||
33
frontend/src/hooks/use-silent-refresh.ts
Normal file
33
frontend/src/hooks/use-silent-refresh.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { useEffect, useCallback } from 'react'
|
||||
import { AuthService } from '@/services/auth'
|
||||
|
||||
/**
|
||||
* Hook to handle silent token refresh in the background.
|
||||
* It proactively refreshes the session to prevent expiration while the user is active.
|
||||
*/
|
||||
export function useSilentRefresh(isAuthenticated: boolean) {
|
||||
const refresh = useCallback(async () => {
|
||||
try {
|
||||
console.log('Proactively refreshing session...')
|
||||
await AuthService.refreshSession()
|
||||
} catch (error) {
|
||||
console.error('Silent refresh failed:', error)
|
||||
// If refresh fails, we don't necessarily logout here,
|
||||
// as the reactive interceptor will handle 401s if the session is truly dead.
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAuthenticated) return
|
||||
|
||||
// Refresh every 25 minutes (access token defaults to 30 mins)
|
||||
const REFRESH_INTERVAL = 25 * 60 * 1000
|
||||
|
||||
const intervalId = setInterval(refresh, REFRESH_INTERVAL)
|
||||
|
||||
// Also refresh immediately on mount/auth if we want to ensure we have a fresh start
|
||||
// refresh()
|
||||
|
||||
return () => clearInterval(intervalId)
|
||||
}, [isAuthenticated, refresh])
|
||||
}
|
||||
@@ -52,6 +52,11 @@ export const AuthService = {
|
||||
await api.post("/auth/logout")
|
||||
},
|
||||
|
||||
async refreshSession(): Promise<AuthResponse> {
|
||||
const response = await api.post<AuthResponse>("/auth/refresh")
|
||||
return response.data
|
||||
},
|
||||
|
||||
async updateTheme(theme: Theme): Promise<UserResponse> {
|
||||
const response = await api.patch<UserResponse>("/auth/theme", { theme })
|
||||
return response.data
|
||||
|
||||
Reference in New Issue
Block a user