Skip to main content

Two-Factor Authentication

TOTP

Add an extra layer of security with TOTP-based two-factor authentication.

TOTP Standard

Works with any authenticator app

Backup Codes

Recovery codes for lost devices

Rate Limited

Brute-force protection built-in

Enforceable

Require 2FA for specific roles

Overview

Two-factor authentication (2FA) adds an extra layer of security by requiring users to provide a time-based one-time password (TOTP) in addition to their regular password. Users can use authenticator apps like Google Authenticator, Authy, or 1Password.

Google Authenticator
Authy
1Password

How 2FA Works

1

User Enables 2FA

Users enable 2FA through the Sylphx Console account settings or your app's settings page using the platform API.

2

Scan QR Code

User scans the QR code with their authenticator app (or enters secret manually).

3

Verify Code

User enters a 6-digit code from their app to verify setup and receives backup codes.

4

Login with 2FA

On subsequent logins, the SDK automatically handles the 2FA challenge.

2FA Setup

2FA setup and management is handled through the Sylphx Console or via platform-level APIs. The SDK handles the login flow when a user has 2FA enabled.

Sign In with 2FA

When a user with 2FA enabled signs in, the SDK automatically handles the 2FA challenge. Use the useSignInForm headless hook for full control:

components/login-with-2fa.tsx
'use client'

import { useSignInForm } from '@sylphx/sdk/react'

export function LoginForm() {
  const {
    form,
    setEmail,
    setPassword,
    setOtp,
    handlePasswordSubmit,
    handleTwoFactorVerify,
    isLoading,
    error,
    pendingTwoFactor,
  } = useSignInForm({ afterSignInUrl: '/dashboard' })

  // 2FA verification step
  if (pendingTwoFactor) {
    return (
      <form onSubmit={handleTwoFactorVerify}>
        <h2>Enter Authentication Code</h2>
        <p className="text-muted-foreground mb-4">
          Enter the 6-digit code from your authenticator app
        </p>
        {error && <div className="text-red-500 mb-4">{error}</div>}
        <input
          type="text"
          placeholder="000000"
          value={form.otp}
          onChange={e => setOtp(e.target.value)}
          maxLength={6}
          autoFocus
          className="text-center text-2xl tracking-widest"
        />
        <button type="submit" disabled={isLoading}>
          {isLoading ? 'Verifying...' : 'Verify'}
        </button>
      </form>
    )
  }

  // Initial login step
  return (
    <form onSubmit={handlePasswordSubmit}>
      {error && <div className="text-red-500 mb-4">{error}</div>}
      <input
        type="email"
        placeholder="Email"
        value={form.email}
        onChange={e => setEmail(e.target.value)}
      />
      <input
        type="password"
        placeholder="Password"
        value={form.password}
        onChange={e => setPassword(e.target.value)}
      />
      <button type="submit" disabled={isLoading}>
        {isLoading ? 'Signing in...' : 'Sign In'}
      </button>
    </form>
  )
}

Automatic 2FA Detection

The useSignInForm hook automatically detects when 2FA is required and sets pendingTwoFactor to the user's info. You just need to render the OTP input and call handleTwoFactorVerify.

Backup Codes

Backup codes allow users to access their account if they lose their authenticator device. Backup codes are provided when 2FA is first enabled and can be regenerated through the Console.

// Using a backup code to sign in
// Backup codes work the same as TOTP codes in the sign-in flow
import { useSignInForm } from '@sylphx/sdk/react'

function LoginWithBackupCode() {
  const { setOtp, handleTwoFactorVerify, pendingTwoFactor } = useSignInForm({
    afterSignInUrl: '/dashboard'
  })

  // When 2FA is required, user can enter a backup code
  // instead of the TOTP code from their authenticator app
  if (pendingTwoFactor) {
    return (
      <form onSubmit={handleTwoFactorVerify}>
        <input
          type="text"
          placeholder="Enter backup code (e.g., XXXX-XXXX)"
          onChange={e => setOtp(e.target.value)}
        />
        <button type="submit">Use Backup Code</button>
      </form>
    )
  }
}

Backup Code Usage

Each backup code can only be used once. Users should regenerate backup codes through the Console or platform settings if they're running low.

Managing 2FA

2FA setup, configuration, and disabling is managed through the Sylphx Console or your app's account settings using platform-level APIs. This ensures sensitive security operations are properly validated.

Platform-Level Operations

The following operations are available through the Console or platform API:
  • Enable 2FA with QR code setup
  • Generate and view backup codes
  • Regenerate backup codes
  • Disable 2FA (requires code verification)

Check 2FA Status

2FA status can be checked through your backend or Console API. The SDK focuses on handling the authentication flow - when a user with 2FA signs in, the pendingTwoFactor state indicates that verification is required.

import { useSignInForm } from '@sylphx/sdk/react'

function LoginForm() {
  const { pendingTwoFactor, ...rest } = useSignInForm({
    afterSignInUrl: '/dashboard'
  })

  // pendingTwoFactor is set when login succeeds but 2FA is required
  // { userId: string, email: string }
  if (pendingTwoFactor) {
    // User has 2FA enabled, show OTP input
    return <TwoFactorForm {...rest} />
  }

  return <CredentialsForm {...rest} />
}

Best Practices

PropertyTypeDescription
Encourage 2FARecommendedPrompt users to enable 2FA after signup, especially for sensitive apps
Require for adminsRecommendedEnforce 2FA for admin accounts
Backup codesRequiredAlways provide backup codes and remind users to save them
Recovery optionsRequiredHave a support process for users who lose both device and backup codes
Rate limitingAutomaticPlatform automatically rate-limits 2FA attempts

Enforce 2FA

You can require 2FA for all users or specific roles in your Sylphx Dashboard under App Settings → Security.