To add more information, I went into the actual package files and DD'd out the response that's being returned from Cloudflare, and the response is success => true, so this is definitely an issue with my code or how Fortify is validating the $request parameters.
Issue with validating Turnstile captcha on login only using Fortify and Laravel-Captcha; register works fine
Ok I've got a very weird problem here that I cannot figure out. I'm using Rahul Dey's Laravel-Captcha package on my site. The captcha is validated correctly on the user registration form no problem, but the exact same snippet on the login form fails to validate. I'm sure it's something I'm doing wrong but I would really appreciate a second set of eyes.
FortifyServiceProvider:
public function boot(): void
{
Fortify::createUsersUsing(CreateNewUser::class);
...
Fortify::authenticateUsing(function (Request $request) {
Validator::make($request->all(), [
'email' => ['required', 'string', 'email', 'max:255'],
Captcha::getResponseName() => ['required', 'captcha'], // <--- Never validates
])->validate();
...
}
CreateNewUser (this works fine):
public function create(array $input): User
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => $this->passwordRules(),
Captcha::getResponseName() => ['required', 'captcha'], // <--- Always validates
'terms' => Jetstream::hasTermsAndPrivacyPolicyFeature() ? ['accepted', 'required'] : '',
])->validate();
Both import the Rahul900day\Captcha\Facades\Captcha; and both have the <x-captcha-container /> element inside their form tags. They both inherit the same layout injecting the JS, and if you dd() the $input / $request, the correct cf-turnstile-response shows up.
I feel like I'm missing something very stupid, but I can't see what.
Ok, so thanks to the Laravel Discord, someone suggest that I bind my request class to the container as part of the FortifyServiceProvider. Once I did that, I was able to correctly use my own FortifyLoginRequest class that extended Fortify's LoginRequest. Now I can use the validator provided in the laravel-captcha package to validate the Cloudflare Turnstile captchas when someone tries to login.
FortifyServiceProvider.php
<?php
namespace App\Providers;
use App\Actions\Fortify\CreateNewUser;
use App\Actions\Fortify\ResetUserPassword;
use App\Actions\Fortify\UpdateUserPassword;
use App\Actions\Fortify\UpdateUserProfileInformation;
use App\Http\Requests\FortifyLoginRequest;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;
use Laravel\Fortify\Fortify;
use Laravel\Fortify\Http\Requests\LoginRequest;
class FortifyServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
$this->app->bind(LoginRequest::class, FortifyLoginRequest::class); // <- I did this
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
<snip>
Fortify::authenticateUsing(function (FortifyLoginRequest $request) { // <- so I could do this
$user = User::where('email', $request->email)->first();
if ($user && Hash::check($request->password, $user->password)) {
return $user;
}
});
<snip>
}
}
FortifyLoginRequest.php
<?php
namespace App\Http\Requests;
use Laravel\Fortify\Fortify;
use Laravel\Fortify\Http\Requests\LoginRequest;
use Rahul900day\Captcha\Facades\Captcha;
class FortifyLoginRequest extends LoginRequest
{
public function authorize(): bool
{
return true;
}
/** @phpstan-ignore-next-line */
public function rules(): array
{
return [
Fortify::username() => ['required', 'string'],
'password' => ['required', 'string'],
Captcha::getResponseName() => ['required', 'captcha'],
];
}
}
Please or to participate in this conversation.