# Authentication, Authorization, and Accounting (AAA) Design ## Overview Implement a comprehensive AAA system for EuchreCamp with user authentication, role-based authorization, and activity logging using Next.js and Better Auth. ## Authentication (Who are you?) ### User Model (Prisma Schema) ```prisma // prisma/schema.prisma model User { id String @id @default(cuid()) email String @unique emailVerified Boolean @default(false) password String? name String? role Role @default(PLAYER) // Relationships player Player? @relation(fields: [playerId], references: [id]) playerId String? // Better Auth fields accounts Account[] sessions Session[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Player { id String @id @default(cuid()) name String rating Int @default(1000) user User? userId String? // Relationships matches Match[] partnerships Partnership[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } enum Role { PLAYER TOURNAMENT_ADMIN CLUB_ADMIN } ``` ### Authentication Flow (Better Auth) 1. User enters email and password 2. Better Auth verifies email exists 3. Password verification using secure hashing (scrypt by default) 4. If successful: - Create session token - Set secure HTTP-only cookie - Redirect to dashboard 5. If failed: - Rate limiting applied (Better Auth built-in) - Account lockout after multiple failed attempts ### Session Management (Better Auth) - **Session Storage**: Secure HTTP-only cookies - **Session Expiration**: Configurable (default 30 days) - **Session Invalidation**: On password change - **Concurrent Sessions**: Supported with session tracking ### Password Requirements - Minimum 8 characters - Configurable via Better Auth settings - Hashed with scrypt (server-side) ### Registration Flow (Next.js + Better Auth) 1. User registers with email and password via `/auth/register` 2. System creates user record with `emailVerified: false` 3. Email confirmation flow (if enabled) 4. User can log in after verification ### Password Reset Flow 1. User requests password reset via `/auth/reset-password` 2. System generates unique token 3. Email reset link to user 4. User enters new password 5. System validates and updates password hash 6. Invalidate all existing sessions ## Authorization (What can you do?) ### Role-Based Access Control (RBAC) #### Roles ```typescript // src/lib/auth.ts enum Role { PLAYER = 0, // Default user - can view rankings, own profile TOURNAMENT_ADMIN = 1, // Can manage specific tournaments CLUB_ADMIN = 2 // Superuser - full access } ``` #### Permission Matrix | Permission | Player | Tournament Admin | Club Admin | |------------|--------|------------------|------------| | View rankings | ✅ | ✅ | ✅ | | View own profile | ✅ | ✅ | ✅ | | Edit own profile | ✅ | ✅ | ✅ | | View other profiles | ✅ | ✅ | ✅ | | Record own matches | ✅ | ✅ | ✅ | | Create tournaments | ❌ | ✅ | ✅ | | Manage own tournaments | ❌ | ✅ | ✅ | | Manage all tournaments | ❌ | ❌ | ✅ | | Manage all players | ❌ | ❌ | ✅ | | Club settings | ❌ | ❌ | ✅ | ### Implementation ```typescript // src/lib/auth.ts import { betterAuth } from "better-auth"; import { prisma } from "./prisma"; export const auth = betterAuth({ database: prisma, emailAndPassword: { enabled: true, }, plugins: [ // Additional plugins as needed ], }); // Authorization helper export function can(user: User, action: string, resource?: any): boolean { switch (action) { case "view_rankings": return true; // All users can view rankings case "edit_profile": return !resource || resource.id === user.playerId; case "create_tournament": return user.role === "CLUB_ADMIN"; case "manage_tournament": return user.role === "CLUB_ADMIN" || (user.role === "TOURNAMENT_ADMIN" && resource.adminId === user.playerId); case "manage_players": return user.role === "CLUB_ADMIN"; default: return false; } } ``` ### Middleware ```typescript // src/middleware.ts import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; import { getSession } from "@/lib/auth"; export async function middleware(request: NextRequest) { const session = await getSession(request); // Protect admin routes if (request.nextUrl.pathname.startsWith("/admin")) { if (!session) { return NextResponse.redirect(new URL("/auth/login", request.url)); } if (session.user.role !== "CLUB_ADMIN") { return NextResponse.redirect(new URL("/unauthorized", request.url)); } } return NextResponse.next(); } export const config = { matcher: ["/admin/:path*"], }; ``` ## Accounting (What did you do?) ### Activity Logging (Prisma) ```prisma // prisma/schema.prisma model ActivityLog { id String @id @default(cuid()) userId String action String // e.g., 'login', 'create_tournament', 'record_match' resourceType String? // e.g., 'tournament', 'match', 'player' resourceId String? ipAddress String? userAgent String? details Json? // Additional context user User @relation(fields: [userId], references: [id]) createdAt DateTime @default(now()) @@index([userId, createdAt]) @@index([resourceType, resourceId]) } ``` ### Tracked Events - Authentication events (login, logout, password change) - Tournament management (create, update, delete, schedule) - Match recording (create, update, delete) - Player management (create, update) - Settings changes ### Audit Reports - User activity timeline - Tournament lifecycle audit - Match result verification log - System changes overview ### Implementation ```typescript // src/lib/activity.ts import { prisma } from "./prisma"; export async function logActivity( userId: string, action: string, resourceType?: string, resourceId?: string, details?: any ) { await prisma.activityLog.create({ data: { userId, action, resourceType, resourceId, details, ipAddress: "0.0.0.0", // Get from request userAgent: "unknown", // Get from request }, }); } ``` ## Implementation Plan ### Phase 1: Authentication (Week 1-2) - [x] Set up Better Auth with Prisma - [x] Create login page (`/auth/login`) - [x] Create registration page (`/auth/register`) - [x] Implement session management - [x] Add navigation for logged-in users - [ ] Password reset functionality - [ ] Email confirmation system ### Phase 2: Authorization (Week 2-3) - [x] Define roles in Prisma schema - [x] Implement RBAC middleware - [ ] Add role assignment UI (for club admins) - [ ] Protect routes based on roles - [ ] Add permission checks to API routes ### Phase 3: Accounting (Week 3-4) - [ ] Create activity logging system - [ ] Track key events - [ ] Build audit reports UI - [ ] Add activity feed to dashboard ### Phase 4: Security Hardening (Week 4-5) - [x] Rate limiting (Better Auth built-in) - [ ] IP-based lockout - [ ] Secure cookie settings - [ ] CSRF protection (Next.js built-in) - [ ] Security headers - [ ] Session fixation prevention ## Security Considerations ### Password Security - Use scrypt hashing (Better Auth default) - Never store plaintext passwords - Enforce strong password policy (via Better Auth) - Rate limit password attempts ### Session Security - Use signed, encrypted cookies - Regenerate session ID on privilege escalation - Set appropriate expiration times - Invalidate on password change ### Access Control - Principle of least privilege - Defense in depth - Fail securely (deny by default) - Log all access attempts ### Data Protection - Secure transmission (HTTPS only) - Regular security audits - Compliance with privacy regulations ## API Endpoints ### Authentication (Better Auth) ``` POST /api/auth/sign-up/email # Register new account POST /api/auth/sign-in/email # Login with email/password POST /api/auth/sign-out # Logout current session POST /api/auth/forgot-password # Request password reset POST /api/auth/reset-password # Reset password with token ``` ### Users ``` GET /api/users/me # Get current user profile PATCH /api/users/me # Update own profile GET /api/users/:id # Get user profile (public) ``` ### Admin ``` GET /api/admin/users # List users (club admin only) PATCH /api/admin/users/:id # Update user roles (club admin only) GET /api/admin/activity # View audit logs (club admin only) ``` ## Testing Strategy ### Unit Tests (Vitest) - Password hashing verification - Permission calculations - Session management - Activity logging ### Integration Tests - Login/logout flow - Registration process - Password reset - Role-based access ### Security Tests - SQL injection prevention (Prisma) - XSS prevention (Next.js) - CSRF protection (Next.js) - Rate limiting - Session security ## Migration Steps 1. Set up Better Auth with Prisma 2. Create users table and related models 3. Add foreign key from users to players 4. Update navigation to show login/logout links 5. Add authentication checks to existing routes 6. Implement role assignment for existing admins 7. Set up activity logging for new features