Skip to content

Two-Factor Authentication

Two-factor authentication (2FA) adds an extra security layer by requiring a TOTP code from an authenticator app in addition to the password.

How It Works

  1. Generate — server creates a TOTP secret and returns a QR code URL
  2. Scan — user scans the QR code with an authenticator app (Google Authenticator, Authy, etc.)
  3. Enable — user enters a valid TOTP code to confirm setup
  4. Login — after password verification, user must provide a TOTP code

API Endpoints

MethodPathDescription
POST/api/auth/2fa/generateGenerate 2FA secret + QR code URL
POST/api/auth/2fa/enableEnable 2FA (verify TOTP code)
POST/api/auth/2fa/disableDisable 2FA (verify TOTP code)

Prisma Model

2FA state is stored directly on the User model:

prisma
model User {
  // ... other fields
  twoFactorSecret  String?
  twoFactorEnabled Boolean  @default(false)
}

Frontend

TwoFactorSetup Component

The TwoFactorSetup.vue component in Settings provides:

  • Generate button — calls POST /api/auth/2fa/generate, displays QR code
  • Verify & Enable input — user enters TOTP code, calls POST /api/auth/2fa/enable
  • Disable button — requires TOTP confirmation, calls POST /api/auth/2fa/disable
  • Status indicator showing current 2FA state

Key Implementation Details

  • The secret is generated server-side using the speakeasy library
  • QR code URL follows the otpauth:// protocol for authenticator app compatibility
  • Enabling 2FA requires verifying a valid code first (prevents locking yourself out)
  • Disabling 2FA also requires a valid TOTP code (prevents unauthorized removal)
  • The secret is stored encrypted in the database