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 (