feat: set up authentication infrastructure with NextAuth.js v5

- Install next-auth@beta, bcryptjs, zod, and @auth/prisma-adapter
- Create auth.ts with credentials provider and JWT session strategy
- Create auth.config.ts for edge-compatible middleware configuration
- Add NextAuth type extensions for session and JWT
- Create API route handler for authentication
- Configure environment variables for NextAuth
- Add AUTH_SETUP.md documentation

Task: 1. Set up authentication infrastructure
Requirements: 1.1, 2.1
This commit is contained in:
2025-12-01 23:56:45 +00:00
parent b3c7f92877
commit 2c3b66b085
12 changed files with 1602 additions and 3 deletions

View File

@@ -0,0 +1,745 @@
# Design Document: User Authentication and Sharing
## Overview
This design extends the Ultimate Lists App to support multi-user authentication and collaborative list sharing. The system will implement secure user registration and login using NextAuth.js (Auth.js v5), session management with JWT tokens, and a permission-based access control system for list sharing.
The authentication system integrates seamlessly with the existing Next.js 14 App Router architecture, using Server Actions for authentication operations and middleware for route protection. The design maintains the current PWA capabilities while adding user-specific data isolation and collaborative features.
Key design decisions:
- **NextAuth.js v5** for authentication (industry-standard, well-maintained, Next.js 14 compatible)
- **Credentials provider** for email/password authentication
- **bcrypt** for password hashing
- **JWT sessions** for stateless authentication
- **Middleware-based route protection** for securing pages
- **Permission-based access control** with owner, editor, and viewer roles
- **Database-level access control** to ensure data isolation
## Architecture
### High-Level Architecture
```
┌─────────────────────────────────────────────────────────┐
│ Client Browser │
│ ┌──────────────────────────────────────────────────┐ │
│ │ React Components (RSC + Client) │ │
│ │ ┌────────────┐ ┌────────────┐ ┌───────────┐ │ │
│ │ │Auth Pages │ │ Components │ │ Hooks │ │ │
│ │ │Login/ │ │ (Protected)│ │ │ │ │
│ │ │Register │ │ │ │ │ │ │
│ │ └────────────┘ └────────────┘ └───────────┘ │ │
│ └──────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Service Worker (PWA) │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
│ HTTP/Server Actions
▼
┌─────────────────────────────────────────────────────────┐
│ Next.js Server │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Middleware │ │
│ │ (Route Protection & Auth) │ │
│ └──────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ NextAuth.js │ │
│ │ (Session Management & Authentication) │ │
│ └──────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Server Actions │ │
│ │ (Business Logic + Access Control) │ │
│ └──────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Prisma Client │ │
│ │ (Data Access with ACL) │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
│ SQL
▼
┌─────────────────────────────────────────────────────────┐
│ MySQL Database │
│ (Users, Lists, Items, Collaborators, Invitations) │
└─────────────────────────────────────────────────────────┘
```
### Technology Stack
**New Dependencies:**
- **next-auth@5.0.0-beta**: Authentication framework for Next.js
- **bcryptjs**: Password hashing library
- **@types/bcryptjs**: TypeScript types for bcryptjs
- **zod**: Schema validation for forms and API inputs
**Existing Stack:**
- Framework: Next.js 14 with App Router
- Language: TypeScript
- Database: MySQL with Prisma ORM
- UI: React 18 with Tailwind CSS
## Components and Interfaces
### Authentication Layer
**NextAuth Configuration (`auth.ts`)**
```typescript
// Core authentication configuration
export const authOptions = {
providers: [
CredentialsProvider({
credentials: { email, password },
authorize: async (credentials) => {
// Validate credentials
// Query user from database
// Verify password with bcrypt
// Return user object or null
}
})
],
session: { strategy: 'jwt' },
callbacks: {
jwt: async ({ token, user }) => {
// Add user ID to token
},
session: async ({ session, token }) => {
// Add user ID to session
}
},
pages: {
signIn: '/auth/login',
signOut: '/auth/logout',
error: '/auth/error'
}
}
```
**Middleware (`middleware.ts`)**
```typescript
// Protect routes requiring authentication
export function middleware(request: NextRequest) {
// Check authentication status
// Redirect to login if not authenticated
// Allow access if authenticated
}
export const config = {
matcher: ['/', '/list/:path*', '/profile/:path*']
}
```
**Authentication Actions (`lib/auth-actions.ts`)**
- `registerUser(email, password, name)`: Create new user account
- `validateCredentials(email, password)`: Verify login credentials
- `updatePassword(userId, currentPassword, newPassword)`: Change password
- `updateProfile(userId, data)`: Update user profile
- `deleteAccount(userId)`: Delete user and associated data
### Access Control Layer
**Permission Utilities (`lib/permissions.ts`)**
```typescript
type Permission = 'owner' | 'editor' | 'viewer'
// Check if user can access list
async function canAccessList(userId: string, listId: string): Promise<boolean>
// Check if user can edit list
async function canEditList(userId: string, listId: string): Promise<boolean>
// Check if user can delete list
async function canDeleteList(userId: string, listId: string): Promise<boolean>
// Get user's permission level for list
async function getPermission(userId: string, listId: string): Promise<Permission | null>
```
**Modified Server Actions (`lib/actions.ts`)**
All existing server actions will be modified to include access control:
- `getLists(userId)`: Get lists user owns or has access to
- `createList(userId, title, color)`: Create list owned by user
- `updateList(userId, listId, data)`: Update list if user has permission
- `deleteList(userId, listId)`: Delete list if user is owner
- `getListWithItems(userId, listId)`: Get list if user has access
- `createItem(userId, listId, data)`: Create item if user can edit
- `updateItem(userId, itemId, data)`: Update item if user can edit parent list
- `deleteItem(userId, itemId)`: Delete item if user can edit parent list
- `toggleItem(userId, itemId)`: Toggle item if user can edit parent list
**Sharing Actions (`lib/sharing-actions.ts`)**
- `inviteUserToList(ownerId, listId, email, permission)`: Create invitation
- `getInvitations(userId)`: Get pending invitations for user
- `acceptInvitation(userId, invitationId)`: Accept invitation and grant access
- `declineInvitation(userId, invitationId)`: Decline and remove invitation
- `getCollaborators(userId, listId)`: Get users with access to list
- `updateCollaboratorPermission(ownerId, listId, collaboratorId, permission)`: Change permission level
- `removeCollaborator(ownerId, listId, collaboratorId)`: Revoke access
### Presentation Layer
**New Pages**
- `/auth/login` - Login form
- `/auth/register` - Registration form
- `/auth/error` - Authentication error display
- `/profile` - User profile management
- `/invitations` - Pending invitations list
**New Components**
- `LoginForm`: Email/password login form with validation
- `RegisterForm`: Registration form with password requirements
- `ProfileForm`: Edit user profile information
- `PasswordChangeForm`: Change password with current password verification
- `InvitationCard`: Display invitation with accept/decline actions
- `CollaboratorList`: Show users with access to a list
- `ShareListModal`: Invite users to a list
- `PermissionBadge`: Display permission level (owner/editor/viewer)
- `ProtectedRoute`: Wrapper component for authenticated routes
**Modified Components**
- `ListCard`: Show sharing indicator if list has collaborators
- `ListDetailView`: Add share button for owners, show permission level
- `ItemForm`: Disable editing for viewers
## Data Models
### New Database Models
**User Model**
```typescript
{
id: string (cuid)
email: string (unique)
name: string | null
passwordHash: string
createdAt: DateTime
updatedAt: DateTime
ownedLists: List[] (relation)
collaborations: Collaborator[] (relation)
sentInvitations: Invitation[] (relation)
receivedInvitations: Invitation[] (relation)
}
```
**Collaborator Model** (Join table for list sharing)
```typescript
{
id: string (cuid)
userId: string
listId: string
permission: 'editor' | 'viewer'
createdAt: DateTime
user: User (relation)
list: List (relation)
@@unique([userId, listId])
}
```
**Invitation Model**
```typescript
{
id: string (cuid)
email: string
listId: string
inviterId: string
permission: 'editor' | 'viewer'
status: 'pending' | 'accepted' | 'declined'
createdAt: DateTime
expiresAt: DateTime
list: List (relation)
inviter: User (relation)
}
```
### Modified Database Models
**List Model** (add owner relationship)
```typescript
{
id: string (cuid)
title: string
color: string
ownerId: string (new)
createdAt: DateTime
updatedAt: DateTime
owner: User (new relation)
items: Item[]
collaborators: Collaborator[] (new relation)
invitations: Invitation[] (new relation)
}
```
**Item Model** (no changes to schema, but queries will check list access)
```typescript
{
// Existing fields remain the same
// Access control enforced through parent list
}
```
### Session Model
**Session Data** (stored in JWT)
```typescript
{
user: {
id: string
email: string
name: string | null
}
expires: string (ISO date)
}
```
## Correctness Properties
*A property is a characteristic or behavior that should hold true across all valid executions of a system—essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
### User Registration Properties
**Property 1: Registration creates unique user**
*For any* valid email and password, registering a new user should create a user account with a unique identifier that differs from all existing user identifiers.
**Validates: Requirements 1.1**
**Property 2: Duplicate email rejection**
*For any* existing user email, attempting to register with that email should be rejected and return an error.
**Validates: Requirements 1.2**
**Property 3: Password hashing on registration**
*For any* user registration with a password, the stored password value in the database should be a valid bcrypt hash and should not equal the plain text password.
**Validates: Requirements 1.3**
**Property 4: Registration creates session**
*For any* successful user registration, a valid session should be created for that user immediately after registration.
**Validates: Requirements 1.4**
**Property 5: Password length validation**
*For any* password with fewer than 8 characters, registration should be rejected and return a validation error.
**Validates: Requirements 1.5**
### Authentication Properties
**Property 6: Valid credentials create session**
*For any* registered user with known password, submitting correct credentials should authenticate the user and create a valid session.
**Validates: Requirements 2.1**
**Property 7: Invalid credentials rejection**
*For any* login attempt with incorrect password or non-existent email, authentication should fail and return an error.
**Validates: Requirements 2.2**
**Property 8: Session expiration enforcement**
*For any* expired session token, attempting to access protected resources should be denied.
**Validates: Requirements 2.4**
**Property 9: Logout terminates session**
*For any* authenticated user, after logging out, the session token should become invalid and subsequent requests should be denied.
**Validates: Requirements 2.5**
### Session Management Properties
**Property 10: Secure token generation**
*For any* successful login, a session token should be created with sufficient entropy and proper format.
**Validates: Requirements 3.1**
**Property 11: Session persistence**
*For any* valid session token, re-validating the token should maintain the authenticated state with the same user information.
**Validates: Requirements 3.2**
**Property 12: Session duration persistence**
*For any* session created, the session should remain valid for the configured duration even after simulated browser close/reopen.
**Validates: Requirements 3.4**
### List Ownership Properties
**Property 13: List ownership assignment**
*For any* user creating a list, the created list should have its ownerId set to the creating user's ID.
**Validates: Requirements 4.1**
**Property 14: List access filtering**
*For any* user querying for lists, the results should include only lists where the user is the owner or has a collaborator record, and should include all such lists.
**Validates: Requirements 4.2, 4.4**
**Property 15: Unauthorized list access denial**
*For any* user attempting to access a list they don't own and aren't a collaborator on, the access should be denied and return an error.
**Validates: Requirements 4.3**
**Property 16: Account deletion cascades to lists**
*For any* user with owned lists, deleting the user account should result in all owned lists being removed from the database.
**Validates: Requirements 4.5**
### Invitation Properties
**Property 17: Invitation creation with unique ID**
*For any* list owner inviting a user by email, an invitation record should be created with a unique identifier and the specified permission level.
**Validates: Requirements 5.1, 6.1**
**Property 18: Invitation acceptance grants access**
*For any* pending invitation, when the invited user accepts it, a collaborator record should be created granting the user access to the list with the specified permission.
**Validates: Requirements 5.2**
**Property 19: Invitation decline removes record**
*For any* pending invitation, when the invited user declines it, the invitation should be removed from the database.
**Validates: Requirements 5.3**
**Property 20: Collaborator list completeness**
*For any* list with collaborators, querying the collaborators should return all users who have access including their permission levels.
**Validates: Requirements 5.4**
**Property 21: Access revocation enforcement**
*For any* collaborator with access to a list, after the owner revokes access, the user should no longer be able to access the list.
**Validates: Requirements 5.5**
### Permission Properties
**Property 22: Editor permission allows modifications**
*For any* user with editor permission on a list, the user should be able to create, update, and delete items in that list.
**Validates: Requirements 6.2**
**Property 23: Viewer permission prevents modifications**
*For any* user with viewer permission on a list, attempts to create, update, or delete items should be denied and return an error.
**Validates: Requirements 6.3, 6.4**
**Property 24: Permission update enforcement**
*For any* collaborator with editor permission, after the owner changes their permission to viewer, item modification attempts should be denied.
**Validates: Requirements 6.5**
### Profile Management Properties
**Property 25: Profile update persistence**
*For any* user updating profile information, the changes should be saved and associated with the correct user account.
**Validates: Requirements 7.1**
**Property 26: Password change requires current password**
*For any* password change attempt with incorrect current password, the change should be rejected and return an error.
**Validates: Requirements 7.2**
**Property 27: Password hashing on change**
*For any* successful password change, the new password should be stored as a bcrypt hash and not as plain text.
**Validates: Requirements 7.3**
**Property 28: Email uniqueness validation**
*For any* attempt to update email to an address already in use by another user, the update should be rejected and return an error.
**Validates: Requirements 7.4**
**Property 29: Profile data exposure protection**
*For any* user profile query, the returned data should not include the password hash or other sensitive authentication data.
**Validates: Requirements 7.5**
### Invitation Notification Properties
**Property 30: Invitation visibility**
*For any* invitation created for a user's email, querying that user's pending invitations should include the invitation.
**Validates: Requirements 8.1**
**Property 31: Invitation details completeness**
*For any* pending invitation, the invitation data should include the list name and inviter information.
**Validates: Requirements 8.2**
**Property 32: Invitation removal after action**
*For any* invitation that is accepted or declined, the invitation should no longer appear in the user's pending invitations list.
**Validates: Requirements 8.4**
**Property 33: Invitation timestamp recording**
*For any* created invitation, the invitation should have a createdAt timestamp that is set to the time of creation.
**Validates: Requirements 8.5**
### Data Isolation Properties
**Property 34: Item access through list permission**
*For any* user querying items, only items from lists the user has access to should be returned.
**Validates: Requirements 9.2**
### Migration Properties
**Property 35: Migration data preservation**
*For any* list migrated to a user account, all list data including items, metadata, and timestamps should remain unchanged after migration.
**Validates: Requirements 10.3**
## Error Handling
### Authentication Errors
**Invalid Credentials**
- Return clear error messages without revealing whether email exists
- Log failed login attempts for security monitoring
- Implement rate limiting to prevent brute force attacks
**Session Errors**
- Handle expired sessions gracefully with redirect to login
- Clear invalid tokens from client storage
- Provide clear feedback when re-authentication is required
**Registration Errors**
- Validate email format before database query
- Check password requirements client-side and server-side
- Return specific validation errors for each field
### Authorization Errors
**Access Denied**
- Return 403 Forbidden for unauthorized access attempts
- Log unauthorized access attempts
- Provide user-friendly error messages
**Permission Errors**
- Check permissions before executing operations
- Return clear error messages indicating required permission level
- Prevent information leakage about resources user can't access
### Database Errors
**Constraint Violations**
- Handle unique constraint violations (duplicate email)
- Manage foreign key constraints properly
- Use transactions for multi-step operations
**Connection Failures**
- Implement retry logic with exponential backoff
- Provide fallback error messages
- Log database errors for debugging
### Invitation Errors
**Invalid Invitations**
- Validate email format before creating invitation
- Check if user is already a collaborator
- Handle expired invitations gracefully
**Invitation Conflicts**
- Prevent duplicate invitations to same email for same list
- Handle case where invited email doesn't exist yet
- Manage invitation expiration
## Testing Strategy
### Unit Testing
The application will use **Vitest** as the testing framework for unit tests. Unit tests will focus on:
**Authentication Layer**
- Password hashing and verification
- Token generation and validation
- Credential validation logic
- Session creation and management
**Access Control Layer**
- Permission checking functions
- Access control filtering logic
- Collaborator management operations
**Business Logic**
- Invitation creation and acceptance flow
- Profile update operations
- List ownership assignment
- Cascade deletion logic
**Utility Functions**
- Email validation
- Password strength validation
- Token generation
- Data sanitization
Unit tests will use realistic test data and verify specific examples, edge cases, and error conditions.
### Property-Based Testing
The application will use **fast-check** as the property-based testing library. Property-based tests will verify the universal correctness properties defined in this document.
**Configuration Requirements:**
- Each property-based test MUST run a minimum of 100 iterations
- Each test MUST be tagged with a comment referencing the correctness property
- Tag format: `// Feature: user-auth-and-sharing, Property {number}: {property_text}`
- Each correctness property MUST be implemented by a SINGLE property-based test
**Property Test Coverage:**
- User registration (Properties 1-5)
- Authentication (Properties 6-9)
- Session management (Properties 10-12)
- List ownership (Properties 13-16)
- Invitations (Properties 17-21)
- Permissions (Properties 22-24)
- Profile management (Properties 25-29)
- Invitation notifications (Properties 30-33)
- Data isolation (Property 34)
- Migration (Property 35)
**Test Data Generation:**
Property-based tests will use custom generators for:
- Valid email addresses
- Passwords of various lengths
- User IDs (cuid format)
- Permission levels (owner, editor, viewer)
- Invitation statuses
- Session tokens
- Profile data
### Integration Testing
Integration tests will verify:
- End-to-end authentication flows (register → login → access protected resource)
- List sharing workflows (invite → accept → collaborate)
- Permission enforcement across the stack
- Session persistence across requests
- Middleware integration with authentication
### Security Testing
Security tests will verify:
- Password hashing strength
- Session token security
- SQL injection prevention
- XSS prevention in user inputs
- CSRF protection
- Rate limiting effectiveness
## Performance Considerations
### Authentication Performance
- Cache session validation results
- Use efficient bcrypt work factor (10-12 rounds)
- Implement connection pooling for database
- Index user email field for fast lookups
### Access Control Performance
- Index foreign keys (userId, listId in Collaborator table)
- Cache permission checks for frequently accessed lists
- Use database-level filtering for access control
- Implement efficient JOIN queries for list retrieval
### Session Management
- Use stateless JWT tokens to avoid database lookups
- Set appropriate token expiration times
- Implement token refresh mechanism if needed
- Use secure, httpOnly cookies for token storage
## Security Considerations
### Password Security
- Use bcrypt with appropriate work factor (10-12 rounds)
- Enforce minimum password length (8 characters)
- Consider additional password requirements (complexity)
- Never log or expose passwords in plain text
- Implement password reset functionality securely
### Session Security
- Use cryptographically secure random token generation
- Set httpOnly and secure flags on session cookies
- Implement CSRF protection
- Use short session expiration times
- Implement session invalidation on logout
### Access Control Security
- Enforce access control at database query level
- Never trust client-side permission checks
- Validate user identity on every request
- Use parameterized queries to prevent SQL injection
- Implement rate limiting on sensitive operations
### Data Protection
- Encrypt sensitive data at rest
- Use HTTPS for all communications
- Implement proper CORS policies
- Sanitize all user inputs
- Follow principle of least privilege
### Invitation Security
- Implement invitation expiration
- Validate email addresses
- Prevent invitation spam
- Rate limit invitation creation
- Verify inviter has permission to share
## Migration Strategy
### Data Migration
**Phase 1: Schema Updates**
1. Add User table to database
2. Add Collaborator table
3. Add Invitation table
4. Add ownerId field to List table (nullable initially)
**Phase 2: Migration Script**
1. Create a default "system" user for existing lists
2. Associate all existing lists with system user
3. Provide UI for users to claim lists by creating accounts
4. Make ownerId non-nullable after migration
**Phase 3: Deployment**
1. Deploy authentication system
2. Run migration script
3. Enable authentication requirements
4. Monitor for issues
### Backward Compatibility
- Maintain existing API endpoints during transition
- Provide grace period for users to create accounts
- Preserve all existing list and item data
- Ensure PWA functionality continues to work
## Deployment Considerations
### Environment Variables
```
DATABASE_URL=mysql://...
NEXTAUTH_URL=https://yourdomain.com
NEXTAUTH_SECRET=<generated-secret>
JWT_SECRET=<generated-secret>
```
### Database Migrations
1. Run Prisma migrations: `npx prisma migrate dev`
2. Generate Prisma client: `npx prisma generate`
3. Run data migration script if needed
4. Verify schema changes in production
### Monitoring
- Track failed login attempts
- Monitor session creation/expiration
- Log unauthorized access attempts
- Track invitation acceptance rates
- Monitor database query performance
## Future Enhancements
### Authentication Features
- OAuth providers (Google, GitHub, etc.)
- Two-factor authentication
- Password reset via email
- Email verification
- Remember me functionality
- Account recovery options
### Collaboration Features
- Real-time collaboration indicators
- Activity feed for shared lists
- Comments on items
- @mentions in notes
- Notification system for list updates
- Team/organization support
### Permission Enhancements
- Custom permission levels
- Granular item-level permissions
- Temporary access grants
- Permission templates
- Audit log for permission changes