lake/login-captcha
lake/login-captcha adds captcha protection to Laravel login forms with minimal setup. It integrates with the default authentication flow, helps block automated login attempts, and provides simple configuration for captcha rendering and validation. Ideal for quickly securing login pages.
This is a Dcat-admin extension, so it slots into Dcat-admin's existing extension system rather than a plain Laravel package. The value proposition is narrow and clear: put a captcha on the /admin/auth/login screen to blunt scripted credential stuffing and password spraying against your admin panel.
Before you install, confirm your baseline:
2.x is installed and the admin panel boots (php artisan admin);gd extension enabled (php -m | grep gd) — image-based captchas fail hard without it;Install and register:
composer require lake/login-captcha
php artisan admin:import lake/login-captcha
admin:import is the Dcat-admin convention: it records the extension in config/admin.php under extensions and runs the package's install routine (publishing views/config/assets). If the import command complains about the name, use the service provider directly:
php artisan vendor:publish --provider="Lake\\LoginCaptcha\\LoginCaptchaServiceProvider"
Where to look first:
vendor/lake/login-captcha/README.md and src/ — the service provider tells you exactly which routes, views, and config keys are registered. The package is small enough to read end-to-end in a few minutes.php artisan route:list | grep -i captcha after install to confirm the image endpoint exists.config/login-captcha.php) for length, size, expiry, case sensitivity, and — as of 1.0.11 — the captcha position setting that controls where the captcha field is rendered on the login form.config/ directory against your published copy — 1.0.11 adds a new key that your existing published config will not contain (see Gotchas).First real use case: log out, hit /admin/auth/login, and verify the image renders in the position you configured, the refresh link works, and a wrong code is rejected server-side (not just client-side). That last check is the one most people skip — a captcha that only validates in JavaScript is decorative.
1. Toggle-by-environment. Captcha on the login form makes automated testing and local development painful. Wire the package's enable flag (or a config override) to app()->environment() / config('app.env') so local and testing skip validation while production enforces it. Publish the config and commit it; do not rely on the package default.
2. Treat it as defense-in-depth, not the defense. Pair it with Dcat-admin's login throttling / a RateLimiter on the login route. The captcha stops naive bots; the rate limiter stops everything else. A captcha alone does not stop distributed attempts.
3. Reuse the validation rule in custom auth flows. If you have a second login surface (a separate guard, an SSO callback form, an API token endpoint with a human step), don't hand-roll validation — use the same rule/facade the package registers so the session-key format stays consistent:
$request->validate([
'captcha' => ['required', 'captcha'], // confirm exact rule alias in the README
]);
If the package exposes a facade instead, call Captcha::check($request->input('captcha')) before authenticating. Either way, validate before hitting the credential check so failed captchas don't count against the user's password attempts.
4. Refresh affordance and field placement. The login blade should give users a click-to-refresh image and an accessible label. As of 1.0.11 the placement of the captcha field on the login form is configurable — use that setting rather than forking the login view just to move the input above or below the password field. If you use a custom Dcat-admin theme that overrides admin::pages.login, the position setting may not apply to your override; you must merge the captcha field into that override yourself or it will silently disappear after a theme update.
5. Customization via config, not edits. Length, image dimensions, character set, TTL, and now field position are almost always in the published config. Adjust there. Only override the view if you need branding (your logo inside the image, dark-mode colors, non-standard DOM placement); keep the override namespaced and documented so the next upgrade doesn't clobber it — and note in that doc that the position config no longer governs your rendering.
6. Session-key discipline. Captchas are stored in the session keyed to the login form. Whatever you do, keep the same session across form render → submit. If you introduce a subdomain split (e.g., assets on static.), set the session cookie domain to cover both, or the captcha will always fail for users.
7. Rollout pattern. Ship it behind a config flag defaulting to off, enable in staging, watch login failure rates and support tickets for 48 hours, then enable in production. Captcha friction is a common cause of "I can't log in" tickets, especially for non-technical admins. If you change the position setting post-launch, treat it as a UI change worth a quick note to admins — muscle memory matters on a login screen.
1.0.11 is a new config key. If you installed an earlier version, your committed config/login-captcha.php will not have it, and the package will fall back to its default position — which may not be the one you want, and will differ from a fresh install. Republish (into a temp dir and diff, don't blow away your edits) or add the key manually, and do this deliberately on every upgrade of this package.php -m on every node and in the Docker image, not just locally.Cache-Control: no-store) and the captcha image endpoint must be excluded from any edge cache. Otherwise every user sees the same stale image.<img src> plus a JS preload), users will submit an answer that no longer matches. Preload once.0/O, 1/l/I cause false rejections. Most captcha libraries let you exclude ambiguous characters; verify the config exposes that and turn it on. Confirm whether validation is case-insensitive by default — if not, decide deliberately.php artisan route:list (route registered?), browser Network tab (image returns 200 with image/png?), storage/logs/laravel.log (validation exception?), the rendered login HTML (is the field where you expect it?), and session()->getId() consistency between the GET and POST via a temporary log line.phpunit.xml set the env flag your config reads, or bind a fake captcha implementation in a test service provider. Do not disable captcha globally in phpunit.xml if you also run browser/E2E tests that should exercise the real login path — scope the bypass to unit test suites. A position-only release does not change validation behaviour, so existing bypasses keep working.1.0.11 follows a long gap since the March 2023 release), the package has ~32 stars and zero dependents, and 1.0.11 is a small UI-oriented patch that touches the login view — exactly the surface most likely to conflict with Dcat-admin theme overrides. Before adopting on a current stack, verify it boots against your Dcat-admin and Laravel versions, and check whether a minor Laravel upgrade (session/cookie internals) breaks it. If it does, the fallback is trivial: the package is a thin wrapper around a standard captcha library, and you can reproduce the same feature with mews/captcha (or gregwar/captcha) plus a small login-view override — likely in under an hour. Budget for that possibility.composer.json (including 1.0.11's new position key in your runbook notes), and be ready to fork. Also confirm the Apache-2.0 license notice is retained if you do fork.How can I help you explore Laravel packages today?