fix: Resolve authentication login loop preventing dashboard access
## Problem Users experienced infinite login loops where successful authentication would redirect to dashboard, then immediately redirect back to login page. ## Root Cause Client-server authentication mismatch due to httpOnly cookies: - Login API sets httpOnly cookies using server-side Supabase client ✅ - Dashboard server reads httpOnly cookies correctly ✅ - Dashboard client script tried to read httpOnly cookies using client-side Supabase ❌ ## Solution 1. Fixed Admin Dashboard: Removed non-existent `is_super_admin` column references 2. Created Auth Check API: Server-side auth validation for client scripts 3. Updated Admin API Router: Uses auth check API instead of client-side Supabase ## Key Changes - src/pages/admin/dashboard.astro: Fixed database queries - src/pages/api/admin/auth-check.ts: NEW server-side auth validation API - src/lib/admin-api-router.ts: Uses API calls instead of client-side auth - src/pages/api/auth/session.ts: Return 200 status for unauthenticated users - src/pages/login.astro: Enhanced cache clearing and session management ## Testing - Automated Playwright tests validate end-to-end login flow - Manual testing confirms successful login without loops ## Documentation - AUTHENTICATION_FIX.md: Complete technical documentation - CLAUDE.md: Updated with authentication system notes 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,8 @@ export const POST: APIRoute = async ({ request, cookies }) => {
|
||||
const formData = await request.json();
|
||||
const { email, password } = formData;
|
||||
|
||||
console.log('[LOGIN] Attempting login for:', email);
|
||||
|
||||
if (!email || !password) {
|
||||
return new Response(JSON.stringify({
|
||||
error: 'Email and password are required'
|
||||
@@ -16,13 +18,21 @@ export const POST: APIRoute = async ({ request, cookies }) => {
|
||||
}
|
||||
|
||||
const supabase = createSupabaseServerClient(cookies);
|
||||
console.log('[LOGIN] Created Supabase client');
|
||||
|
||||
const { data, error } = await supabase.auth.signInWithPassword({
|
||||
email,
|
||||
password,
|
||||
});
|
||||
|
||||
console.log('[LOGIN] Supabase response:', {
|
||||
hasUser: !!data?.user,
|
||||
hasSession: !!data?.session,
|
||||
error: error?.message
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.log('[LOGIN] Authentication failed:', error.message);
|
||||
return new Response(JSON.stringify({
|
||||
error: error.message
|
||||
}), {
|
||||
@@ -32,23 +42,50 @@ export const POST: APIRoute = async ({ request, cookies }) => {
|
||||
}
|
||||
|
||||
// Get user organization
|
||||
const { data: userData } = await supabase
|
||||
console.log('[LOGIN] Looking up user data for ID:', data.user.id);
|
||||
const { data: userData, error: userError } = await supabase
|
||||
.from('users')
|
||||
.select('organization_id, role, is_super_admin')
|
||||
.select('organization_id, role')
|
||||
.eq('id', data.user.id)
|
||||
.single();
|
||||
|
||||
console.log('[LOGIN] User data lookup:', {
|
||||
userData,
|
||||
userError: userError?.message,
|
||||
hasOrganization: !!userData?.organization_id,
|
||||
userId: data.user.id
|
||||
});
|
||||
|
||||
// If user lookup failed, log detailed error and return error response
|
||||
if (userError) {
|
||||
console.error('[LOGIN] User lookup failed:', {
|
||||
error: userError,
|
||||
userId: data.user.id,
|
||||
userEmail: data.user.email
|
||||
});
|
||||
return new Response(JSON.stringify({
|
||||
error: 'Failed to retrieve user profile. Please try again.'
|
||||
}), {
|
||||
status: 500,
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
}
|
||||
|
||||
const redirectTo = !userData?.organization_id
|
||||
? '/onboarding/organization'
|
||||
: userData?.role === 'admin'
|
||||
? '/admin/dashboard'
|
||||
: '/dashboard';
|
||||
|
||||
console.log('[LOGIN] Redirecting to:', redirectTo);
|
||||
|
||||
return new Response(JSON.stringify({
|
||||
success: true,
|
||||
user: data.user,
|
||||
organizationId: userData?.organization_id,
|
||||
isAdmin: userData?.role === 'admin',
|
||||
isSuperAdmin: userData?.role === 'admin' && userData?.is_super_admin === true,
|
||||
redirectTo: !userData?.organization_id
|
||||
? '/onboarding/organization'
|
||||
: userData?.role === 'admin'
|
||||
? '/admin/dashboard'
|
||||
: '/dashboard'
|
||||
isSuperAdmin: false, // Super admin logic can be added later if needed
|
||||
redirectTo
|
||||
}), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
|
||||
Reference in New Issue
Block a user