## 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>
205 lines
6.8 KiB
Markdown
205 lines
6.8 KiB
Markdown
# Authentication Login Loop Fix
|
|
|
|
## Problem Description
|
|
|
|
Users experienced a login loop where:
|
|
1. User enters valid credentials and login succeeds
|
|
2. User gets redirected to dashboard initially
|
|
3. Dashboard immediately redirects back to login page
|
|
4. This creates an infinite loop preventing access to the dashboard
|
|
|
|
## Root Cause Analysis
|
|
|
|
The issue was a **client-server authentication mismatch** in the authentication system:
|
|
|
|
### The Problem Flow
|
|
1. **Login API** (`/src/pages/api/auth/login.ts`): Sets httpOnly cookies using server-side Supabase client ✅
|
|
2. **Dashboard Server** (`/src/pages/admin/dashboard.astro`): Reads httpOnly cookies using server-side Supabase client ✅
|
|
3. **Dashboard Client Script** (`/src/lib/admin-api-router.ts`): Attempts to read httpOnly cookies using client-side Supabase client ❌
|
|
|
|
### Technical Details
|
|
- **httpOnly cookies**: Cannot be accessed by client-side JavaScript for security
|
|
- **Client-side Supabase**: `supabase.auth.getSession()` fails when cookies are httpOnly
|
|
- **Authentication mismatch**: Server says "authenticated" but client says "not authenticated"
|
|
|
|
### Secondary Issues Found
|
|
- **Missing database column**: Admin dashboard tried to select non-existent `is_super_admin` column
|
|
- **Database query failures**: Caused authentication to fail even with valid sessions
|
|
|
|
## Solution Implementation
|
|
|
|
### 1. Fixed Admin Dashboard Server-Side Auth
|
|
**File**: `/src/pages/admin/dashboard.astro`
|
|
|
|
**Problem**:
|
|
```typescript
|
|
.select('role, organization_id, is_super_admin') // is_super_admin doesn't exist
|
|
```
|
|
|
|
**Fix**:
|
|
```typescript
|
|
.select('role, organization_id') // Removed non-existent column
|
|
```
|
|
|
|
### 2. Created Server-Side Auth Check API
|
|
**File**: `/src/pages/api/admin/auth-check.ts` (NEW)
|
|
|
|
**Purpose**: Provides a server-side authentication check that client-side code can call
|
|
|
|
**Features**:
|
|
- Uses server-side Supabase client with access to httpOnly cookies
|
|
- Returns authentication status and user information
|
|
- Handles admin role verification
|
|
- Provides consistent error handling
|
|
|
|
**API Response**:
|
|
```typescript
|
|
{
|
|
authenticated: boolean,
|
|
isAdmin: boolean,
|
|
user?: {
|
|
id: string,
|
|
email: string,
|
|
name: string
|
|
},
|
|
organizationId?: string,
|
|
error?: string
|
|
}
|
|
```
|
|
|
|
### 3. Updated Admin API Router
|
|
**File**: `/src/lib/admin-api-router.ts`
|
|
|
|
**Before**:
|
|
```typescript
|
|
// Tried to use client-side Supabase (fails with httpOnly cookies)
|
|
const { data: { session }, error } = await supabase.auth.getSession();
|
|
```
|
|
|
|
**After**:
|
|
```typescript
|
|
// Uses server-side auth check API
|
|
const response = await fetch('/api/admin/auth-check', {
|
|
method: 'GET',
|
|
credentials: 'include'
|
|
});
|
|
```
|
|
|
|
## Testing & Validation
|
|
|
|
### Playwright Automated Testing
|
|
Used Playwright to create automated end-to-end tests that:
|
|
1. Navigate to login page
|
|
2. Fill credentials and submit form
|
|
3. Monitor network requests and cookie setting
|
|
4. Verify final redirect destination
|
|
5. Capture screenshots at each step
|
|
|
|
### Test Results
|
|
- **Before Fix**: Infinite redirect loop between login and dashboard
|
|
- **After Fix**: Successful login and stable dashboard access
|
|
|
|
### Test Files
|
|
- `/home/tyler/apps/bct-whitelabel/test-login.js`: Playwright test script
|
|
- `/home/tyler/apps/bct-whitelabel/test-recordings/`: Screenshots and recordings
|
|
|
|
## Implementation Details
|
|
|
|
### Authentication Flow (Fixed)
|
|
1. **User submits login form**
|
|
- Client sends credentials to `/api/auth/login`
|
|
- Login API validates credentials with Supabase
|
|
- Sets httpOnly session cookies
|
|
- Returns success + redirect path
|
|
|
|
2. **User redirected to dashboard**
|
|
- Server-side auth check reads httpOnly cookies
|
|
- Validates session and admin status
|
|
- Renders dashboard if authorized
|
|
|
|
3. **Dashboard client script initializes**
|
|
- Calls `/api/admin/auth-check` endpoint
|
|
- Server validates httpOnly cookies
|
|
- Returns authentication status to client
|
|
- Client proceeds with dashboard functionality
|
|
|
|
### Security Considerations
|
|
- **httpOnly cookies**: Maintain security by preventing client-side access
|
|
- **Server-side validation**: All authentication checks use server-side Supabase client
|
|
- **API endpoint security**: Auth check API validates session before returning user data
|
|
|
|
## Files Modified
|
|
|
|
### Primary Fixes
|
|
1. **`/src/pages/admin/dashboard.astro`**
|
|
- Fixed database query (removed `is_super_admin` column)
|
|
- Added proper error handling for user lookup
|
|
- Line 20: `select('role, organization_id')` instead of `select('role, organization_id, is_super_admin')`
|
|
|
|
2. **`/src/pages/api/admin/auth-check.ts`** (NEW)
|
|
- Created server-side authentication check API
|
|
- Handles admin role verification
|
|
- Returns user information for client-side use
|
|
|
|
3. **`/src/lib/admin-api-router.ts`**
|
|
- Replaced client-side Supabase auth with API call
|
|
- Line 17-20: Uses `fetch('/api/admin/auth-check')` instead of `supabase.auth.getSession()`
|
|
|
|
### Supporting Fixes
|
|
4. **`/src/pages/api/auth/session.ts`**
|
|
- Changed unauthenticated response from 401 to 200 status
|
|
- Prevents browser console errors for normal "not logged in" state
|
|
|
|
5. **`/src/pages/login.astro`**
|
|
- Enhanced session cache clearing after successful login
|
|
- Reduced cache duration for more responsive auth checks
|
|
- Added support for force refresh URL parameters
|
|
|
|
## Monitoring & Maintenance
|
|
|
|
### Key Metrics to Monitor
|
|
- **Login success rate**: Should be near 100% for valid credentials
|
|
- **Dashboard load time**: Should not have authentication delays
|
|
- **Session API calls**: Should not hit rate limits
|
|
|
|
### Future Improvements
|
|
- **Add `is_super_admin` column**: If super admin functionality is needed
|
|
- **Implement Redis caching**: For better session caching in production
|
|
- **Add authentication middleware**: For more centralized auth handling
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
1. **"User not authenticated or not admin" error**
|
|
- Check if user has `admin` role in database
|
|
- Verify session cookies are being set correctly
|
|
|
|
2. **404 on `/api/admin/auth-check`**
|
|
- Ensure the new API endpoint file was deployed
|
|
- Check that the file is in the correct location
|
|
|
|
3. **Still getting login loops**
|
|
- Clear browser cookies and sessionStorage
|
|
- Check if admin dashboard is using the updated admin-api-router
|
|
|
|
### Debug Commands
|
|
```bash
|
|
# Check user role in database
|
|
psql -c "SELECT email, role FROM users WHERE email = 'user@example.com';"
|
|
|
|
# Test auth check API directly
|
|
curl -H "Cookie: sb-..." http://localhost:3000/api/admin/auth-check
|
|
|
|
# Monitor auth-related logs
|
|
docker logs bct-astro-dev | grep -E "(LOGIN|AUTH|ADMIN)"
|
|
```
|
|
|
|
## Impact Summary
|
|
|
|
✅ **Fixed**: Login loop preventing dashboard access
|
|
✅ **Improved**: Authentication system reliability
|
|
✅ **Enhanced**: Error handling and debugging capabilities
|
|
✅ **Maintained**: Security with httpOnly cookies
|
|
✅ **Added**: Automated testing for authentication flow
|
|
|
|
The authentication system now works seamlessly across all user types and provides a stable foundation for the application. |