# Authentication Protection Strategy ## Overview GridPilot website implements a **defense-in-depth** authentication protection strategy using both **middleware-level** and **component-level** protection to ensure authenticated routes are properly secured. ## Protection Layers ### 1. Middleware Protection (First Line of Defense) **File**: `apps/website/middleware.ts` The middleware provides **server-side** route protection that runs before any page rendering: ```typescript // Key protection logic export function middleware(request: NextRequest) { const mode = getAppMode(); const { pathname } = request.nextUrl; // Public routes are always accessible if (isPublicRoute(pathname)) { return NextResponse.next(); } // Check for authentication cookie const cookies = request.cookies; const hasAuthCookie = cookies.has('gp_session'); // In alpha mode, redirect to login if no session if (mode === 'alpha' && !hasAuthCookie) { const loginUrl = new URL('/auth/login', request.url); loginUrl.searchParams.set('returnTo', pathname); return NextResponse.redirect(loginUrl); } // In pre-launch mode, return 404 for protected routes return new NextResponse(null, { status: 404, statusText: 'Not Found', }); } ``` **Protected Routes** (not in public list): - `/dashboard` - `/profile/*` - `/onboarding` - `/sponsor/*` - `/admin/*` - All other non-public routes **Public Routes**: - `/` (home) - `/auth/*` (login, signup, etc.) - `/api/auth/*` (auth API endpoints) ### 2. Component-Level Protection (Second Line of Defense) **Files**: Layout components in protected routes Each protected route group has a layout that wraps content with `AuthGuard`: #### Dashboard Layout **File**: `apps/website/app/dashboard/layout.tsx` ```typescript export default function DashboardLayout({ children }: DashboardLayoutProps) { return (
{children}
); } ``` #### Profile Layout **File**: `apps/website/app/profile/layout.tsx` ```typescript export default function ProfileLayout({ children }: ProfileLayoutProps) { return (
{children}
); } ``` #### Sponsor Layout **File**: `apps/website/app/sponsor/layout.tsx` ```typescript export default function SponsorLayout({ children }: SponsorLayoutProps) { return (
{children}
); } ``` #### Onboarding Layout **File**: `apps/website/app/onboarding/layout.tsx` ```typescript export default function OnboardingLayout({ children }: OnboardingLayoutProps) { return (
{children}
); } ``` #### Admin Layout **File**: `apps/website/app/admin/layout.tsx` ```typescript export default function AdminLayout({ children }: AdminLayoutProps) { return (
{children}
); } ``` ### 3. Page-Level Protection (Third Line of Defense - Defense in Depth) **File**: `apps/website/app/dashboard/page.tsx` The dashboard page includes additional client-side verification: ```typescript export default function DashboardPage() { const router = useRouter(); const { session, loading: authLoading } = useAuth(); const { data: dashboardData, isLoading, error } = useDashboardOverview(); // Additional client-side auth check (defense in depth) useEffect(() => { if (!authLoading && !session) { router.push('/auth/login?returnTo=/dashboard'); } }, [session, authLoading, router]); // Show loading state during auth check if (authLoading) { return (
Verifying authentication...
); } // Redirect if not authenticated (should be caught by layout, but this is extra safety) if (!session) { return null; // Layout will handle redirect } // ... rest of dashboard content } ``` ## Authentication Flow ### Unauthenticated User Accessing Protected Route 1. **Middleware Intercept**: User requests `/dashboard` 2. **Cookie Check**: Middleware checks for `gp_session` cookie 3. **Redirect**: If no cookie, redirect to `/auth/login?returnTo=/dashboard` 4. **Login**: User authenticates via login flow 5. **Session Creation**: API creates session, sets `gp_session` cookie 6. **Return**: User redirected back to `/dashboard` 7. **AuthGuard**: Layout verifies session exists 8. **Page Render**: Dashboard content loads ### Authenticated User Accessing Protected Route 1. **Middleware Intercept**: User requests `/dashboard` 2. **Cookie Check**: Middleware finds `gp_session` cookie 3. **Access Granted**: Request proceeds to page rendering 4. **AuthGuard**: Layout verifies session via AuthContext 5. **Page Render**: Dashboard content loads ### Role-Based Access (Admin Routes) 1. **Middleware**: Checks for authentication cookie 2. **RouteGuard**: Verifies user has required roles (`owner`, `admin`) 3. **Access**: Only granted if both conditions pass ## Security Features ### 1. Cookie Security - Session cookie: `gp_session` - Secure transmission via HTTPS - HttpOnly flag (server-side) - SameSite policy ### 2. Session Validation - Client-side session verification via AuthContext - Server-side session validation via API - Automatic redirect on session loss ### 3. Error Handling - Loading states during auth verification - Graceful redirects for unauthorized access - Clear error messages for users ### 4. Defense in Depth - Multiple protection layers (middleware + layout + page) - Each layer independently verifies authentication - Reduces single point of failure ## Route Protection Matrix | Route Group | Middleware | Layout Guard | Page-Level Check | Role Required | |-------------|------------|--------------|------------------|---------------| | `/` | ✅ Public | ❌ None | ❌ None | None | | `/auth/*` | ✅ Public | ❌ None | ❌ None | None | | `/dashboard` | ✅ Protected | ✅ AuthGuard | ✅ Yes | None | | `/profile/*` | ✅ Protected | ✅ AuthGuard | ❌ None | None | | `/onboarding` | ✅ Protected | ✅ AuthGuard | ❌ None | None | | `/sponsor/*` | ✅ Protected | ✅ AuthGuard | ❌ None | None | | `/admin/*` | ✅ Protected | ✅ RouteGuard | ❌ None | owner/admin | | `/leagues` | ✅ Public | ❌ None | ❌ None | None | | `/teams` | ✅ Public | ❌ None | ❌ None | None | | `/drivers` | ✅ Public | ❌ None | ❌ None | None | | `/leaderboards` | ✅ Public | ❌ None | ❌ None | None | | `/races` | ✅ Public | ❌ None | ❌ None | None | ## Testing Authentication Protection ### Test Scenarios 1. **Unauthenticated Access to Protected Route** - Navigate to `/dashboard` without login - Expected: Redirect to `/auth/login?returnTo=/dashboard` 2. **Authenticated Access to Protected Route** - Login successfully - Navigate to `/dashboard` - Expected: Dashboard loads with user data 3. **Session Expiry** - Login, navigate to `/dashboard` - Clear session cookie - Expected: Redirect to login on next action 4. **Role-Based Access** - Non-admin user tries `/admin` - Expected: Redirect to login (or 404 in pre-launch mode) ### Manual Testing Commands ```bash # Test 1: Unauthenticated access curl -I http://localhost:3000/dashboard # Should redirect to /auth/login # Test 2: Check middleware response curl -I http://localhost:3000/dashboard -H "Cookie: gp_session=valid_token" # Should return 200 OK # Test 3: Check public routes curl -I http://localhost:3000/leagues # Should return 200 OK (no auth required) ``` ## Maintenance Notes ### Adding New Protected Routes 1. **Add to middleware** if it needs authentication: ```typescript // In isPublicRoute() function const publicRoutes = [ // ... existing routes // '/new-public-route', // Add if public ]; ``` 2. **Create layout file** for route group: ```typescript // app/new-route/layout.tsx export default function NewRouteLayout({ children }) { return ( {children} ); } ``` 3. **Test thoroughly**: - Unauthenticated access → redirect - Authenticated access → works - Session expiry → redirect ### Security Best Practices 1. **Always use both middleware and component guards** 2. **Never rely on only one protection layer** 3. **Test session expiry scenarios** 4. **Monitor for authentication bypass attempts** 5. **Keep public routes list minimal** ## Current Implementation Status ✅ **Complete Protection**: - Dashboard route with multi-layer protection - Profile routes with AuthGuard - Sponsor routes with AuthGuard - Admin routes with role-based protection - Onboarding routes with AuthGuard ✅ **Public Routes**: - Home page - Auth pages - Discovery pages (leagues, teams, drivers, races, leaderboards) ✅ **Security Features**: - Defense-in-depth architecture - Role-based access control - Session validation - Graceful error handling - Clear user feedback ✅ **Loading State Fixes**: - Fixed infinite loading issue - Proper session state management - Clear authentication flow feedback - No more "stuck on loading" problems ## Known Issues Fixed ### Loading State Problem (RESOLVED) **Issue**: Users experienced infinite "Loading..." state on dashboard **Root Cause**: Multiple authentication state systems conflicting **Solution**: Unified loading state management across AuthContext, AuthGateway, and RouteGuard **Changes Made**: 1. AuthContext now properly tracks loading state during session fetch 2. AuthGateway only uses authContext.loading for isLoading state 3. AuthorizationBlocker treats null session as unauthenticated (not loading) 4. RouteGuard provides clear feedback during authentication verification 5. Dashboard page simplified to remove redundant auth checks **Result**: Authentication flow now works smoothly with proper redirects and no infinite loading. The authentication protection strategy is **comprehensive and secure** for production use.