Need help logging in?
37 |38 | We'll make it easy. What do you need help with? 39 |
40 |├── .cursor
└── rules
│ ├── auth-workflows.mdc
│ ├── component-architecture.mdc
│ ├── data-models.mdc
│ └── security-algorithms.mdc
├── .cursorignore
├── .env.example
├── .giga
└── specifications.json
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── bun.lock
├── components.json
├── docs
├── auth-flow.md
├── cleanup-setup.md
├── flow-questions.md
├── plan.md
├── project-overview.md
├── roadmap.md
├── supabase-email-templates.md
├── supabase-snippets.md
└── verification-example.tsx
├── emails
├── components
│ └── header.tsx
└── templates
│ ├── data-export-ready.tsx
│ ├── data-export-requested.tsx
│ ├── device-verification.tsx
│ ├── email-alert.tsx
│ └── email-verification.tsx
├── next.config.ts
├── package.json
├── postcss.config.mjs
├── scripts
└── reset-project.ts
├── src
├── app
│ ├── account
│ │ ├── data
│ │ │ └── page.tsx
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ └── security
│ │ │ └── page.tsx
│ ├── api
│ │ └── auth
│ │ │ ├── 2fa
│ │ │ ├── disable
│ │ │ │ └── route.ts
│ │ │ └── enroll
│ │ │ │ └── route.ts
│ │ │ ├── callback
│ │ │ └── route.ts
│ │ │ ├── change-email
│ │ │ └── route.ts
│ │ │ ├── change-password
│ │ │ └── route.ts
│ │ │ ├── confirm
│ │ │ └── route.ts
│ │ │ ├── data-exports
│ │ │ ├── [id]
│ │ │ │ ├── download
│ │ │ │ │ └── route.ts
│ │ │ │ └── route.ts
│ │ │ └── route.ts
│ │ │ ├── device-sessions
│ │ │ ├── current
│ │ │ │ └── route.ts
│ │ │ ├── geolocation
│ │ │ │ └── route.ts
│ │ │ ├── revoke
│ │ │ │ └── route.ts
│ │ │ ├── route.ts
│ │ │ └── trusted
│ │ │ │ └── route.ts
│ │ │ ├── email
│ │ │ ├── check
│ │ │ │ └── route.ts
│ │ │ ├── login
│ │ │ │ └── route.ts
│ │ │ ├── resend-confirmation
│ │ │ │ └── route.ts
│ │ │ ├── send-verification
│ │ │ │ └── route.ts
│ │ │ └── signup
│ │ │ │ └── route.ts
│ │ │ ├── forgot-password
│ │ │ └── route.ts
│ │ │ ├── github
│ │ │ └── signin
│ │ │ │ └── route.ts
│ │ │ ├── google
│ │ │ └── signin
│ │ │ │ └── route.ts
│ │ │ ├── logout
│ │ │ └── route.ts
│ │ │ ├── post-auth
│ │ │ └── route.ts
│ │ │ ├── reset-password
│ │ │ └── route.ts
│ │ │ ├── send-email-alert
│ │ │ └── route.ts
│ │ │ ├── social
│ │ │ ├── connect
│ │ │ │ └── route.ts
│ │ │ └── disconnect
│ │ │ │ └── route.ts
│ │ │ ├── user
│ │ │ ├── avatar
│ │ │ │ └── update
│ │ │ │ │ └── route.ts
│ │ │ ├── delete
│ │ │ │ └── route.ts
│ │ │ ├── events
│ │ │ │ └── route.ts
│ │ │ ├── route.ts
│ │ │ └── update
│ │ │ │ └── route.ts
│ │ │ ├── verify-device
│ │ │ ├── route.ts
│ │ │ └── send-code
│ │ │ │ └── route.ts
│ │ │ └── verify
│ │ │ └── route.ts
│ ├── auth
│ │ ├── error
│ │ │ └── page.tsx
│ │ ├── forgot-password
│ │ │ └── page.tsx
│ │ ├── login-help
│ │ │ └── page.tsx
│ │ ├── login
│ │ │ └── page.tsx
│ │ ├── reset-password
│ │ │ └── page.tsx
│ │ ├── signup
│ │ │ └── page.tsx
│ │ └── verify-device
│ │ │ └── page.tsx
│ ├── dashboard
│ │ └── page.tsx
│ ├── favicon.ico
│ ├── fonts
│ │ ├── GeistMonoVF.woff
│ │ └── GeistVF.woff
│ ├── globals.css
│ ├── layout.tsx
│ └── page.tsx
├── components
│ ├── 2fa-methods.tsx
│ ├── 2fa-setup-dialog.tsx
│ ├── auth-confirm.tsx
│ ├── auth-form.tsx
│ ├── back-button.tsx
│ ├── data-export.tsx
│ ├── delete-account.tsx
│ ├── device-sessions-list.tsx
│ ├── event-log.tsx
│ ├── header.tsx
│ ├── revoke-all-devices.tsx
│ ├── social-providers.tsx
│ ├── ui
│ │ ├── accordion.tsx
│ │ ├── alert-dialog.tsx
│ │ ├── alert.tsx
│ │ ├── aspect-ratio.tsx
│ │ ├── avatar.tsx
│ │ ├── badge.tsx
│ │ ├── breadcrumb.tsx
│ │ ├── button.tsx
│ │ ├── calendar.tsx
│ │ ├── card.tsx
│ │ ├── carousel.tsx
│ │ ├── chart.tsx
│ │ ├── checkbox.tsx
│ │ ├── collapsible.tsx
│ │ ├── command.tsx
│ │ ├── context-menu.tsx
│ │ ├── dialog.tsx
│ │ ├── drawer.tsx
│ │ ├── dropdown-menu.tsx
│ │ ├── form.tsx
│ │ ├── hover-card.tsx
│ │ ├── input-otp.tsx
│ │ ├── input.tsx
│ │ ├── label.tsx
│ │ ├── menubar.tsx
│ │ ├── navigation-menu.tsx
│ │ ├── pagination.tsx
│ │ ├── phone-input.tsx
│ │ ├── popover.tsx
│ │ ├── progress.tsx
│ │ ├── radio-group.tsx
│ │ ├── resizable.tsx
│ │ ├── scroll-area.tsx
│ │ ├── select.tsx
│ │ ├── separator.tsx
│ │ ├── sheet.tsx
│ │ ├── sidebar.tsx
│ │ ├── skeleton.tsx
│ │ ├── slider.tsx
│ │ ├── sonner.tsx
│ │ ├── switch.tsx
│ │ ├── table.tsx
│ │ ├── tabs.tsx
│ │ ├── textarea.tsx
│ │ ├── toast.tsx
│ │ ├── toaster.tsx
│ │ ├── toggle-group.tsx
│ │ ├── toggle.tsx
│ │ └── tooltip.tsx
│ ├── url-error-handler.tsx
│ ├── user-dropdown.tsx
│ ├── user-provider.tsx
│ └── verify-form.tsx
├── config
│ └── auth.ts
├── hooks
│ ├── use-account-events.ts
│ ├── use-auth.ts
│ ├── use-data-exports.ts
│ ├── use-device-sessions.ts
│ ├── use-mobile.tsx
│ └── use-toast.ts
├── lib
│ └── utils.ts
├── middleware.ts
├── trigger
│ └── user-data-exports.ts
├── types
│ ├── api.ts
│ └── auth.ts
├── utils
│ ├── account-events
│ │ └── server.ts
│ ├── api.ts
│ ├── auth
│ │ ├── device-sessions
│ │ │ ├── index.ts
│ │ │ └── server.ts
│ │ ├── index.ts
│ │ ├── recovery-token.ts
│ │ └── verification-codes.ts
│ ├── data-export
│ │ ├── index.ts
│ │ └── server.ts
│ ├── email-alerts.ts
│ ├── rate-limit.ts
│ └── supabase
│ │ ├── client.ts
│ │ ├── middleware.ts
│ │ └── server.ts
└── validation
│ └── auth-validation.ts
├── tailwind.config.ts
├── trigger.config.ts
└── tsconfig.json
/.cursor/rules/auth-workflows.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description:
3 | globs:
4 | alwaysApply: true
5 | ---
6 | # auth-workflows
7 |
8 | ### Two-Factor Authentication (2FA) Implementation
9 | - MUST: Implement 2FA using authenticator apps and SMS with the following flow:
10 | 1. Generate verification codes using `src/utils/auth/verification-codes.ts`
11 | 2. Validate codes against hashes
12 | - AVOID:
13 | - Storing raw verification codes
14 | - Using email as primary 2FA method
15 | - Implementing custom code generation
16 | - WHY: Ensures secure time-based verification while following industry standards
17 | - EXAMPLE: `src/utils/auth/verification-codes.ts`
18 |
19 | ### Device Trust Calculation
20 | - MUST: Calculate device trust scores using:
21 | - Device name match (30 points)
22 | - Browser match (20 points)
23 | - OS match (20 points)
24 | - IP range match (15 points)
25 | - AVOID:
26 | - Storing raw device identifiers
27 | - Using location as primary trust factor
28 | - Skipping verification for partially trusted devices
29 | - WHY: Provides risk-based authentication while protecting user privacy
30 | - EXAMPLE: `src/utils/auth/index.ts`
31 |
32 | ### Session Management
33 | - MUST: Implement sessions with:
34 | 1. Device fingerprinting via `src/utils/auth/device-sessions/server.ts`
35 | 2. Session revocation requiring 2FA via `src/components/device-sessions-list.tsx`
36 | 3. Location tracking for non-local IPs
37 | - AVOID:
38 | - Storing sessions without device context
39 | - Auto-extending expired sessions
40 | - Using client-side session storage
41 | - WHY: Enables secure multi-device access while maintaining user control
42 | - EXAMPLE: `src/hooks/use-device-sessions.ts`
43 |
44 | ### Account Security Events
45 | - MUST: Log security events with:
46 | - Device information
47 | - Event category (success/warning/error)
48 | - Verification method used
49 | - IP address and location
50 | - AVOID:
51 | - Logging sensitive data
52 | - Missing critical security events
53 | - Delayed event logging
54 | - WHY: Provides audit trail and security monitoring
55 | - EXAMPLE: `src/utils/account-events/server.ts`
56 |
57 | ### Email Alert System
58 | - MUST: Send alerts for:
59 | - New device logins
60 | - 2FA changes
61 | - Password changes
62 | - Email changes
63 | - Account deletion
64 | - AVOID:
65 | - Sending alerts without device context
66 | - Using generic templates
67 | - Blocking main operations on alert failure
68 | - WHY: Keeps users informed of security-relevant account changes
69 | - EXAMPLE: `src/utils/email-alerts.ts`
70 |
71 | ### Rate Limiting
72 | - MUST: Implement tiered rate limits:
73 | - Auth operations: 10/10s
74 | - SMS operations: User+IP based limits
75 | - Data exports: 3/day
76 | - AVOID:
77 | - Global rate limits
78 | - Client-side rate limiting
79 | - Sharing limits across tenants
80 | - WHY: Prevents abuse while allowing legitimate high-volume usage
81 | - EXAMPLE: `src/utils/rate-limit.ts`
82 |
83 | $END$
--------------------------------------------------------------------------------
/.cursor/rules/component-architecture.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description:
3 | globs:
4 | alwaysApply: true
5 | ---
6 | # component-architecture
7 |
8 | ### Component Structure & Dependencies
9 | - MUST: Structure form components hierarchically with `AuthForm` as parent and specialized validation components as children
10 | - AVOID: Direct API calls in form components - use hooks for data fetching/mutations
11 | - WHY: Separates form UI from business logic, enables reuse of validation patterns
12 | - EXAMPLE: `src/components/auth-form.tsx` coordinates child components like `2fa-methods.tsx`
13 |
14 | ### Authentication Flow Components
15 | - MUST: Use hook-based state management for auth flows (login, signup, 2FA)
16 | - AVOID: Mixing auth state across components, keeping auth logic in UI components
17 | - WHY: Centralizes auth state management, simplifies testing
18 | - EXAMPLE: `src/components/user-provider.tsx` handles global auth state
19 |
20 | ### Form Validation
21 | - MUST: Implement field-level validation using `useFormField` hook pattern
22 | - AVOID: Custom validation logic inside form components
23 | - WHY: Consistent validation behaviors across forms
24 | - EXAMPLE: `src/components/ui/form.tsx` FormFieldContext pattern
25 |
26 | ### Toast Notifications
27 | - MUST: Use centralized toast system via `useToast` hook for all user feedback
28 | - AVOID: Multiple toast implementations or direct toast calls
29 | - WHY: Consistent notification styling and behavior
30 | - EXAMPLE: `src/components/ui/toast.tsx` provides toast primitives
31 |
32 | ### Data Loading States
33 | - MUST: Implement skeleton loading components during data fetches
34 | - AVOID: Showing empty states or spinners
35 | - WHY: Provides visual continuity during loading
36 | - EXAMPLE: `src/components/ui/skeleton.tsx` skeleton components
37 |
38 | ### Device Session Management
39 | - MUST: Use `DeviceSessionsList` component for managing active sessions
40 | - AVOID: Direct session manipulation outside session components
41 | - WHY: Centralizes session management UI/logic
42 | - EXAMPLE: `src/components/device-sessions-list.tsx`
43 |
44 | ### Two-Factor Authentication
45 | - MUST: Use `2FASetupDialog` for all 2FA enrollment flows
46 | - AVOID: Custom 2FA setup implementations
47 | - WHY: Consistent 2FA setup experience
48 | - EXAMPLE: `src/components/2fa-setup-dialog.tsx`
49 |
50 | ### Export Data Workflow
51 | - MUST: Use `DataExport` component for handling user data exports
52 | - AVOID: Custom export implementations
53 | - WHY: Standardizes export process and UI
54 | - EXAMPLE: `src/components/data-export.tsx`
55 |
56 | ### Account Management
57 | - MUST: Use `DeleteAccount` component for account deletion flows
58 | - AVOID: Custom deletion implementations
59 | - WHY: Ensures proper verification and cleanup
60 | - EXAMPLE: `src/components/delete-account.tsx`
61 |
62 | ### Social Provider Integration
63 | - MUST: Use `SocialProviders` component for OAuth integration
64 | - AVOID: Direct OAuth provider implementation
65 | - WHY: Centralizes social auth handling
66 | - EXAMPLE: `src/components/social-providers.tsx`
67 |
68 | $END$
--------------------------------------------------------------------------------
/.cursor/rules/data-models.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description:
3 | globs:
4 | alwaysApply: true
5 | ---
6 | # data-models
7 |
8 | ### Core Data Models
9 |
10 | #### User Account Model
11 | - MUST: Implement user accounts with:
12 | - Unique identifier (UUID)
13 | - Email address (verified status)
14 | - Password hash (bcrypt)
15 | - Account status (active/disabled)
16 | - Creation timestamp
17 | - Last login timestamp
18 | - AVOID: Storing sensitive data in plain text
19 | - WHY: Core identity model for authentication and access control
20 | - EXAMPLE: `src/types/auth.ts`
21 |
22 | #### Device Sessions
23 | - MUST: Track device sessions with:
24 | - Session ID
25 | - User ID (foreign key)
26 | - Device info (browser, OS, IP)
27 | - Trust score (0-100)
28 | - Last active timestamp
29 | - Verification status
30 | - AVOID: Storing raw IP addresses without hashing
31 | - WHY: Required for security monitoring and session management
32 | - EXAMPLE: `src/utils/auth/device-sessions/server.ts`
33 |
34 | #### Account Events
35 | - MUST: Log security events with:
36 | - Event ID
37 | - User ID
38 | - Event type (enum)
39 | - Metadata (JSON)
40 | - Device session ID (foreign key)
41 | - Timestamp
42 | - AVOID: Including PII in metadata
43 | - WHY: Audit trail for security and compliance
44 | - EXAMPLE: `src/utils/account-events/server.ts`
45 |
46 | ### Authentication Methods
47 |
48 | #### Two-Factor Authentication
49 | - MUST: Store 2FA configuration:
50 | - Method type (authenticator/SMS)
51 | - Backup codes (hashed)
52 | - Phone number (E.164 format)
53 | - Verification status
54 | - Setup timestamp
55 | - AVOID: Storing TOTP secrets in plain text
56 | - WHY: Required for multi-factor security
57 | - EXAMPLE: `src/types/auth.ts`
58 |
59 | #### Social Providers
60 | - MUST: Track OAuth connections:
61 | - Provider type (Google/GitHub)
62 | - Provider user ID
63 | - Access tokens (encrypted)
64 | - Connection status
65 | - Last sync timestamp
66 | - AVOID: Storing refresh tokens in database
67 | - WHY: Enables social login integration
68 | - EXAMPLE: `src/utils/auth/index.ts`
69 |
70 | ### Data Export Models
71 |
72 | #### Export Requests
73 | - MUST: Track export jobs with:
74 | - Request ID
75 | - User ID
76 | - Status (pending/processing/complete)
77 | - File path
78 | - Created timestamp
79 | - Expiry timestamp
80 | - AVOID: Storing exported data in database
81 | - WHY: Manages user data export workflow
82 | - EXAMPLE: `src/utils/data-export/server.ts`
83 |
84 | ### Relationships and Constraints
85 | - MUST: Implement cascading deletes for:
86 | - User → Device Sessions
87 | - User → Account Events
88 | - User → 2FA Methods
89 | - User → Social Providers
90 | - MUST: Enforce unique constraints on:
91 | - User email addresses
92 | - Device session IDs
93 | - Export request IDs
94 | - WHY: Maintains data integrity and prevents orphaned records
95 |
96 | $END$
--------------------------------------------------------------------------------
/.cursor/rules/security-algorithms.mdc:
--------------------------------------------------------------------------------
1 | ---
2 | description:
3 | globs:
4 | alwaysApply: true
5 | ---
6 | # security-algorithms
7 |
8 | ### Device Trust Score Calculation
9 | - MUST: Implement trust scoring using factors with exact weights:
10 | - Device name match: 30 points
11 | - Browser match: 20 points
12 | - OS match: 20 points
13 | - IP range match: 15 points
14 | - AVOID: Using custom weights or additional factors
15 | - WHY: Consistent evaluation of device trustworthiness across application
16 | - EXAMPLE: `src/utils/auth/index.ts`
17 | ```ts
18 | const calculateTrustScore = (device: DeviceInfo) => {
19 | let score = 0;
20 | if (device.name === storedDevice.name) score += 30;
21 | if (device.browser === storedDevice.browser) score += 20;
22 | //...etc
23 | }
24 | ```
25 |
26 | ### Rate Limiting Tiers
27 | - MUST: Implement the following rate limit tiers:
28 | - Auth operations: 10 requests/10 seconds
29 | - Authenticated operations: 100 requests/minute
30 | - General protection: 1000 requests/minute
31 | - SMS operations: IP + user-based limits
32 | - Data exports: 3 requests/day
33 | - AVOID: Custom rate limit values or alternative implementations
34 | - WHY: Protects against abuse while ensuring legitimate access
35 | - EXAMPLE: `src/utils/rate-limit.ts`
36 |
37 | ### Verification Code Generation
38 | - MUST: Generate verification codes using:
39 | - Authenticator: 6-digit numeric codes
40 | - SMS: 6-digit numeric codes
41 | - Email: Custom length alphanumeric codes
42 | - Backup codes: Word-based or alphanumeric format
43 | - AVOID: Custom code formats or lengths
44 | - WHY: Ensures compatibility with standard authenticator apps and SMS
45 | - EXAMPLE: `src/utils/auth/verification-codes.ts`
46 |
47 | ### Recovery Token Generation
48 | - MUST: Generate recovery tokens using:
49 | - 32 bytes of random data
50 | - URL-safe base64 encoding
51 | - 1 hour expiration
52 | - AVOID: Custom token formats or expiration times
53 | - WHY: Industry standard approach for secure recovery links
54 | - EXAMPLE: `src/utils/auth/recovery-token.ts`
55 |
56 | ### Data Export Security
57 | - MUST: Implement the following controls:
58 | - One-time use download tokens
59 | - 24-hour token expiration
60 | - Automatic file cleanup after download
61 | - Rate limiting of 3 requests per day
62 | - AVOID: Permanent download links or extended token validity
63 | - WHY: Prevents unauthorized access to exported user data
64 | - EXAMPLE: `src/utils/data-export/server.ts`
65 |
66 | $END$
--------------------------------------------------------------------------------
/.cursorignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.*
7 | .yarn/*
8 | !.yarn/patches
9 | !.yarn/plugins
10 | !.yarn/releases
11 | !.yarn/versions
12 |
13 | # testing
14 | /coverage
15 |
16 | # next.js
17 | /.next/
18 | /out/
19 |
20 | # production
21 | /build
22 |
23 | # misc
24 | .DS_Store
25 | *.pem
26 |
27 | # debug
28 | npm-debug.log*
29 | yarn-debug.log*
30 | yarn-error.log*
31 |
32 | # env files (can opt-in for committing if needed)
33 | .env*
34 | !.env.example
35 |
36 | # vercel
37 | .vercel
38 |
39 | # typescript
40 | *.tsbuildinfo
41 | next-env.d.ts
42 |
43 | CONTRIBUTING.dev.md
44 | scripts/decode-jwt.py
45 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | NEXT_PUBLIC_SUPABASE_URL=your-supabase-project-url
2 | NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
3 | SUPABASE_SERVICE_ROLE_KEY=your-supabase-service-role-key
4 | NEXT_PUBLIC_SITE_URL=http://localhost:3000
5 |
6 | # Optional features
7 |
8 | # Require re-login after password reset (generate using `openssl rand -hex 32` in the terminal)
9 | # RECOVERY_TOKEN_SECRET=your-recovery-token-secret
10 |
11 | # Email (recommended for production)
12 | # RESEND_API_KEY=your-resend-api-key
13 | # RESEND_FROM_EMAIL="Auth
18 |
13 | Download a copy of your personal data. We'll email you when it's 14 | ready. 15 |
16 |
72 |
73 | {JSON.stringify(
74 | {
75 | error: errorObject,
76 | },
77 | null,
78 | 2
79 | )}
80 |
81 |
82 | )}
83 | >
84 | 38 | We'll make it easy. What do you need help with? 39 |
40 |10 | This is the dashboard. Do whatever you need here! 11 |
12 |19 | Drop in production-ready auth code with everything apps need 20 |
21 |71 | {email ? ( 72 | <> 73 | We have sent a confirmation email to{" "} 74 | {email}. Click the 75 | link inside to finish setting up your account. 76 | > 77 | ) : ( 78 | "No email was provided. Please try again." 79 | )} 80 |
81 | {email && ( 82 | 98 | )} 99 |