Skip to content

Commit b8e6ece

Browse files
committed
refactor: improve token handling and redirection logic for authentication
1 parent 277d58b commit b8e6ece

File tree

3 files changed

+69
-26
lines changed

3 files changed

+69
-26
lines changed

contexts/auth-context.tsx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,26 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
7070
} catch (profileError) {
7171
console.error('Failed to get user profile:', profileError)
7272

73-
// If profile fetch fails with auth error, clear token
73+
// If profile fetch fails with any auth-related error, clear token immediately
7474
if (profileError instanceof Error && (
7575
profileError.message.includes('401') ||
7676
profileError.message.includes('Unauthorized') ||
7777
profileError.message.includes('munkamenet lejárt') ||
78-
profileError.message.includes('Profile fetch timeout')
78+
profileError.message.includes('Profile fetch timeout') ||
79+
profileError.message.includes('Hitelesítési hiba') ||
80+
profileError.message.includes('Authentication') ||
81+
profileError.message.includes('Invalid token') ||
82+
profileError.message.includes('Token expired')
7983
)) {
8084
console.log('🔑 Clearing token due to profile fetch error:', profileError.message)
8185
apiClient.setToken(null)
8286
setUser(null)
87+
88+
// Force redirect to login if we're in the app
89+
if (typeof window !== 'undefined' && window.location.pathname.startsWith('/app')) {
90+
console.log('🔄 Token expired in app area - redirecting to login')
91+
window.location.href = '/login'
92+
}
8393
} else {
8494
// For other errors (network, server), don't clear token immediately
8595
// Let the user retry or handle it gracefully
@@ -149,7 +159,14 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
149159
} catch (error) {
150160
console.error('Logout error:', error)
151161
} finally {
162+
// Ensure user state is cleared and token is fully removed
152163
setUser(null)
164+
apiClient.setToken(null)
165+
166+
// Force redirect to login to ensure clean state
167+
if (typeof window !== 'undefined') {
168+
window.location.href = '/login'
169+
}
153170
}
154171
}
155172

@@ -169,6 +186,13 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
169186
console.error('Token refresh failed:', error)
170187
setUser(null)
171188
apiClient.setToken(null)
189+
190+
// Force redirect to login if refresh fails and we're in app area
191+
if (typeof window !== 'undefined' && window.location.pathname.startsWith('/app')) {
192+
console.log('🔄 Token refresh failed in app area - redirecting to login')
193+
window.location.href = '/login'
194+
}
195+
172196
throw error
173197
}
174198
}

