DÉMO
dev only

Two-factor auth

TOTP authentication compatible with Google Authenticator and Authy.

Overview

Two-factor authentication is based on TOTP (Time-based One-Time Password), compatible with Google Authenticator, Authy and any standard TOTP client. The scheb/2fa-bundle automatically intercepts logins after password verification.

Role Detail
Business logic: secret generation, QR code, enable, disable, backup codessrc/Service/Auth/TwoFactorService.php
Routes for the activation and deactivation flowsrc/Controller/Account/TwoFactorController.php
Activation page with QR code and code confirmationtemplates/account/2fa_setup.html.twig
One-time display of backup codes after activationtemplates/account/2fa_backup_codes.html.twig
TOTP code input form at login (rendered by scheb)templates/auth/2fa.html.twig
scheb configuration: TOTP enabled, issuer, templateconfig/packages/scheb_2fa.yaml
main firewall: two_factor enabled with its routesconfig/packages/security.yaml

Dependencies

Three packages are required: the scheb bundle for interception, the TOTP provider, and endroid/qr-code to generate QR codes.

composer require scheb/2fa-bundle scheb/2fa-totp endroid/qr-code

Configuration

The bundle is configured in two files: scheb_2fa.yaml for the TOTP provider and security.yaml for the firewall.

Firewall (security.yaml)

The two_factor entry must be added to the main firewall for scheb to intercept logins.

config/packages/security.yaml config/packages/scheb_2fa.yaml

User entity

The entity implements TotpTwoFactorInterface. Three database columns are used: two_factor_secret, two_factor_enabled and two_factor_backup_codes.

src/Entity/Auth/User.php

Activation flow

Activation takes place in two steps: scan the QR code, then confirm with a valid code.

  1. 1

    The user clicks "Enable 2FA" from /account/security.

    GET /account/security/2fa/setup

    a temporary secret is generated and stored in session, the QR code is rendered via endroid/qr-code.

  2. 2

    The user scans the QR code with Google Authenticator, Authy or any compatible TOTP client.

  3. 3

    The user enters the 6-digit code displayed by their app to confirm the setup.

    POST /account/security/2fa/enable

    the code is verified against the session secret via TotpAuthenticatorInterface::checkCode(). On failure, the QR code is re-displayed.

  4. 4

    Backup codes are generated (8 hex codes of 8 characters) and displayed once.

    GET /account/security/2fa/backup-codes

    codes are stored in the user's two_factor_backup_codes JSON column.

The temporary secret is stored in session during setup (key _2fa_temp_secret) and removed after successful activation. The database flush only happens after code validation.

Login with 2FA

When a user with 2FA enabled logs in, scheb/2fa-bundle automatically takes over after password verification.

  1. 1

    The user enters their email and password — standard authentication.

  2. 2

    scheb intercepts and issues a TwoFactorToken. The user is redirected to /2fa to enter their code.

    GET /2fa → POST /2fa_check
  3. 3

    After code validation, the TwoFactorToken is replaced by a fully authenticated token and the user accesses the application.

Backup codes

Single-use backup codes (8 codes) are generated at activation. They allow access if the authentication device is lost.

Codes are stored as JSON in the two_factor_backup_codes column. Managing their consumption (single use) can be implemented if needed via InMemoryTwoFactorProviderInterface.

Backup codes are displayed only once after activation (session storage then deletion). The user must save them immediately.

Disabling

Disabling clears the TOTP secret, disables the flag and removes backup codes from the database.

POST /account/security/2fa/disable

clears totpSecret, sets totpEnabled → false, backupCodes → null, then flush.

Loading…
Loading the web debug toolbar…
Attempt #