- User enters their email address
- System generates a TOTP code and magic link
- Server console logs the user's email, the code, and the magic link. In production, this would instead send to the user's email
- User can either:
- Click the magic link to automatically verify
- Enter the 6-digit code manually
- Upon successful verification:
- User account is created if it doesn't exist
- Session is established
- User is redirected to dashboard
The UI informs the user of state, such as if the code is incorrect, expired, or is accessed from another browser.
Create a .env
file in the root directory with the following variables:
DATABASE_URL="postgresql://user:password@host:port/database"
SESSION_SECRET="generate-a-secure-random-string"
TOTP_SECRET="generate-a-64-character-hex-string"
Generate a secure TOTP secret (64 character hex string):
node -e "console.log(crypto.randomBytes(32).toString('hex'))"
Generate a session secret:
node -e "console.log(crypto.randomBytes(32).toString('base64url'))"
- Clone the repository:
git clone https://github.com/cyrusvorwald/react-router-playground.git
cd react-router-playground
- Install dependencies:
npm install
-
Set up your environment variables as described above
-
Run database migrations:
npm run db:migrate
- Start the development server:
npm run dev
Your application will be available at http://localhost:5173
.
This template uses Drizzle ORM with PostgreSQL. The schema includes:
- Users table with email and timestamps
- Built-in migrations support
- Type-safe database queries
To modify the schema:
- Edit
app/db/schema.ts
- Generate migrations:
npm run db:generate
- Apply migrations:
npm run db:migrate
app/
├── components/ # Reusable UI components
│ ├── auth/ # Authentication-related components
│ └── ui/ # shadcn/ui components
├── constants/ # Auth error codes
├── db/ # Database configuration and schema
├── hooks/ # React hooks
├── lib/ # Utility functions
├── routes/ # Route components and handlers
└── services/ # Server functions