Security First
Two-factor authentication is no longer optional for any serious platform. We implemented TOTP (Time-based One-Time Password) with backup codes as our primary 2FA method.
Architecture Overview
Our 2FA system consists of several components:
- Setup Flow - QR code generation and secret storage
- Verification Flow - TOTP validation during login
- Backup Codes - Emergency access with single-use codes
- OAuth Integration - 2FA requirement for OAuth logins too
The Pending Session Pattern
When a user with 2FA enabled logs in, we create a "pending" session stored in verification_tokens:
// Create pending 2FA session
const pendingSessionId = uuid();
await prisma.verification_tokens.create({
data: {
identifier: `2fa_pending:${pendingSessionId}`,
token: user.id,
expires: new Date(Date.now() + 5 * 60 * 1000),
},
});
This session expires in 5 minutes, giving users time to complete verification without security risks.
Backup Codes
We generate 10 backup codes during 2FA setup, each hashed with Argon2id. When used, a code is marked as consumed to prevent reuse.



