feat: two-factor authentication (TOTP + backup codes)
Uses better-auth's built-in twoFactor plugin rather than hand-rolling TOTP — adds the two_factors table and users.twoFactorEnabled, wires the server/client plugins (allowPasswordless: true so OAuth-only accounts aren't locked out of managing 2FA), and adds a custom rate limit for the verify endpoints (5/min — far stricter than the default 100/10s, since a 6-digit code has a much smaller keyspace than a password). New Settings → Security section walks through enable (password confirm -> QR + backup codes -> confirm a live code before it's actually turned on, per the plugin's default flow) and disable. New /verify-2fa page handles the post-password mid-login step, with a backup-code fallback. Verified live end-to-end: enable, confirm, forced re-auth on next sign-in, TOTP accepted, backup code accepted (single-use), disable. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -592,7 +592,17 @@
|
||||
"resendingSending": "Sending…",
|
||||
"resendFailed": "Failed to resend",
|
||||
"resendSuccess": "Verification email sent — check your inbox",
|
||||
"or": "or"
|
||||
"or": "or",
|
||||
"twoFactorTitle": "Two-factor authentication",
|
||||
"twoFactorAppDescription": "Enter the 6-digit code from your authenticator app.",
|
||||
"twoFactorBackupDescription": "Enter one of your backup codes.",
|
||||
"twoFactorCodeLabel": "Code",
|
||||
"twoFactorBackupCodeLabel": "Backup code",
|
||||
"twoFactorVerify": "Verify",
|
||||
"twoFactorVerifying": "Verifying…",
|
||||
"twoFactorInvalidCode": "Invalid code",
|
||||
"twoFactorUseBackupCode": "Use a backup code instead",
|
||||
"twoFactorUseApp": "Use your authenticator app instead"
|
||||
},
|
||||
"batchCooking": {
|
||||
"title": "Batch cooking",
|
||||
@@ -1174,6 +1184,31 @@
|
||||
"downloadData": "Download my data",
|
||||
"downloadDataDescription": "Get a JSON export of all the personal data Epicure holds about you — your profile, recipes, activity, and settings.",
|
||||
"downloadDataButton": "Download my data",
|
||||
"twoFactorTitle": "Two-factor authentication",
|
||||
"twoFactorDescription": "Require a code from an authenticator app in addition to your password when signing in.",
|
||||
"twoFactorEnableButton": "Enable",
|
||||
"twoFactorDisableButton": "Disable",
|
||||
"twoFactorEnabled": "Two-factor authentication enabled",
|
||||
"twoFactorDisabled": "Two-factor authentication disabled",
|
||||
"twoFactorEnableFailed": "Failed to start setup",
|
||||
"twoFactorDisableFailed": "Failed to disable",
|
||||
"twoFactorConfirmPasswordTitle": "Confirm your password",
|
||||
"twoFactorConfirmPasswordDescription": "Enter your password to set up two-factor authentication.",
|
||||
"twoFactorContinue": "Continue",
|
||||
"twoFactorCancel": "Cancel",
|
||||
"twoFactorSetupTitle": "Set up two-factor authentication",
|
||||
"twoFactorSetupDescription": "Scan this code with your authenticator app (like Google Authenticator or 1Password), then enter the 6-digit code it shows.",
|
||||
"twoFactorQrAlt": "QR code for two-factor authentication setup",
|
||||
"twoFactorBackupCodesLabel": "Backup codes",
|
||||
"twoFactorBackupCodesHint": "Save these somewhere safe — each one can be used once to sign in if you lose access to your authenticator app.",
|
||||
"twoFactorCopyCodes": "Copy codes",
|
||||
"twoFactorCodesCopied": "Copied",
|
||||
"twoFactorCopyFailed": "Failed to copy",
|
||||
"twoFactorCodeLabel": "6-digit code",
|
||||
"twoFactorVerifyAndEnable": "Verify & enable",
|
||||
"twoFactorInvalidCode": "Invalid code",
|
||||
"twoFactorDisableTitle": "Disable two-factor authentication",
|
||||
"twoFactorDisableDescription": "Your account will only need your password to sign in.",
|
||||
"webhookCreateFailed": "Failed to create webhook",
|
||||
"webhookDeleteFailed": "Failed to delete webhook",
|
||||
"webhookUpdateFailed": "Failed to update webhook",
|
||||
|
||||
Reference in New Issue
Block a user