GOOGLE RECAPTCHA V3 LARAVEL IMPLEMENTATION

August 3rd, 2019 by Kevin Pimentel

I’ve been putting off switching to reCAPTCHA v3 mostly because v2 works just fine, why upgrade? Because nobody cares for the traffic lights and crosswalks. I guess it’s time to get with the times. Here’s how I was able to implement reCAPTCHA v3 in my Laravel blog. 

Register With Google

Start by heading over to Google reCAPTCHA. Here you’ll see a.. Mongoose? I could be wrong. No, no, I’m pretty sure it’s a mongoose. I Googled it. Then, click on the Admin console button. 


Sign in or create an account, you know the drill.



Once you get inside the console, select the + plus button and fill out the form. It’s really easy to get a pair of keys.


Very important to select reCAPTCHA v3. Afterall, it is a tutorial post on how to implement reCAPTCHA v3. 

I Got The Keys Keys Keys

Grab the keys and drop them into your env file.


Yes, those are real keys. No, they are not my keys. Yes, I deleted them before I posted this, they were only generated for the screenshot. 


Now that our keys are loaded in we can start coding.

Form Field

We need to add a field to our form because we are going to pass the data with the form request.


@if (env('RECAPTCHA_SITE_KEY'))
    <input id="recaptchaResponse" name="recaptcha_response" type="hidden">
@endif

JavaScript

We need to get a token from Google for the reCAPTCHA. To do this, we call grecaptcha.execute on script load. Then, we take the response token, and shove it into our input field.


@if (env('RECAPTCHA_SITE_KEY'))
    <script src='https://www.google.com/recaptcha/api.js?render={{ env('RECAPTCHA_SITE_KEY') }}&onload=onloadCallback&render=explicit'></script>
   	<script>
        function onloadCallback() {
	      grecaptcha.ready(function() {
	        grecaptcha.execute('{{ env('RECAPTCHA_SITE_KEY') }}', {
	          action: 'homepage'
	        }).then(function (token) {
	        	var recaptchaResponse = document.getElementById('recaptchaResponse');
	        	recaptchaResponse.value = token;
	        });
	      });
	    }
    </script>
@endif

Server Validation

When the subscription form gets submitted it will hit my controllers store method. I’m doing some validation on the email to make sure it’s not a duplicate email, but that’s not important. The actual validation is happening in the isValidCaptcha method.


I’ll probably move this code into a trait for my Request files. But right now this is a good starting point. 


public function store(SubscriberRequest $request)
{
  	if (!$this->isValidCaptcha($request->all())) {
    	return redirect()->back()->withErrors([
			'message' => 'invalid recaptcha'
		]);
	}

	Subscriber::create($request->validated());

  	return redirect()->back()->with('message', 'subscribed successfully!');
}

public function isValidCaptcha(array $data)
{
    if (env('APP_DEBUG') === true) return true;

	if (!isset($data['recaptcha_response']) || is_null($data['recaptcha_response'])) return false;

	$url = env('RECAPTCHA_URL');
	$secret = env('RECAPTCHA_SECRET_KEY');

	$response = $this->client->get("{$url}?secret={$secret}&response={$data['recaptcha_response']}");
	$json = $response->getBody();
	$recaptcha = json_decode($json);

	if (isset($recaptcha->success) && $recaptcha->success == false) return false;

	return ($recaptcha->score >= 0.5) ? true : false;
}

Here we make a request to the reCAPTCHA site verify URL which is:


https://www.google.com/recaptcha/api/siteverify 


The response will return a score that we can use to determine if the user is a bot or not. Generally, the closer to 1, the more likely it’s a real person. The closer the score is to 0, the more likely that it’s a bot. As you collect analytics you should be able to adjust that number based on the data collected.

Side Notes

  1. To improve this code you might consider moving the score to a config or environment variable. That way the score can be easily adjusted. 
  2. I’d also consider moving the isValidCaptcha into a request trait that can be used by the different request classes, depending on which forms use it.

Conclusion

Implementing reCAPTCHA v3 in Laravel is a breeze. In short, you need to get the keys from Google, add a form field to your form, make a JavaScript request for the reCAPTCHA v3 token, and validate the score on the server.



Kevin Pimentel

There are two types of people in the world: those that code, and those that don’t. I said that! Quote me. My name is Kevin and I’m one of the ones that codes.