laravel-ir-captcha maintained by klangch
Laravel IR Captcha
Laravel IR Captcha (Image Rotation Captcha) is a customizable image rotation CAPTCHA package for Laravel 11 and 12.
Features
- Interactive, intuitive, and more user-friendly than classic text-based CAPTCHAs.
- Customizable UI and flexible configuration.
- No third-party services required. Everything are handled locally.
Preview
https://github.com/user-attachments/assets/32460513-4fe3-4bfa-bcf7-79c5e9b7f5e1
Installation
Make sure the PHP gd extension is installed and enabled.
Install with composer using following command:
composer require klangch/laravel-ir-captcha
Configuration
Publish configuration, view, localization files by using following command:
$ php artisan vendor:publish --provider="Klangch\LaravelIRCaptcha\LaravelIRCaptchaServiceProvider"
config/ir-captcha.phplang/vendor/ir-captcha/en/messages.phpresoures/views/vendor/ir-captcha/irCaptcha.blade.php
Usage
Show captcha in iframe
<iframe src="{{ ir_captcha()->iframeUrl() }}" height="290" width="300"></iframe>
Listen for iframe's post message
window.addEventListener("message", (event) => {
if (event.data && event.data.type === "irCaptcha" && event.data.status === "success") {
// Get captcha token and set to input field
document.querySelector("input[name='captcha_token']").value = event.data.captchaToken;
// Continue form submission...
}
});
URL for iframe
// Get captcha URL with helper
ir_captcha()->iframeUrl();
// Get captcha URL with parent origin and dark theme
ir_captcha()->iframeUrl('https://[your_parent_origin].com', true);
// Or append parent origin and dark theme param manually
$url = ir_captcha()->iframeUrl() . '?parent_origin=https://[your_parent_origin].com&theme=dark';
or set dark theme dynamically in Laravel Blade + JS
// Get captcha URL with helper
let captchaUrl = "{{ ir_captcha()->iframeUrl() }}";
// Or without helper
let captchaUrl = "https://[your_captcha_domain].com/ir-captcha";
// Then append parent origin
captchaUrl += "?parent_origin=" + window.location.origin;
// Append theme
if (themeMode === "dark") {
captchaUrl += "&theme=dark";
}
document.getElementById("captchaIframe").src = captchaUrl;
Validate captcha token
if (ir_captcha()->validateCaptchaToken($token) === true) {
// Validation success
}
or by using Laravel validation rule:
use Illuminate\Support\Facades\Validator;
use Klangch\LaravelIRCaptcha\Rules\IRCaptcha;
$rules = [
'captcha_token' => ['required', new IRCaptcha],
];
$validator = Validator::make($request->all(), $rules);
$validator->validate();
Clear expired captcha files
Clear expired captcha files by using following command:
$ php artisan ir-captcha:clear-expired
You can set this command in cron job to regularly clear expired files.
⚠️ Note For Frontend Framework On Different Domains ⚠️
When using this package with frontend hosted on different domain (such as a Next.js app embedding captcha verification page via an iframe), there are a few important things to keep in mind:
⚠️ CSRF Exclusion
CSRF protection may block requests due to cross-origin restrictions. To allow verification requests from the iframe to bypass CSRF validation, you can explicitly exclude the verification endpoint:
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
// ...
$middleware->validateCsrfTokens(except: [
'ir-captcha-verify',
]);
});
⚠️ Set Captcha Locale
You can set the captcha's language by passing a locale code as a query string parameter, such as _lang. Then, use middleware to set the application's locale accordingly.
For example, in your HTML:
<iframe src="https://[your_captcha_domain].com/ir-captcha?parent_origin=https://[your_parent_origin].com&_lang=cn"></iframe>
In your middleware, retrieve the _lang value and set the application locale:
public function handle(Request $request, Closure $next): Response
{
$locale = $request->input('_lang', 'en');
App::setLocale($locale);
return $next($request);
}
For a complete working example, see the Code Example repository.