lib/api.ts

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -729,9 +729,19 @@ class ApiClient {
729729
// Also set as httpOnly cookie for middleware - encode properly
730730
document.cookie = `jwt_token=${encodeURIComponent(cleanToken)}; path=/; max-age=${7 * 24 * 60 * 60}; secure; samesite=strict`
731731
} else {
732+
// Clear all possible token storage locations
732733
localStorage.removeItem('jwt_token')
733-
// Remove cookie
734+
// Remove cookie with all possible variations
734735
document.cookie = 'jwt_token=; path=/; expires=Thu, 01 Jan 1970 00:00:01 GMT;'
736+
document.cookie = 'jwt_token=; path=/; expires=Thu, 01 Jan 1970 00:00:01 GMT; secure; samesite=strict'
737+
document.cookie = 'jwt_token=; path=/; domain=' + window.location.hostname + '; expires=Thu, 01 Jan 1970 00:00:01 GMT;'
738+
739+
// Also clear sessionStorage just in case
740+
try {
741+
sessionStorage.removeItem('jwt_token')
742+
} catch (e) {
743+
console.warn('Could not clear sessionStorage:', e)
744+
}
735745
}
736746
}
737747
}
@@ -865,25 +875,29 @@ class ApiClient {
865875
// For public endpoints, don't clear token and use specific error message
866876
throw new Error(errorData.message || 'Hitelesítési hiba történt.')
867877
} else {
868-
// For protected endpoints, be more careful about clearing tokens
869-
// Only clear token if it's explicitly an authentication error
870-
if (errorData.message && (
871-
errorData.message.includes('Invalid token') ||
872-
errorData.message.includes('Token expired') ||
873-
errorData.message.includes('Authentication failed') ||
874-
errorData.message.includes('Hitelesítés sikertelen')
875-
)) {
876-
console.log('🔑 Clearing token due to explicit auth error:', errorData.message)
877-
this.setToken(null)
878-
throw new Error('A munkamenet lejárt. Kérjük, jelentkezzen be újra.')
879-
} else {
880-
// For other 401 errors, don't clear token - could be temporary issue
881-
console.warn('⚠️ 401 error but preserving token (might be temporary):', {
882-
endpoint,
883-
error: errorData.message
884-
})
885-
throw new Error(errorData.message || 'Hitelesítési hiba történt. Próbálja újra.')
878+
// For protected endpoints, always clear expired tokens
879+
// Be more aggressive about token clearing on 401 errors in production
880+
// This fixes the redirect loop issue where expired tokens weren't being cleared properly
881+
console.log('🔑 401 error on protected endpoint - clearing token:', {
882+
endpoint,
883+
error: errorData.message,
884+
environment: typeof window !== 'undefined' ? window.location.hostname : 'unknown'
885+
})
886+
887+
// Always clear token on 401 for protected endpoints to prevent redirect loops
888+
// When a token truly expires, we need to ensure it's completely removed from all storage
889+
this.setToken(null)
890+
891+
// Force reload to clear any cached state and redirect properly
892+
// This prevents the middleware redirect loop between /login and /app/iranyitopult
893+
if (typeof window !== 'undefined') {
894+
// Small delay to ensure token clearing is completed
895+
setTimeout(() => {
896+
window.location.href = '/login'
897+
}, 100)
886898
}
899+
900+
throw new Error('A munkamenet lejárt. Kérjük, jelentkezzen be újra.')
887901
}
888902
} else if (response.status === 403) {
889903
throw new Error('Nincs jogosultsága ehhez a művelethez.')
@@ -980,9 +994,11 @@ class ApiClient {
980994
}
981995

982996
private shouldNotRetry(error: Error): boolean {
983-
// Don't retry on authentication errors
997+
// Don't retry on authentication errors - token is likely expired
984998
if (error.message.includes('401') || error.message.includes('Unauthorized') ||
985-
error.message.includes('munkamenet lejárt')) {
999+
error.message.includes('munkamenet lejárt') || error.message.includes('Hitelesítési hiba') ||
1000+
error.message.includes('Authentication') || error.message.includes('Invalid token') ||
1001+
error.message.includes('Token expired')) {
9861002
return true
9871003
}
9881004

middleware.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ export function middleware(request: NextRequest) {
1414
})
1515
}
1616

17+
// Check if token is actually valid (not just present)
18+
const hasValidToken = token && token.trim() !== '' && token !== 'null' && token !== 'undefined'
19+
1720
// Protected routes - require authentication
1821
const protectedPaths = ['/app']
1922
const isProtectedPath = protectedPaths.some(path =>
@@ -29,14 +32,14 @@ export function middleware(request: NextRequest) {
2932
const authOnlyPublicPaths = ['/login']
3033
const isAuthOnlyPublicPath = authOnlyPublicPaths.includes(request.nextUrl.pathname)
3134

32-
// If trying to access protected route without token
33-
if (isProtectedPath && (!token || token.trim() === '' || token === 'null')) {
35+
// If trying to access protected route without valid token
36+
if (isProtectedPath && !hasValidToken) {
3437
console.log('🚫 Redirecting to login - no valid token for protected route')
3538
return NextResponse.redirect(new URL('/login', request.url))
3639
}
3740

3841
// If logged in and trying to access auth-only public pages (like login)
39-
if (token && token.trim() !== '' && token !== 'null' && isAuthOnlyPublicPath) {
42+
if (hasValidToken && isAuthOnlyPublicPath) {
4043
console.log('✅ Redirecting authenticated user away from login')
4144
return NextResponse.redirect(new URL('/app/iranyitopult', request.url))
4245
}

0 commit comments

Comments
 (0)