Skip to content

Instantly share code, notes, and snippets.

@geosem42
Last active August 29, 2025 01:46
Show Gist options
  • Save geosem42/103c39cdf4bb685b51dd10fc38e4eace to your computer and use it in GitHub Desktop.
Save geosem42/103c39cdf4bb685b51dd10fc38e4eace to your computer and use it in GitHub Desktop.

Revisions

  1. geosem42 revised this gist Aug 22, 2024. No changes.
  2. geosem42 revised this gist Aug 22, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion recaptcha-v3.md
    Original file line number Diff line number Diff line change
    @@ -52,7 +52,7 @@ class CaptchaValidation
    ```

    # Create AuthenticateUser Action
    Create `app/Actions/Fortify/AuthenticateUser.php`. This new class is responsible for authenticating users. It checks the user credentials and validates the ReCaptcha response. It uses caching to prevent multiple ReCaptcha validations for the same token, improving performance.
    Create `app/Actions/Fortify/AuthenticateUser.php`. This new class is responsible for authenticating users. It checks the user credentials and validates the ReCaptcha response. It uses caching to prevent multiple ReCaptcha validations for the same token.
    ```
    namespace App\Actions\Fortify;
  3. geosem42 revised this gist Aug 22, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion recaptcha-v3.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    This gist will guide you through the process of integrating Google ReCaptcha v3 into a Laravel Jetstream w/ Inertia application. We'll cover the setup process step-by-step, from configuring API keys to implementing the necessary components.
    This gist will guide you through the process of integrating Google ReCaptcha v3 into a Laravel Jetstream w/ Inertia application.

    # API Keys and Configuration

  4. geosem42 renamed this gist Aug 22, 2024. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  5. geosem42 revised this gist Aug 22, 2024. 1 changed file with 213 additions and 4 deletions.
    217 changes: 213 additions & 4 deletions gistfile1.md
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,216 @@
    Test
    This gist will guide you through the process of integrating Google ReCaptcha v3 into a Laravel Jetstream w/ Inertia application. We'll cover the setup process step-by-step, from configuring API keys to implementing the necessary components.

    some `code` here
    # API Keys and Configuration

    First, obtain your ReCaptcha v3 API keys from the Google ReCaptcha Admin Console. Add these keys to your `.env` file:
    ```
    Lots of code here
    ```
    RECAPTCHA_SITE_KEY=your_site_key_here
    RECAPTCHA_SECRET_KEY=your_secret_key_here
    ```
    Next, update your `config/services.php` file to include the ReCaptcha configuration. This configuration allows us to access our ReCaptcha keys throughout the application using Laravel's config helper. It keeps our sensitive keys secure by referencing environment variables.
    ```
    'recaptcha' => [
    'site_key' => env('RECAPTCHA_SITE_KEY'),
    'secret_key' => env('RECAPTCHA_SECRET_KEY'),
    ],
    ```

    # Create CaptchaValidation Action
    Create a new file `app/Actions/Fortify/CaptchaValidation.php`. This class handles the server-side validation of the ReCaptcha response. It sends a POST request to Google's verification endpoint, logs the result, and returns a boolean indicating whether the validation was successful.
    ```
    namespace App\Actions\Fortify;
    use Illuminate\Support\Facades\Http;
    use Illuminate\Support\Facades\Log;
    class CaptchaValidation
    {
    public function validate($captchaResponse)
    {
    $response = Http::asForm()->post('https://www.google.com/recaptcha/api/siteverify', [
    'secret' => config('services.recaptcha.secret_key'),
    'response' => $captchaResponse,
    ]);
    $result = $response->json();
    Log::info('ReCaptcha validation result', $result);
    if (!$result['success']) {
    Log::warning('ReCaptcha validation failed', $result);
    return false;
    }
    Log::info('ReCaptcha validation successful', [
    'score' => $result['score'] ?? 'N/A',
    'action' => $result['action'] ?? 'N/A',
    ]);
    return true;
    }
    }
    ```

    # Create AuthenticateUser Action
    Create `app/Actions/Fortify/AuthenticateUser.php`. This new class is responsible for authenticating users. It checks the user credentials and validates the ReCaptcha response. It uses caching to prevent multiple ReCaptcha validations for the same token, improving performance.
    ```
    namespace App\Actions\Fortify;
    use App\Models\User;
    use Illuminate\Support\Facades\Hash;
    use Illuminate\Validation\ValidationException;
    use Laravel\Fortify\Fortify;
    use Illuminate\Support\Facades\Cache;
    use Illuminate\Support\Facades\Log;
    class AuthenticateUser
    {
    public function __invoke($request)
    {
    $user = User::where('email', $request->email)->first();
    if ($user) {
    $cacheKey = 'recaptcha_' . md5($request->input('g-recaptcha-response'));
    try {
    $validationResult = Cache::remember($cacheKey, 60, function () use ($request) {
    return app(CaptchaValidation::class)->validate($request->input('g-recaptcha-response'));
    });
    Log::info('ReCaptcha validation result', ['result' => $validationResult]);
    if ($validationResult && Hash::check($request->password, $user->password)) {
    return $user;
    }
    } catch (\Exception $e) {
    Log::error('ReCaptcha validation error', ['error' => $e->getMessage()]);
    }
    }
    throw ValidationException::withMessages([
    Fortify::username() => [trans('auth.failed')],
    ]);
    }
    }
    ```

    # Update CreateNewUser Action
    Modify `app/Actions/Fortify/CreateNewUser.php`. We've added ReCaptcha validation to the user registration process. This ensures that a valid ReCaptcha response is required before creating a new user.
    ```
    namespace App\Actions\Fortify;
    use App\Models\User;
    use Illuminate\Support\Facades\Hash;
    use Illuminate\Support\Facades\Validator;
    use Laravel\Fortify\Contracts\CreatesNewUsers;
    use Laravel\Jetstream\Jetstream;
    class CreateNewUser implements CreatesNewUsers
    {
    use PasswordValidationRules;
    public function create(array $input): User
    {
    // Add this
    app(CaptchaValidation::class)->validate($input['g-recaptcha-response']);
    Validator::make($input, [
    'name' => ['required', 'string', 'max:255'],
    'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
    'password' => $this->passwordRules(),
    'terms' => Jetstream::hasTermsAndPrivacyPolicyFeature() ? ['accepted', 'required'] : '',
    ])->validate();
    return User::create([
    'name' => $input['name'],
    'email' => $input['email'],
    'password' => Hash::make($input['password']),
    ]);
    }
    }
    ```

    # Update HandleInertiaRequests Middleware
    Modify `app/Http/Middleware/HandleInertiaRequests.php`. This modification shares the ReCaptcha site key with all Inertia responses, making it available in our Vue components.
    ```
    public function share(Request $request): array
    {
    return array_merge(parent::share($request), [
    'recaptchaSiteKey' => config('services.recaptcha.site_key'),
    // ... other shared data
    ]);
    }
    ```

    # Create ReCaptcha Vue Component
    Create a new file `resources/js/Components/ReCaptcha.vue`. This component handles the client-side integration of ReCaptcha. It loads the ReCaptcha script, executes the ReCaptcha challenge, and emits the response token to be used in form submissions.
    ```
    <script setup>
    import { onMounted, ref } from 'vue';
    const props = defineProps({
    action: {
    type: String,
    required: true
    },
    siteKey: {
    type: String,
    required: true
    }
    });
    const emit = defineEmits(['captcha-response']);
    const captchaResponse = ref(null);
    onMounted(() => {
    const script = document.createElement('script');
    script.src = `https://www.google.com/recaptcha/api.js?render=${props.siteKey}`;
    document.head.appendChild(script);
    script.onload = () => {
    window.grecaptcha.ready(() => {
    window.grecaptcha.execute(props.siteKey, { action: props.action })
    .then(token => {
    captchaResponse.value = token;
    emit('captcha-response', token);
    });
    });
    };
    });
    </script>
    <template>
    <input type="hidden" name="g-recaptcha-response" :value="captchaResponse">
    </template>
    ```

    # Update Register and Login Vue Components
    Modify `resources/js/Pages/Auth/Register.vue` and `resources/js/Pages/Auth/Login.vue` to include the ReCaptcha component. The `setCaptchaResponse` function updates the form data with the ReCaptcha token when received from the ReCaptcha component.
    ```
    <script setup>
    import ReCaptcha from '@/Components/ReCaptcha.vue';
    const form = useForm({
    // ... other form fields
    'g-recaptcha-response': '',
    });
    const setCaptchaResponse = (response) => {
    form['g-recaptcha-response'] = response;
    };
    </script>
    <template>
    <!-- ... other form fields -->
    <ReCaptcha
    action="register"
    :site-key="$page.props.recaptchaSiteKey"
    @captcha-response="setCaptchaResponse"
    />
    </template>
    ```

    These changes work together to integrate ReCaptcha v3 into the authentication flow of a Laravel Jetstream application, enhancing security without significantly impacting the user experience.
  6. geosem42 renamed this gist Aug 22, 2024. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  7. geosem42 created this gist Aug 22, 2024.
    7 changes: 7 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,7 @@
    Test

    some `code` here

    ```
    Lots of code here
    ```