Skip to content
FitMyKBVerify

FitMyKB Verify

Add a CAPTCHA to Laravel with a validation rule

A small validation rule checks the token with siteverify, so any form request can require it next to its other rules.

Keys

Add FMK_SITE_KEY and FMK_SECRET to .env and map them in config/services.php under 'fitmykb' as site_key and secret.

The rule

The rule posts the token to siteverify with Laravel's HTTP client and fails the field when the check doesn't pass.

PHP · app/Rules
<?php // app/Rules/FitMyKBCaptcha.php
namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Support\Facades\Http;

class FitMyKBCaptcha implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $reply = Http::asForm()->timeout(5)->post('https://fitmykb.com/captcha/siteverify', [
            'secret' => config('services.fitmykb.secret'),
            'response' => (string) $value,
        ]);
        if (! $reply->json('success')) {
            $fail('Please complete the check.');
        }
    }
}

The form and the controller

Load api.js in the Blade view, place the box in the form, and require fmk-captcha-response with the rule.

Blade and controller
{{-- resources/views/register.blade.php --}}
<script src="https://fitmykb.com/captcha/api.js" async defer></script>
<form method="POST" action="/register">
    @csrf
    <input name="email" type="email">
    <div class="fmk-captcha" data-sitekey="{{ config('services.fitmykb.site_key') }}"></div>
    <button>Create account</button>
</form>

// In the controller
$request->validate([
    'email' => ['required', 'email'],
    'fmk-captcha-response' => ['required', new \App\Rules\FitMyKBCaptcha],
]);

Form requests

In a FormRequest, put the same rule in rules(). Livewire forms can read the token from the request in the action that saves.

Testing

In feature tests, swap the rule with Http::fake for the siteverify address, so tests never call the network.

Get free keys · Full developer docs