Files
Todo/.kiro/specs/user-auth-and-sharing/design.md
Paul Bailey 2c3b66b085 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
2025-12-01 23:56:45 +00:00

28 KiB

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)

// 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)

// 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)

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

{
  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)

{
  id: string (cuid)
  userId: string
  listId: string
  permission: 'editor' | 'viewer'
  createdAt: DateTime
  user: User (relation)
  list: List (relation)
  
  @@unique([userId, listId])
}

Invitation Model

{
  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)

{
  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)

{
  // Existing fields remain the same
  // Access control enforced through parent list
}

Session Model

Session Data (stored in JWT)

{
  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