Fix redirect loops and SSR hydration issues in auth flow
All checks were successful
Build And Push Image / docker (push) Successful in 2m59s
All checks were successful
Build And Push Image / docker (push) Successful in 2m59s
- Replace ref with useState in useAuth for SSR compatibility - Move navigation logic from top-level to onMounted hooks - Add guest middleware to login page to prevent auth conflicts - Simplify dashboard auth checks by relying on middleware - Add loading state to index page during auth resolution This prevents infinite redirect loops and hydration mismatches that occurred during server-side rendering when navigating between authenticated and unauthenticated states.
This commit is contained in:
@@ -18,35 +18,26 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
definePageMeta({
|
||||
middleware: 'auth'
|
||||
middleware: 'auth',
|
||||
layout: 'dashboard'
|
||||
});
|
||||
|
||||
const { user, userTier, isAuthenticated, checkAuth } = useAuth();
|
||||
const { user, userTier } = useAuth();
|
||||
const loading = ref(true);
|
||||
const authChecked = ref(false);
|
||||
|
||||
// Check authentication on mount
|
||||
onMounted(async () => {
|
||||
console.log('🔄 Dashboard mounted, checking authentication...');
|
||||
// Route to tier-specific dashboard - auth middleware ensures user is authenticated
|
||||
onMounted(() => {
|
||||
console.log('🔄 Dashboard mounted, routing to tier-specific page...');
|
||||
|
||||
// Ensure auth is checked before routing
|
||||
await checkAuth();
|
||||
authChecked.value = true;
|
||||
|
||||
console.log('✅ Auth check complete:', {
|
||||
isAuthenticated: isAuthenticated.value,
|
||||
user: user.value?.email,
|
||||
tier: userTier.value
|
||||
});
|
||||
|
||||
// Now route based on auth status
|
||||
if (isAuthenticated.value && user.value) {
|
||||
// Auth middleware has already verified authentication - just route to tier page
|
||||
if (user.value && userTier.value) {
|
||||
const tierRoute = `/dashboard/${userTier.value}`;
|
||||
console.log('🔄 Routing to tier-specific dashboard:', tierRoute);
|
||||
await navigateTo(tierRoute, { replace: true });
|
||||
navigateTo(tierRoute, { replace: true });
|
||||
} else {
|
||||
console.log('🔄 User not authenticated, redirecting to login');
|
||||
await navigateTo('/login');
|
||||
console.warn('❌ No user or tier found - this should not happen after auth middleware');
|
||||
// Fallback - middleware should have caught this
|
||||
navigateTo('/login');
|
||||
}
|
||||
|
||||
loading.value = false;
|
||||
|
||||
@@ -1,12 +1,42 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- Redirect to dashboard if authenticated, otherwise to login -->
|
||||
<div class="loading-container">
|
||||
<v-container fluid class="fill-height">
|
||||
<v-row justify="center" align="center">
|
||||
<v-col cols="auto" class="text-center">
|
||||
<v-progress-circular
|
||||
indeterminate
|
||||
color="primary"
|
||||
size="64"
|
||||
width="6"
|
||||
/>
|
||||
<p class="mt-4 text-h6">Loading...</p>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { isAuthenticated } = useAuth();
|
||||
// NO top-level navigation - this causes SSR issues and loops!
|
||||
// Let middleware and lifecycle hooks handle routing properly
|
||||
|
||||
// Redirect based on authentication status
|
||||
await navigateTo(isAuthenticated.value ? '/dashboard' : '/login');
|
||||
onMounted(() => {
|
||||
const { isAuthenticated } = useAuth();
|
||||
|
||||
// Route after component is mounted (client-side only)
|
||||
if (isAuthenticated.value) {
|
||||
navigateTo('/dashboard');
|
||||
} else {
|
||||
navigateTo('/login');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.loading-container {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -122,7 +122,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
definePageMeta({
|
||||
layout: false
|
||||
layout: false,
|
||||
middleware: 'guest' // This prevents authenticated users from accessing login
|
||||
});
|
||||
|
||||
// Use the auth composable
|
||||
@@ -205,17 +206,9 @@ const handlePasswordResetSuccess = (message: string) => {
|
||||
console.log('Password reset:', message);
|
||||
};
|
||||
|
||||
// Check auth and auto-focus on mount
|
||||
onMounted(async () => {
|
||||
// Check if user is already authenticated (client-side only)
|
||||
const isAuthenticated = await checkAuth();
|
||||
if (isAuthenticated && user.value) {
|
||||
console.log('🔄 User already authenticated, redirecting to dashboard');
|
||||
await navigateTo('/dashboard');
|
||||
return;
|
||||
}
|
||||
|
||||
// Auto-focus username field
|
||||
// Auto-focus on mount - guest middleware handles auth redirects
|
||||
onMounted(() => {
|
||||
// Only auto-focus, no auth check needed - guest middleware handles it
|
||||
nextTick(() => {
|
||||
const usernameField = document.querySelector('input[type="text"]') as HTMLInputElement;
|
||||
if (usernameField) {
|
||||
|
||||
Reference in New Issue
Block a user