r/u2f-two-factor-bundle
Symfony bundle that adds U2F hardware-key two-factor authentication to your login flow, letting users register and verify USB security keys alongside existing credentials for stronger account protection.
Architecture fit — still a framework mismatch, but the Symfony side of the story moved. This remains a Symfony bundle, not a Laravel package: no ServiceProvider, no config/*.php, no publishable migrations, no facades. Integration surface is unchanged — Bundle class, DI extension with compiler passes, XML/YAML container config, Twig challenge view, Doctrine ORM entity/repository for key registration, and event listeners on the second-factor authentication lifecycle. For a Laravel target, the headline finding stands: this is a port, not an install.
What changed in 0.8.0 — and what did not. Release note reads "This is no compatible with Symfony 5", which is almost certainly a typo for "now compatible with Symfony 5." Treat as the intended meaning, but verify against composer.json before relying on it — the note is the only artefact we have and the data payload was empty. If accurate, this is the first release since 2020-05-19 and it materially revises one prior finding:
scheb/two-factor-bundle does not exist for Symfony 5 — its successor is scheb/2fa-bundle. So 0.8.0 either migrated to that successor or dropped the parent entirely. Either is a real improvement over the Symfony 2/3.4 graveyard.What did not change — the finding that actually decides this.
navigator.u2f and the Chrome U2F extension APIs were removed (Chrome 98+, 2022, counterparts following). Symfony 5 compatibility on the server does not resurrect a browser API. Unless the release also rewrote the front-end Twig/JS to WebAuthn / navigator.credentials — which the note does not claim — the shipped flow still cannot execute in a current browser. This is the first thing to check in the diff.Revised technical risk ranking: the framework-EOL risk drops from "blocking" to "manageable with effort"; browser/API obsolescence remains blocking and unchanged; maintenance and security-process risk remain unchanged. Net: the artefact is less rotten than assessed, and still not adoptable as a dependency.
Key questions before investing any effort (updated):
scheb/two-factor-bundle, or has it moved to scheb/2fa-bundle? This determines whether a Symfony 5 adoptor inherits an abandoned parent or not.composer.json — Symfony 5.x only, or 5.4/6.x? "Compatible with Symfony 5" spans a wide range of support status.opportunity: 4.57 a genuine capability gap, or the package's niche-ness? Unchanged — the score still reads more like a warning than an invitation.Stack fit. In Laravel: unchanged, poor. No service provider, Twig not Blade, Doctrine not Eloquent, Symfony dispatcher not Laravel's. 0.8.0 does not touch this. In Symfony: materially improved — from "EOL 2.x/3.x via an abandoned bundle" to "5.x via an arguably live bundle," pending question #3. The disposition is still: treat the repository as a reference implementation, not a library — but the reference is now more current and more readable.
Recommended path — replace, don't port (unchanged). For a Laravel target:
web-auth/webauthn-lib or laragear/webauthn — spec-current WebAuthn/CTAP2.TwoFactorProvider abstraction so TOTP/WebAuthn/recovery codes share one enforcement point.webauthn_credentials (credential ID, public key, counter, transports, AAGUID, nickname, last_used_at). The bundle's schema is a usable shape reference only.navigator.credentials.create/get.Extraction, if reuse is mandated. Scope is unchanged — lift challenge/verification services, strip DI and Twig, replace client JS with WebAuthn, re-wrap in a service provider — but 0.8.0's Symfony 5 code is easier to read and lift than the 2.x-era code (modern PHP syntax, fewer deprecated container idioms). Marginal effort reduction, same ownership outcome.
Migration path (if a Symfony estate runs this) — the sequencing advice sharpens. Previously two migrations had to be sequenced. 0.8.0 bundles them: adopting the release moves the framework axis and (probably) the parent-bundle axis in one step. That is convenient and risky:
Compatibility notes. If Symfony 5 support is real, assume PHP 7.2.5+ (likely 8.x), Doctrine ORM 2.x, Twig 2/3, and container config that now parses on modern builds. That removes most of the prior "collectively a rewrite" friction for Symfony targets. For Laravel targets, none of it applies — the compatibility surface is irrelevant to our framework.
Sequencing for a greenfield Laravel build: unchanged. (1) Confirm phishing-resistant 2FA is the requirement; (2) WebAuthn PoC behind a flag across Chrome/Safari/Firefox, platform and roaming authenticators; (3) ship TOTP/recovery codes as universal fallback first; (4) enrol cohort and monitor assertion failure rates; (5) only then deprecate weaker factors.
Maintenance. Improved at the margin, unchanged in kind. There is now one release in five years, with two external contributors credited — a positive signal that the repo is not fully fossilised. It is still a single-maintainer project with no dependents to surface regressions. Any adoption remains a permanent internal fork; you inherit security patching for authentication code. The MIT licence makes the fork legal, not cheap.
Support. No vendor, no SLA, no disclosure channel — unchanged by this release. Internal engineers remain the only escalation path, and knowledge still concentrates in whoever does the port. Bus factor of one.
Scaling. Unchanged and still not the constraint. Public-key verification plus a credential lookup per login; single-row counter update. The narrow concurrency contention on same-credential counter updates is worth a lock, not an architecture. The real scaling risk is still browser compatibility, which does not scale at all — it went to zero.
Failure modes, ranked by blast radius:
scheb/two-factor-bundle to scheb/2fa-bundle, the enforcement point and event lifecycle changed. A mis-wired listener is a silent 2FA bypass, not an error. This is the highest-severity specific risk introduced by 0.8.0 and should be tested explicitly.Ramp-up. Essentially unchanged. Read the repo in a day, understand protocol logic in two or three; the domain learning (attestation vs. assertion, RP-ID/origin binding, counter semantics, transport hints) is the real cost. Budget one experienced engineer for 2–3 weeks for a WebAuthn-based Laravel replacement including tests. If a Symfony 5 estate exists, add ~1 week to validate the 0.8.0 upgrade path and the parent-bundle swap — cheaper than the prior estimate for a 2.x→modern migration, and only relevant to that scenario.
Bottom line — revised but not reversed. 0.8.0 is a genuine improvement: first release in five years, Symfony 5 support, outside contributors. It retires the "framework is terminally EOL" objection and makes the codebase a better reference. It does not touch the finding that actually decides this: the client-side U2F API is gone from browsers, and unless the 0.8.0 diff also rewrote the front-end to WebAuthn — which the note does not claim — the shipped flow still cannot run. It also does not create dependents, a security process, or a support commitment.
The opportunity: 4.57 score still reads as "there is a real capability gap here" — phishing-resistant 2FA is worth building. The overall score should move up modestly from 1.51 on maintenance grounds, but the disposition holds: use the repo as a protocol and schema reference, build on WebAuthn in the target framework. Verify the release note's likely typo and inspect the diff for (a) a WebAuthn front-end and (b) the parent-bundle swap before treating 0.8.0 as anything more than a better-maintained reference implementation.
How can I help you explore Laravel packages today?