DEV Community

Sesha
Sesha

Posted on

Integrating Google reCAPTCHA with Laravel, Inertia JS and Vue 3.

I will show you how to add the Google reCAPTCHA version 3 with Laravel with a few simple steps.

I assume you already installed Laravel with Jetstream, InertiaJS and Vue3. If not, this link will help you to install.

Setup 1:

Register your site in the Google reCAPTCHA and get the reCAPTCHA site key and Secret Key.

Configure those values in the config services.php file for better accessibility and management.


 'google_recaptcha' => [
   'url' => 'https://www.google.com/recaptcha/api/siteverify',
   'site_key' => env('GOOGLE_RECAPTCHA_SITE_KEY'),
   'secret_key' => env('GOOGLE_RECAPTCHA_SECRET_SITE_KEY'),
 ]

Enter fullscreen mode Exit fullscreen mode

To access the reCAPTCHA site key in the frontend, share through the HandleInertiaRequest file. Directly mentioning the site key in the front end isn't a great idea.

 public function share(Request $request)
 {
     return array_merge(parent::share($request), [
      'recaptcha_site_key' => config('services.google_recaptcha.site_key'),
     ]);
 }

Enter fullscreen mode Exit fullscreen mode

Setup 2:

Install Vue recaptcha v3 and import in app.js file.

import { VueReCaptcha, useReCaptcha } from 'vue-recaptcha-v3'
...


createInertiaApp({
  title: (title) => `${title} - ${appName}`,
  resolve: (name) => require(`./Pages/${name}.vue`),
  setup({ el, app, props, plugin }) {
    const captcheKey = props.initialPage.props.recaptcha_site_key;
    return createApp({ render: () => h(app, props) })
      .use(plugin)
      .use(VueReCaptcha, { siteKey: captcheKey } )
      .mixin({ methods: { route } })
      .mount(el)
  },
})

Enter fullscreen mode Exit fullscreen mode

Step 3:

To add Google reCAPTCHA to the form. Here, I used a sample form to demonstrate the Google reCAPTCHA with Vue 3 composition API.

<form action="#" method="POST"  @submit.prevent="recaptcha">
   ...

   <jet-input-error :message="form.errors.captcha_token" class="mt-2" />
</form>

<script>
import { useForm } from '@inertiajs/inertia-vue3'
import { useReCaptcha } from "vue-recaptcha-v3";


export default {

  setup() {

    const form = useForm({
      name: null,
      email: null,
      phone: null,
      message: null,
      captcha_token :null,
    })

    const { executeRecaptcha, recaptchaLoaded } = useReCaptcha()
    const recaptcha = async () => {
      await recaptchaLoaded()
      form.captcha_token = await executeRecaptcha('login')
      submit();
    }

    function submit() {
      form.post(route('contact-us.store'), {
        preserveScroll: true,
        onSuccess: () => console.log('success'),
      })
    }

    return {
      form, submit ,recaptcha,
    }
  },
}


</script>

Enter fullscreen mode Exit fullscreen mode

Step 4

Create a Laravel custom rule to verify the token and score. Here, I rejected the form if the score <= 0.5 and status was not equals to true.

<?php

namespace App\Rules;

use Illuminate\Support\Facades\Http;
use Illuminate\Contracts\Validation\Rule;

class Recaptcha implements Rule
{
    /**
     * Create a new rule instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        $endpoint = config('services.google_recaptcha');

        $response = Http::asForm()->post($endpoint['url'], [
            'secret' => $endpoint['secret_key'],
            'response' => $value,
        ])->json();

        if(  $response['success'] && $response['score'] > 0.5) {
            return true;
        }

        return false;
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return 'Something goes wrong. Please contact us directly through the phone or email.';
    }
}

Enter fullscreen mode Exit fullscreen mode

Finally, add in the controller to validate the input request along with reCAPTCHA token.

use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Redirect;
use App\Rules\Recaptcha;

...

public function store() {
 $contact = Contact::create(
   Request::validate([
     'name' => ['required', 'max:50'],
     'email' => ['required', 'max:100','email'],
     'phone' => ['nullable', 'max:13'],
     'message' => ['required', 'max:2000'],
     'captcha_token'  => [new Recaptcha],
    ])
  );  

 return Redirect::route('contact-us');   

}


Enter fullscreen mode Exit fullscreen mode

I hope, this tutorial helps you to integrate Google reCAPTCHA 3 with Laravel. Please let me know if it doesn't work for you.

Thank you.

Top comments (2)

Collapse
 
gnujach profile image
Jose Julian abarca

Hi, first thank for excellent tutorial, one question can you help me?, how can show the Badge only at a component, i load the plugin with Bagde hide, but i need show it in a component, i are not how call the intance of recaptcha in my component, show my code, resource/..app.js
return createApp({render: () => h(app, props)})
.use(plugin)
.use(store)
.use(VueReCaptcha, {
siteKey: captcheKey,
loaderOptions: {
autoHideBadge: true
}
})

My component where a want show the badge:
onMounted(() => {
setTimeout(() => {
const recaptcha = this.$recaptcha
recaptcha.showBadge()
}, 5000)
})

The result, Uncaught TypeError: Cannot read properties of undefined (reading '$recaptcha')

Collapse
 
rlidev profile image
Raúl Lorenzo

How could it load only on the page/contact component instead of globally from app.js?