feat(frontend): Implement silent refresh logic

This commit is contained in:
Yunxiao Xu
2026-02-18 13:43:37 -08:00
parent d11f3dd00c
commit 5adc826cfb
3 changed files with 41 additions and 0 deletions

View File

@@ -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)

View 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])
}

View File

@@ -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