Skip to content

Laravel

EU CAPTCHA integrates with Laravel via the myra-security-gmbh/eu-captcha PHP package.

Installation

composer require myra-security-gmbh/eu-captcha

Configuration

Store credentials in .env and expose them through config/services.php — the Laravel convention for third-party credentials:

.env

EUCAPTCHA_SITE_KEY=YOUR_SITEKEY
EUCAPTCHA_SECRET_KEY=YOUR_SECRET

config/services.php

'eucaptcha' => [
    'sitekey' => env('EUCAPTCHA_SITE_KEY'),
    'secret'  => env('EUCAPTCHA_SECRET_KEY'),
],

Controller

<?php

namespace App\Http\Controllers;

use Myrasec\EuCaptcha;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;

class ContactController extends Controller
{
    public function submit(Request $request): RedirectResponse
    {
        $captcha = new EuCaptcha(
            sitekey: config('services.eucaptcha.sitekey'),
            secret:  config('services.eucaptcha.secret'),
        );

        $result = $captcha->validate(
            $request->input('eu-captcha-response'),
            $request->ip(),
        );

        if (!$result->success()) {
            return back()->withErrors(['captcha' => 'CAPTCHA verification failed.']);
        }

        // process the form...

        return redirect()->route('contact.success');
    }
}

$request->ip() respects Laravel's trusted proxy configuration (set via App\Http\Middleware\TrustProxies or the trustedproxy config), so the real visitor IP is forwarded correctly when running behind a load balancer or CDN.

Form Request

For reusable validation across multiple controllers, add the CAPTCHA check to a dedicated FormRequest:

<?php

namespace App\Http\Requests;

use Myrasec\EuCaptcha;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;

class ContactRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'name'    => ['required', 'string', 'max:255'],
            'email'   => ['required', 'email'],
            'message' => ['required', 'string'],
        ];
    }

    protected function withValidator(Validator $validator): void
    {
        $validator->after(function (Validator $validator) {
            $captcha = new EuCaptcha(
                sitekey: config('services.eucaptcha.sitekey'),
                secret:  config('services.eucaptcha.secret'),
            );

            $result = $captcha->validate(
                $this->input('eu-captcha-response'),
                $this->ip(),
            );

            if (!$result->success()) {
                $validator->errors()->add('captcha', 'CAPTCHA verification failed.');
            }
        });
    }
}

Inject ContactRequest instead of Request in your controller method — Laravel resolves and validates it automatically before the method body runs:

public function submit(ContactRequest $request): RedirectResponse
{
    // validation and CAPTCHA check already passed
    // process the form...

    return redirect()->route('contact.success');
}