🛡️Auth & SecurityComing Soon
Multi-Factor Authentication
TOTP authenticator apps, email verification codes, and WebAuthn passkeys as second factors.
Video coming soon
Add a YouTube video ID to the topics config
Documentation
Overview
Users can enable one or more MFA methods as a second factor after password login. Three methods are supported: Authenticator App (TOTP), Email codes, and Passkeys (WebAuthn).
MFA Methods
Authenticator App (TOTP)
- Secret generated with the
otpauthlibrary and encrypted with AES-256-GCM before storage - QR code displayed during setup for scanning with Google Authenticator, Authy, etc.
- User must verify a code during setup to confirm the app is configured correctly
- On login, the 6-digit time-based code is verified server-side with a ±1 window tolerance
Email Codes
- 6-digit code generated with
crypto.randomIntand stored in Redis with a 10-minute TTL - Sent via Resend transactional email with a branded HTML template
- One-time use — deleted from Redis after successful verification
Passkeys (WebAuthn)
- Registration and authentication powered by
@simplewebauthn/serverand@simplewebauthn/browser - Credentials stored in a dedicated
PasskeyMongoDB model with public key, counter, and transport info - Challenges stored in Redis with a 5-minute TTL to prevent replay attacks
- Users can register multiple passkeys and name them for identification
Login Challenge Flow
- User signs in with credentials —
mfaPending: trueis set on the JWT - Edge middleware intercepts all navigation and redirects to
/sign-in/mfa-verify - User selects a method and verifies
- Verify API sets a
mfa-verified:{userId}flag in Redis - Client calls
updateSession()— JWT callback checks Redis, clearsmfaPending - User is redirected to the home page with full access
TOTP Secret Encryption
Secrets are encrypted at rest using AES-256-GCM with the MFA_ENCRYPTION_KEY environment variable. The IV and auth tag are stored alongside the ciphertext, ensuring secrets are never in plaintext in the database.
Content coming soon — add your video and detailed writeup here.