Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

U2F Two Factor Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package, so "getting started" as a Laravel developer means deciding whether to (a) run a Symfony app alongside/inside your stack, or (b) read the source as a reference implementation for U2F. For most Laravel teams, (b) is still the realistic path — but 0.8.0 widens (a) slightly, since Symfony 5 is now in scope.

Minimal steps if you actually install it:

  1. composer require darookee/u2f-two-factor-bundle in a Symfony app — previously constrained to 2.8/3.x, now reportedly Symfony 5 compatible (confirm the symfony/* and PHP constraints in composer.json before committing; the release note is garbled — "This is no compatible with Symfony 5" almost certainly means now compatible).
  2. Register the bundle in config/bundles.php (Symfony 4/5 Flex style) rather than app/AppKernel.php.
  3. Configure scheb/two-factor-bundle in config/packages/*.yaml and point the firewall's two_factor at the U2F provider. Note the bundle pins an old scheb/two-factor-bundle line — check that it resolves alongside your Symfony 5 version before assuming 0.8.0 "just works."
  4. Import the bundle's routing for the registration/authentication endpoints and include its Twig templates (which load u2f-api.js).

Where to look first in the repo:

  • README.md for the required scheb_two_factor YAML block.
  • Resources/config/services.yml / DependencyInjection/ to see how the U2F server library and provider are wired — on Symfony 5 this is still XML/YAML service definitions, not autowired attributes.
  • The two-factor provider class (the auth check) and the registration controller/templates (the enroll flow). Those two pieces are the entire value of the package, and 0.8.0 did not change them.

First use case: adding a hardware security key as a second factor after password login on a Symfony admin firewall. There is still no Laravel service provider, facade, config publish, or migration — Symfony 5 compatibility did not add a laravel/ bridge. In Laravel you would still reach for web-auth/webauthn-lib or a maintained Laravel WebAuthn/2FA package and only borrow the flow from here.

Implementation Patterns

The package implements the classic U2F two-step handshake through scheb/two-factor-bundle, unchanged by 0.8.0:

  • Enrollment: authenticated user hits the registration route → server builds a RegisterRequest (challenge + appId) → browser JS (u2f.register) prompts the key → response is POSTed back → server validates via the U2F server library and persists keyHandle, publicKey, and counter against the user.
  • Authentication: after the password factor, server builds a SignRequest for the user's stored key handles → browser u2f.sign → server verifies signature and that the counter advanced → session is marked two-factor-complete.
  • Multiple keys per user: the schema allows several registrations; the sign request includes all handles so any enrolled key works.

Day-to-day integration tips, translated to Laravel terms:

  • Treat the provider as a guard/middleware stage: password auth succeeds, then a two_factor middleware blocks the session until the U2F assertion is verified.
  • Store the challenge in session/cache with a short TTL (the bundle uses session); mirror that if you port the flow, and clear it on success to prevent replay.
  • Keep appId/origin fixed for the lifetime of the deployment. Existing key registrations are bound to it; changing domains or http→https invalidates every enrolled key. This is especially relevant if the Symfony 5 move also changes your host/scheme.
  • If you're interoperating with an existing Symfony install from a Laravel app, preserve the DB schema for key handles so enrollments survive the migration, and keep the same origin.
  • Counter updates should be a single DB write inside a transaction after successful verification — concurrent assertions with the same key handle are a real edge case.
  • Upgrading an existing Symfony 3.x install to 0.8.0: treat it as a two-part move (Symfony 3→5 and bundle bump). Stored key handles are unaffected by the bundle version, but session handling, firewall config format, and scheb/two-factor-bundle config keys may need adjusting — re-read the README against your new config rather than copying YAML across.

Gotchas and Tips

  • Symfony 5 is the ceiling, not the floor. 0.8.0 adds Symfony 5 compatibility, but that is the newest supported line — there is no Symfony 6/7 support, and Symfony 5.4 (the LTS) is at or near end of security support. So the package went from "unusable on anything modern" to "usable on the previous major," which is an improvement but not a reason to build new work on it.
  • Verify the release note. "This is no compatible with Symfony 5" reads like a typo for "now compatible," but with a 0.x release and a one-line changelog, read the actual composer.json constraints and the PRs from @jbtronics/@stephanvierkant before you plan an upgrade. Don't refactor a firewall on the strength of a changelog typo.
  • U2F itself is still legacy, and this is the real blocker. Browsers removed the u2f-api.js global in favor of WebAuthn/FIDO2; Chrome and Firefox fail the u2f.register/u2f.sign calls on current versions. A Symfony 5 compatible bundle does not fix an FIDO1 browser API that no longer exists. For new work, WebAuthn is the correct target — this bundle remains a historical reference, not a forward-looking dependency.
  • appId/origin mismatch is the most common failure and looks identical to a bad signature. Check scheme, exact host, no trailing slash.
  • Counter semantics: reject non-increasing counters (clone detection), but tolerate keys that always report 0 — some devices do, and a strict check locks users out.
  • Binary storage: key handles and public keys are binary. Store as blob or base64, never a truncated varchar; truncation produces verification failures that are painful to diagnose.
  • No Laravel integration surface: Symfony 5 support is a Symfony-side change only — still no auto-discovery, no config publish, no Artisan commands. Anything you do in Laravel is custom glue you own.
  • Debugging: log the raw clientData and registrationData/signatureData. Error messages from the U2F library are opaque; also check server/client clock skew against the challenge timestamp.
  • Dependency resolution is the first thing to try, not the last. With an old scheb/two-factor-bundle pin plus Symfony 5 constraints, run composer why-not / composer update --dry-run in a throwaway branch before touching application code.
  • Extension points: you can override the U2F server service (e.g., swap in samyoul/u2f-php), templates, and routes via Symfony DI — but with ~11 stars, 0 dependents, and a one-line 0.8.0 release after years of dormancy, still treat the code as a sample to fork, not a maintained dependency. The single maintainer-response release is encouraging but not a maintenance commitment; vendor/fork it rather than waiting on upstream.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager