feat: Enhance authentication middleware and token refresh logic with improved caching, retry mechanisms, and error handling
This commit is contained in:
@@ -4,6 +4,8 @@ export default defineNuxtPlugin(() => {
|
||||
|
||||
let refreshTimer: NodeJS.Timeout | null = null
|
||||
let isRefreshing = false
|
||||
let retryCount = 0
|
||||
const maxRetries = 3
|
||||
|
||||
const scheduleTokenRefresh = (expiresAt: number) => {
|
||||
// Clear existing timer
|
||||
@@ -12,11 +14,13 @@ export default defineNuxtPlugin(() => {
|
||||
refreshTimer = null
|
||||
}
|
||||
|
||||
// Calculate time until refresh (refresh 2 minutes before expiry)
|
||||
const refreshBuffer = 2 * 60 * 1000 // 2 minutes in milliseconds
|
||||
// Calculate time until refresh (refresh 5 minutes before expiry)
|
||||
const refreshBuffer = 5 * 60 * 1000 // 5 minutes in milliseconds
|
||||
const timeUntilRefresh = expiresAt - Date.now() - refreshBuffer
|
||||
|
||||
console.log('[AUTH_REFRESH] Scheduling token refresh in:', Math.max(0, timeUntilRefresh), 'ms')
|
||||
console.log('[AUTH_REFRESH] Token expires at:', new Date(expiresAt))
|
||||
console.log('[AUTH_REFRESH] Will refresh at:', new Date(expiresAt - refreshBuffer))
|
||||
|
||||
// Only schedule if we have time left
|
||||
if (timeUntilRefresh > 0) {
|
||||
@@ -28,20 +32,37 @@ export default defineNuxtPlugin(() => {
|
||||
console.log('[AUTH_REFRESH] Attempting automatic token refresh...')
|
||||
|
||||
const response = await $fetch<{ success: boolean; expiresAt?: number }>('/api/auth/refresh', {
|
||||
method: 'POST'
|
||||
method: 'POST',
|
||||
retry: 2,
|
||||
retryDelay: 1000
|
||||
})
|
||||
|
||||
if (response.success && response.expiresAt) {
|
||||
console.log('[AUTH_REFRESH] Token refresh successful, scheduling next refresh')
|
||||
retryCount = 0 // Reset retry count on success
|
||||
scheduleTokenRefresh(response.expiresAt)
|
||||
} else {
|
||||
console.error('[AUTH_REFRESH] Token refresh failed, redirecting to login')
|
||||
await navigateTo('/login')
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error('[AUTH_REFRESH] Token refresh error:', error)
|
||||
// If refresh fails, redirect to login
|
||||
await navigateTo('/login')
|
||||
|
||||
// Implement exponential backoff retry
|
||||
if (retryCount < maxRetries) {
|
||||
retryCount++
|
||||
const retryDelay = Math.min(1000 * Math.pow(2, retryCount), 10000) // Max 10 seconds
|
||||
console.log(`[AUTH_REFRESH] Retrying refresh in ${retryDelay}ms (attempt ${retryCount}/${maxRetries})`)
|
||||
|
||||
setTimeout(() => {
|
||||
if (!isRefreshing) {
|
||||
scheduleTokenRefresh(expiresAt)
|
||||
}
|
||||
}, retryDelay)
|
||||
} else {
|
||||
console.error('[AUTH_REFRESH] Max retries reached, redirecting to login')
|
||||
await navigateTo('/login')
|
||||
}
|
||||
} finally {
|
||||
isRefreshing = false
|
||||
}
|
||||
@@ -56,11 +77,14 @@ export default defineNuxtPlugin(() => {
|
||||
console.log('[AUTH_REFRESH] Token expired, attempting immediate refresh...')
|
||||
|
||||
const response = await $fetch<{ success: boolean; expiresAt?: number }>('/api/auth/refresh', {
|
||||
method: 'POST'
|
||||
method: 'POST',
|
||||
retry: 2,
|
||||
retryDelay: 1000
|
||||
})
|
||||
|
||||
if (response.success && response.expiresAt) {
|
||||
console.log('[AUTH_REFRESH] Immediate refresh successful')
|
||||
retryCount = 0 // Reset retry count on success
|
||||
scheduleTokenRefresh(response.expiresAt)
|
||||
} else {
|
||||
console.error('[AUTH_REFRESH] Immediate refresh failed, redirecting to login')
|
||||
@@ -68,7 +92,19 @@ export default defineNuxtPlugin(() => {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[AUTH_REFRESH] Immediate refresh error:', error)
|
||||
await navigateTo('/login')
|
||||
|
||||
// Try one more time before giving up
|
||||
if (retryCount === 0) {
|
||||
retryCount++
|
||||
console.log('[AUTH_REFRESH] Retrying immediate refresh once more...')
|
||||
setTimeout(() => {
|
||||
if (!isRefreshing) {
|
||||
scheduleTokenRefresh(Date.now() - 1) // Force immediate refresh
|
||||
}
|
||||
}, 2000)
|
||||
} else {
|
||||
await navigateTo('/login')
|
||||
}
|
||||
} finally {
|
||||
isRefreshing = false
|
||||
}
|
||||
@@ -127,10 +163,20 @@ export default defineNuxtPlugin(() => {
|
||||
|
||||
// Listen for visibility changes to refresh when tab becomes active
|
||||
if (typeof document !== 'undefined') {
|
||||
let lastVisibilityChange = Date.now()
|
||||
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (!document.hidden) {
|
||||
// Tab became visible, check if we need to refresh
|
||||
checkAndScheduleRefresh()
|
||||
const now = Date.now()
|
||||
const timeSinceLastCheck = now - lastVisibilityChange
|
||||
|
||||
// If tab was hidden for more than 1 minute, check auth status
|
||||
if (timeSinceLastCheck > 60000) {
|
||||
console.log('[AUTH_REFRESH] Tab became visible after', Math.round(timeSinceLastCheck / 1000), 'seconds, checking auth status')
|
||||
checkAndScheduleRefresh()
|
||||
}
|
||||
|
||||
lastVisibilityChange = now
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user