Fix: Improve auth persistence on container restart - distinguish network errors from auth errors (v2.7.3)
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 21s

This commit is contained in:
Play Life Bot
2026-01-02 16:19:54 +03:00
parent 2326a774ad
commit bf539c6e91
2 changed files with 55 additions and 17 deletions

View File

@@ -1 +1 @@
2.7.2 2.7.3

View File

@@ -38,20 +38,29 @@ export function AuthProvider({ children }) {
const refresh = localStorage.getItem(REFRESH_TOKEN_KEY) const refresh = localStorage.getItem(REFRESH_TOKEN_KEY)
if (!refresh) { if (!refresh) {
return false return { success: false, isNetworkError: false }
} }
try { try {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 5000) // 5 second timeout
const response = await fetch('/api/auth/refresh', { const response = await fetch('/api/auth/refresh', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ refresh_token: refresh }) body: JSON.stringify({ refresh_token: refresh }),
signal: controller.signal
}) })
clearTimeout(timeoutId)
if (!response.ok) { if (!response.ok) {
return false // 401 means invalid token (real auth error)
// Other errors might be temporary (503, 502, etc.)
const isAuthError = response.status === 401
return { success: false, isNetworkError: !isAuthError }
} }
const data = await response.json() const data = await response.json()
@@ -61,10 +70,17 @@ export function AuthProvider({ children }) {
localStorage.setItem(USER_KEY, JSON.stringify(data.user)) localStorage.setItem(USER_KEY, JSON.stringify(data.user))
setUser(data.user) setUser(data.user)
return true return { success: true, isNetworkError: false }
} catch (err) { } catch (err) {
// Network errors should be treated as temporary
if (err.name === 'AbortError' ||
(err.name === 'TypeError' && (err.message.includes('fetch') || err.message.includes('Failed to fetch')))) {
console.warn('Refresh token network error, keeping session:', err.message)
return { success: false, isNetworkError: true }
}
// Other errors might be auth related
console.error('Refresh token error:', err) console.error('Refresh token error:', err)
return false return { success: false, isNetworkError: false }
} }
}, []) }, [])
@@ -74,9 +90,14 @@ export function AuthProvider({ children }) {
const token = localStorage.getItem(TOKEN_KEY) const token = localStorage.getItem(TOKEN_KEY)
const savedUser = localStorage.getItem(USER_KEY) const savedUser = localStorage.getItem(USER_KEY)
console.log('[Auth] Initializing auth, token exists:', !!token, 'user exists:', !!savedUser)
if (token && savedUser) { if (token && savedUser) {
try { try {
setUser(JSON.parse(savedUser)) const parsedUser = JSON.parse(savedUser)
setUser(parsedUser) // Set user immediately from localStorage
console.log('[Auth] User restored from localStorage:', parsedUser.email)
// Verify token is still valid with timeout // Verify token is still valid with timeout
const controller = new AbortController() const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 5000) // 5 second timeout const timeoutId = setTimeout(() => controller.abort(), 5000) // 5 second timeout
@@ -95,32 +116,48 @@ export function AuthProvider({ children }) {
const data = await response.json() const data = await response.json()
setUser(data.user) setUser(data.user)
localStorage.setItem(USER_KEY, JSON.stringify(data.user)) localStorage.setItem(USER_KEY, JSON.stringify(data.user))
console.log('[Auth] Token verified successfully')
} else if (response.status === 401) { } else if (response.status === 401) {
// Try to refresh token // Try to refresh token
const refreshed = await refreshToken() console.log('[Auth] Access token expired, attempting refresh...')
if (!refreshed) { const result = await refreshToken()
if (!result.success && !result.isNetworkError) {
// Only logout on real auth errors, not network errors
console.warn('[Auth] Refresh failed with auth error, logging out')
logout() logout()
} else if (!result.success) {
// Network error - keep session, backend might be starting up
console.warn('[Auth] Token refresh failed due to network error, keeping session. User remains logged in.')
// User is already set from localStorage above, so they stay logged in
} else {
console.log('[Auth] Token refreshed successfully')
} }
} else { } else {
// For other errors (like 503, 502, network errors), don't clear auth // For other errors (like 503, 502, network errors), don't clear auth
// Just log the error and keep the user logged in // Just log the error and keep the user logged in
console.warn('Auth check failed with status:', response.status, 'but keeping session') console.warn('[Auth] Auth check failed with status:', response.status, 'but keeping session. User remains logged in.')
// User is already set from localStorage above, so they stay logged in
} }
} catch (err) { } catch (err) {
// Network errors (e.g., backend not ready) should not clear auth // Network errors (e.g., backend not ready) should not clear auth
// Only clear if it's a real auth error // Only clear if it's a real auth error
if (err.name === 'AbortError') { if (err.name === 'AbortError') {
// Timeout - backend might be starting up, keep auth state // Timeout - backend might be starting up, keep auth state
console.warn('Auth check timeout, backend might be starting up. Keeping session.') console.warn('[Auth] Auth check timeout, backend might be starting up. Keeping session. User remains logged in.')
// User is already set from localStorage above, so they stay logged in
} else if (err.name === 'TypeError' && (err.message.includes('fetch') || err.message.includes('Failed to fetch'))) { } else if (err.name === 'TypeError' && (err.message.includes('fetch') || err.message.includes('Failed to fetch'))) {
// Network error - backend might be starting up, keep auth state // Network error - backend might be starting up, keep auth state
console.warn('Network error during auth check, keeping session:', err.message) console.warn('[Auth] Network error during auth check, keeping session:', err.message, 'User remains logged in.')
// User is already set from localStorage above, so they stay logged in
} else { } else {
// Other errors - might be auth related // Other errors - might be auth related
console.error('Auth init error:', err) console.error('[Auth] Auth init error:', err)
// Don't automatically logout on unknown errors // Don't automatically logout on unknown errors
// User is already set from localStorage above, so they stay logged in
} }
} }
} else {
console.log('[Auth] No saved auth data found')
} }
setLoading(false) setLoading(false)
} }
@@ -208,15 +245,16 @@ export function AuthProvider({ children }) {
// If 401, try to refresh token and retry // If 401, try to refresh token and retry
if (response.status === 401) { if (response.status === 401) {
const refreshed = await refreshToken() const result = await refreshToken()
if (refreshed) { if (result.success) {
const newToken = localStorage.getItem(TOKEN_KEY) const newToken = localStorage.getItem(TOKEN_KEY)
headers['Authorization'] = `Bearer ${newToken}` headers['Authorization'] = `Bearer ${newToken}`
response = await fetch(url, { ...options, headers }) response = await fetch(url, { ...options, headers })
} else { } else if (!result.isNetworkError) {
// Only logout if refresh failed (real auth error) // Only logout if refresh failed due to auth error (not network error)
logout() logout()
} }
// If network error, don't logout - let the caller handle the 401
} }
return response return response