Two-factor authentication
Every account can use two-factor authentication with an authenticator app (Google Authenticator, Microsoft Authenticator, Authy, 1Password …). Signing in then takes the password and a 6-digit code, in both the customer panel and the admin interface.
- Customers turn it on themselves under Account (click the email at the bottom of the sidebar): scan the QR code, enter a first code, save the 10 recovery codes. Admins do the same under Your account in the admin interface.
- Requiring it: when adding a user, tick "Require two-factor authentication", or change it later with the 2FA button in the Customers tab. A user who hasn't set it up yet has to do so at the next sign-in, before anything else, and can't switch it off.
- Lost phone: the user signs in with a recovery code (each works once) and can create new codes under Account. If the codes are gone too, reset it with the 2FA button (Reset); if it's required, they set it up again at the next sign-in. Confirm who is asking before resetting.
- Locked out yourself: on the panel host run
npm run user:reset-2fa -- admin@example.com.npm run user:createaccepts--require-2fa.
Details: codes follow TOTP (RFC 6238, SHA-1, 6 digits, 30 seconds), accepted one step early or late for clock drift, and each code works only once. Secrets are stored AES-256-GCM encrypted, recovery codes only as SHA-256 hashes. The second sign-in step is rate-limited and expires after 5 minutes.
Two things to know:
- Keep the panel host's clock right (NTP; Windows does this by default). Codes depend on the time; a clock more than about a minute off rejects them.
- The encryption key is derived from
JWT_SECRET. ChangingJWT_SECRETmakes existing 2FA setups unreadable; reset the affected users afterwards.