fourcoders/latch-bundle
Fourcoders LatchBundle integrates Telefónica Latch into Symfony apps, adding account lock/unlock and second-factor protection. Configure API credentials, pair user accounts, and query Latch status through simple bundle services.
First, a reality check: this is not a Laravel package. fourcoders/latch-bundle is a Symfony2 bundle (circa 2014–2015) that wraps the ElevenPaths/Telefónica Latch SDK — a service where a user taps a padlock in a mobile app to lock their own account, and your app checks that state at login. There is no service provider, no facade, no config/latch.php. Last release was 2015-01-15, it has zero dependents, and the upstream Latch service has since been discontinued. Treat this assessment as "how would I work with this if I inherited it," not "how do I add it to my Laravel app."
If you're on a legacy Symfony2 codebase:
composer require fourcoders/latch-bundle (expect a dev-master constraint — there is no semver tag worth trusting).FourCoders\Bundle\LatchBundle\FourCodersLatchBundle in app/AppKernel.php.fourcoders_latch: with app_id and secret_key) to app/config/config.yml. Verify the real key names in DependencyInjection/Configuration.php before copying anything from a blog post — this is the single most common source of "my config is ignored" confusion.Resources/config/services.xml to find the actual service id for the Latch client (likely fourcoders_latch.latch or similar — grep, don't guess), then at any EventListener/ or annotation class shipped with the bundle.First use case: pair a user, then guard their login. The pairing code is displayed in the user's Latch mobile app; the user types it into your form; you call pair($code) and persist the returned accountId on the User entity. From then on, on every login (or on every request to sensitive controllers), call status($accountId) and deny access when the status is on.
Pairing / unpairing as a first-class flow. Don't bury pairing in the registration controller. Give it its own route and action (/account/latch/pair), require the user to be authenticated, and store the returned accountId in a nullable, indexed column. Unpair on account deletion and offer a manual "unlink my Latch" action — orphaned accountId rows are the usual support ticket.
Enforcement belongs in one place. The most maintainable pattern is a security voter or a kernel.event_listener on security.interactive_login that checks the latch status once at authentication time, rather than sprinkling checks across controllers. A bundle-provided annotation/listener is convenient but tends to couple your security policy to a vendor; wrap the check in your own small LatchGate service that delegates to the bundle's client, so the day the SDK dies (it did) you swap one class.
Wrap the SDK behind an interface. Define LatchClientInterface { pair(string): ?string; status(string): string; unpair(string): void; } and have the bundle's service be one implementation. This gives you a NullLatchClient for tests and local dev, and a single seam for migrating off the dead upstream API.
Fail-open with a timeout, explicitly. Because status() is a synchronous HTTP call to a third party, you need a deliberate policy: cached status with a short TTL (60–300s), a hard timeout (2–3s), and a documented decision on whether an unreachable Latch service blocks login or lets it through. For most consumer apps the answer is fail-open with an alert; for high-security admin panels it's fail-closed. Write that decision into the code as a named constant so nobody "fixes" it accidentally.
Migration pattern. If the upstream is gone, keep the accountId column, keep the pairing UI concept, and reimplement status() against whatever you replace it with. Deleting the bundle is cheap once everything goes through your own interface.
latch_account_id column plus a login-time check — not the code.status() call will time out or 404. A synchronous call on the login path with no timeout configured is effectively a self-inflicted denial-of-service. Check php.ini's default_socket_timeout and the SDK's curl options before you deploy it anywhere.AppKernel registration, no services.yaml, no autowiring. It will not load on Symfony 4+, and the PHP-level type hints predate PHP 7's stricter semantics.NOASSERTION. There's no machine-readable license. Read the LICENSE file in the repo before shipping it inside a commercial product; "no license" legally means "no grant."on, off, undefined) and the pairing response separately. undefined almost always means the accountId is malformed or belongs to a different application's app_id — a mismatch between staging and production credentials is the classic cause.config.yml rather than patching the vendor. If it doesn't, decorate the service and wrap the call yourself.How can I help you explore Laravel packages today?