twoFactor() plugin adds TOTP (time-based one-time password) support compatible with Google Authenticator, Authy, 1Password, and any RFC 6238 app. Users enroll once by scanning a QR code, then provide a 6-digit code on every sign-in.
Setup
Install
Add the plugin
lib/kavach.ts
twoFactor() works with any primary auth method. Pair it with OAuth providers or magic link as well as email/password.Enrollment flow
All enrollment endpoints require an active session.Generate a TOTP secret
POST /auth/2fa/enrollqrCodeUrl as a QR code image in your UI. The user scans it with their authenticator app. Show backupCodes once at this point, they cannot be retrieved again.Confirm with the first code
Ask the user to enter the code their authenticator app shows to confirm enrollment:POST /auth/2fa/verifyLogin verification
When a user with 2FA enabled signs in, the primary auth endpoint returns a partial response instead of a session:POST /auth/2fa/verify
Backup codes
Ten single-use backup codes are generated at enrollment. Each is a 10-character alphanumeric string. A backup code can be submitted in place of a TOTP code at the verify endpoint, useful when the user has lost access to their authenticator app.Regenerate backup codes
POST /auth/2fa/backup-codes
This invalidates all existing backup codes and issues a new set. Requires an active session.
Disabling 2FA
POST /auth/2fa/disable
Requires the user’s current TOTP code as confirmation:
Check enrollment status
GET /auth/2fa/status
Endpoints
All endpoints require an authenticated session unless noted.| Endpoint | Description |
|---|---|
POST /auth/2fa/enroll | Generate a TOTP secret and backup codes |
POST /auth/2fa/verify | Confirm enrollment or complete login |
POST /auth/2fa/disable | Disable 2FA, requires current code |
GET /auth/2fa/status | Check whether 2FA is enabled |
POST /auth/2fa/backup-codes | Regenerate backup codes |
Options
| Option | Type | Default | Description |
|---|---|---|---|
issuer | string | required | App name shown in the authenticator |
enforce | boolean | false | Require 2FA for all users |
shouldEnforce | (user: User) => Promise<boolean> | , | Per-user enforcement logic |
backupCodeCount | number | 10 | Number of backup codes generated at enrollment |
challengeTokenTtl | number | 300 | Seconds to complete verification after primary auth |