scheb/2fa
scheb/2fa adds two-factor authentication to Symfony applications with TOTP authenticator apps, email codes, backup codes, and trusted-device support. It integrates cleanly with Symfony Security and provides extensible, well-tested building blocks for securing user logins.
Architecture fit: scheb/2fa is architecturally a Symfony-first authentication library with a framework-agnostic core. Its split packages (scheb/2fa-totp, scheb/2fa-email, scheb/2fa-backup-code, scheb/2fa-trusted-device) expose small interfaces for providers, codes, and secret storage, but the value-add — the enforcement workflow, firewall integration, preparation/validation hooks, and trusted-device skipping — is delivered through Symfony event listeners, the Symfony security token, and the bundle's DI container. In a Laravel context, we get the low-level primitives (TOTP generation, backup-code generation) but not the wiring. The architectural fit for Symfony is excellent; for Laravel it is partial and requires a bridge layer.
Integration feasibility: Feasible but not plug-and-play. For Laravel, we would consume the framework-agnostic sub-packages and implement a custom guard/middleware that: (1) stores the 2FA-enabled flag and TOTP secret on the users table, (2) issues a short-lived "pending 2FA" session state after password validation, (3) validates codes via the TOTP provider, and (4) manages backup-code consumption and trusted-device tokens ourselves. None of the Symfony bundle's UI, event hooks, or TwoFactorToken behavior transfers directly. This is a moderate-to-large integration effort — roughly a few dev-days for TOTP-only parity, longer for backup codes, trusted devices, and email factor parity.
Technical risk: Medium-high, driven primarily by framework mismatch. This is not a Laravel package — there is no Laravel service provider, no middleware, no Blade scaffolding, and no session integration with Laravel's Auth. The security-sensitive parts (challenge session state, replay prevention, backup-code single-use enforcement) would fall to our own code — a common source of auth bypass bugs. Secondary risks: dependency drift on OTPHP (TOTP generation underlying library), and pulling in Symfony components transitively into a Laravel app. Positive signals: MIT license, thorough test suite, active maintenance, semantic versioning, and a clean recent release (v8.6.1) that only removed an obsolete ext-json constraint on PHP 8 — low-churn, low-breakage signal.
Key questions:
google2fa-laravel, pragmarx/google2fa)? What does scheb/2fa give us that justifies a custom bridge?Stack fit: Strong on Symfony (PHP 8.x, Symfony 6/7, firewall/authenticator integration). Moderate on Laravel: we can adopt the framework-agnostic primitives and the pluggable TwoFactorProviderInterface pattern, but we will be writing the Laravel glue ourselves — a guard, a middleware, migrations for secrets and backup codes, and a setup UI. If the team is Laravel-idiomatic, expect friction from the Symfony event model leaking into the design.
Migration path: Two viable routes. Route A (Laravel-native replacement) — use pragmarx/google2fa-laravel or Fortify's 2FA for TOTP + recovery codes; lower lift, stronger ecosystem support, but you forgo scheb's trusted-device and pluggable-factor ergonomics. Route B (adopt the core) — install scheb/2fa-totp and scheb/2fa-backup-code alone, implement the small interfaces against our Laravel User model, and build the middleware ourselves; higher control, higher ownership cost. For a Symfony service, the standard bundle install with composer and firewall configuration applies. Recommend deciding Route A vs. B with a spike before committing.
Compatibility: PHP 8+ only (v8.6.1 removed ext-json as redundant). Symfony 6/7 for the bundle. Laravel compatibility is not declared and will need to be validated per Laravel version — particularly session handling, CSRF for the 2FA challenge form, and the user provider contract. Expect to pin OTPHP and review transitive Symfony component pulls in composer.lock. No known blocker, but nothing is guaranteed by upstream.
Sequencing:
Maintenance: Upstream is healthy — actively maintained, tested, semantic versioning, MIT, low-churn releases. However, in a Laravel deployment we inherit maintenance of the bridge layer (guard, middleware, migrations, UI), which is our code and our bug surface. Budget ongoing ownership for that layer, plus periodic dependency review of OTPHP and any transitive Symfony components.
Support: Upstream support is Symfony-oriented; Laravel-specific questions will not be answered. Internal documentation and an owner for the auth integration are effectively mandatory. Symfony users get the benefit of a documented, first-class bundle and community precedent.
Scaling: Runtime cost is negligible — TOTP verification is CPU-trivial and the 2FA challenge adds one request per login. Scaling concerns are storage and operations, not throughput: per-user secrets (encrypted at rest), backup-code hashes, trusted-device token tables with TTL and revocation. Email-factor adoption introduces dependency on mail infrastructure and its rate limits/deliverability. Plan for trusted-device table growth and cleanup jobs.
Failure modes: Lost device with no backup codes (locked-out users — a top support-ticket driver); TOTP clock skew and server time drift; backup codes replayed if single-use enforcement is buggy; challenge-session fixation or bypass if the pending-2FA state is mis-scoped; secret leakage in logs or unencrypted columns; email-factor delivery failures; and configuration drift where enforcement is silently disabled in one environment. Each warrants explicit test coverage and an admin-assisted recovery path.
Ramp-up: For a Symfony team, low — hours to first working TOTP, days to full feature adoption. For a Laravel team, moderate — plan roughly one to two weeks for a competent engineer to reach confident TOTP-plus-backup-codes parity, longer for trusted devices. Documentation quality and the test suite materially reduce ramp-up risk; the framework mismatch is the primary learning cost.
How can I help you explore Laravel packages today?