fix: Resolve login redirect loop and authentication conflicts

- Add delay after login to ensure session cookies are set properly
- Fix client-side auth checks in dashboard to handle session refresh gracefully
- Remove conflicting client-side redirects from Navigation component
- All authentication now properly handled by unified server-side auth system

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-13 09:28:24 -06:00
parent 57b23a304c
commit 7fe90e7330
3 changed files with 77 additions and 21 deletions

View File

@@ -299,13 +299,52 @@ import ThemeToggle from './ThemeToggle.tsx';
// Check authentication and load user info
async function initializeNavigation() {
const { data: { session } } = await supabase.auth.getSession();
if (!session) {
window.location.href = '/';
// Try to get session, but don't redirect if none found since auth is handled server-side
const { data: { session }, error: sessionError } = await supabase.auth.getSession();
if (sessionError || !session) {
// Try to get user directly (handles token refresh internally)
const { data: { user }, error: userError } = await supabase.auth.getUser();
if (userError || !user) {
console.log('[NAV] No user session found, user likely not authenticated');
// Don't redirect - let server-side auth handle this
return;
}
// Use the user data we got directly
const userName = user.user_metadata.name || user.email;
const userEmail = user.email;
// Update all name displays
if (userNameText) userNameText.textContent = userName;
if (mobileUserNameText) mobileUserNameText.textContent = userName;
if (dropdownName) dropdownName.textContent = userName;
if (dropdownEmail) dropdownEmail.textContent = userEmail;
// Generate user initials
const initials = userName.split(' ').map(n => n[0]).join('').toUpperCase().slice(0, 2);
if (userAvatar) userAvatar.textContent = initials;
if (mobileUserAvatar) mobileUserAvatar.textContent = initials;
if (dropdownAvatar) dropdownAvatar.textContent = initials;
// Check if user is admin and show admin badge/menu items
const { data: userProfile } = await supabase
.from('users')
.select('role')
.eq('id', user.id)
.single();
if (userProfile?.role === 'admin') {
if (adminBadge) adminBadge.classList.remove('hidden');
if (mobileAdminBadge) mobileAdminBadge.classList.remove('hidden');
if (adminMenuItem) adminMenuItem.classList.remove('hidden');
if (mobileAdminMenuItem) mobileAdminMenuItem.classList.remove('hidden');
}
return;
}
// Load user info
// Session exists, use session user
const { data: { user } } = await supabase.auth.getUser();
if (user) {
const userName = user.user_metadata.name || user.email;

View File

@@ -359,32 +359,46 @@ if (!auth) {
async function loadEvents() {
try {
// Get current user (auth already verified server-side)
const { data: { user } } = await supabase.auth.getUser();
const { data: { user }, error: userError } = await supabase.auth.getUser();
if (!user) {
// This shouldn't happen due to server-side auth, but handle gracefully
console.error('No user found despite server-side auth');
loading.innerHTML = `
<div class="rounded-xl p-6 max-w-md mx-auto" style="background: var(--error-bg); border: 1px solid var(--error-border);">
<p class="font-medium" style="color: var(--error-color);">Session error</p>
<p class="text-sm mt-2" style="color: var(--error-color); opacity: 0.8;">Please refresh the page</p>
</div>
`;
if (userError || !user) {
// Session might be stale, try to refresh and retry once
console.log('[DASHBOARD] No user session found, attempting to refresh...');
const { data: refreshData, error: refreshError } = await supabase.auth.refreshSession();
if (refreshError || !refreshData?.user) {
// If refresh fails, redirect to login
console.error('Session refresh failed, redirecting to login');
window.location.href = '/login';
return;
}
// Use refreshed user data
console.log('[DASHBOARD] Session refreshed successfully for user:', refreshData.user.id);
}
// Get the actual user object (either original or refreshed)
const currentUser = user || (await supabase.auth.getUser()).data.user;
if (!currentUser) {
console.error('Unable to get user after refresh attempt');
window.location.href = '/login';
return;
}
const { data: userProfile, error: userError } = await supabase
const { data: userProfile, error: userProfileError } = await supabase
.from('users')
.select('organization_id, role')
.eq('id', user.id)
.eq('id', currentUser.id)
.single();
if (userError) {
if (userProfileError) {
// Error loading user profile
loading.innerHTML = `
<div class="rounded-xl p-6 max-w-md mx-auto" style="background: var(--error-bg); border: 1px solid var(--error-border);">
<p class="font-medium" style="color: var(--error-color);">Error loading user profile</p>
<p class="text-sm mt-2" style="color: var(--error-color); opacity: 0.8;">${userError.message || userError}</p>
<p class="text-sm mt-2" style="color: var(--error-color); opacity: 0.8;">${userProfileError.message || userProfileError}</p>
</div>
`;
return;

View File

@@ -357,13 +357,16 @@ const csrfToken = generateCSRFToken();
const urlParams = new URLSearchParams(window.location.search);
const returnTo = urlParams.get('returnTo') || urlParams.get('redirect');
// Use the redirectTo from server or fallback to returnTo
// Use the redirectTo from server or fallback to returnTo or default dashboard
const finalRedirect = returnTo || result.redirectTo || '/dashboard';
console.log('[LOGIN] Login successful, redirecting to:', finalRedirect);
// Use window.location.replace to prevent back button issues
window.location.replace(finalRedirect);
// Small delay to ensure session cookies are set properly
setTimeout(() => {
// Use window.location.href instead of replace to ensure proper navigation
window.location.href = finalRedirect;
}, 100);
}
} catch (error) {
errorMessage.textContent = (error as Error).message;