Google reCaptcha with AngularJS

May 19, 2015
by Rahil Shaikh

Tough on bots, easy on humans, this is Google’s “No CAPTCHA reCAPTCHA” and this tutorial will show you how to integrate it in your AngularJs projects.

Captchas are meant to protect your website from spam and abuse, Google has introduced this new service with quite a few innovative ways to prove you are a human and let you pass with ease while making it difficult for bots.

Overview

For the demo I’ll create a simple signup from with AngularJS which will include the reCaptcha widget. The user will have to solve the captcha to be able to submit the form. Solving the captcha will give us the “g-captcha-response” which we will verify at the back-end.

For client-side implementation I’ll be using angular-recaptcha library. This library will make it easier to use reCaptcha in our angular forms.

We will also need a web api to send “g-captcha-response” to our back-end, where we will have to verify it by making a post request to Google’s siteverify API.  The API could be built using anything eg: nodejs, java, php.

For this demo I’m using php slim framework, I’ll add the sample code at the end.

Sections

  • Register your website to avail Google reCaptcha service

Client side implementation

  • Set up AngularJs project
  • Display reCaptcha Widget
  • Get g-captcha-response after user verifies
  • Make ajax request to server with g-captcha-response

Server side implementation

  • Verify user’s response with Google

 

DEMO  DOWNLOAD

Note: The signup form is for demo purpose, we are not storing any information that you may enter, feel free to enter any random info.

Register your website to avail Google reCaptcha service

To register you website for reCaptcha visit https://www.google.com/recaptcha/, sign in with your Google account. Fill the register form with your domain details and hit register.

Google reCaptcah

On successfully registering Google provides you with a site key and a secret key.

Site Key: You will use this on you client side code.

Secret Key: This will be used to communicate from your server to Google, make sure you keep it a secret.

Set up AngularJs project

You can skip to the next step if you are only looking for reCaptcha integration.

Below is our markup of a simple signup form with AngularJS. We have included the AngularJS library and bootstrap css files.

The angular app and controller is defined. We have a simple signup form setup with name, email and password fields. I’m using Angular’s “controller as” syntax in this example. You can know more about it here.

index.html
<html>
       <head>
        <link href="css/bootstrap.min.css" rel="stylesheet" media="screen" />
        <link href="css/bootstrap-theme.min.css" rel="stylesheet" media="screen"/>
    </head>
    <body ng-app="angularRecaptcha">
        <div class="col-md-6 col-md-offset-3 signupform" ng-controller="recapCtrl as recap">
            <form name="recap.signupForm" ng-submit="recap.signup()">
                <div class="form-group">
                    <label>Name</label>
                    <input type="text" class="form-control" ng-model="recap.name" placeholder="Enter Name" required>
                </div>
                <div class="form-group">
                    <label>Email address</label>
                    <input type="email" class="form-control" ng-model="recap.email" placeholder="Enter email" required>
                </div>
                <div class="form-group">
                    <label>Password</label>
                    <input type="password" class="form-control" ng-model="recap.password" placeholder="Password" required>
                </div>
                <button type="submit" class="btn btn-default">Submit</button>
            </form>
        </div>

        <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.js"></script>
        <script src="js/app.js"></script>
    </body>
</html>

Lets have a look at our app.js. Here I’ve defined the angular module and recapCtrl as our controller. The controller has a function as vm.signup(), that at the moment does nothing.

app.js
(function(){
    angular.module('angularRecaptcha',[])
   
    .controller('recapCtrl',[function(){
        var vm = this;
       
        vm.signup = function(){

        }
    }])
})()

Display reCaptcha Widget

We are using an angular library angular-recaptcha for our client side implementation.

The first thing we need to do is include reCaptcha library provided by Google into your project.

<script src=https://www.google.com/recaptcha/api.js?onload=vcRecaptchaApiLoaded&render=explicit async defer></script>

Include the above line in your head tag. The onload callback is necessary to notify angular-recaptcha library that reCaptcha api is ready for usage.

Next download the angular-recaptcha library and include the js file in your project. You can install it using npm, bower or download it from the below link.

https://github.com/VividCortex/angular-recaptcha/blob/master/release/angular-recaptcha.min.js

Now inject the vcRecaptcha as dependency into you angular module.

angular.module(‘angularRecaptcha’,[‘vcRecaptcha’])

Adding the reCaptcha widget to the UI is easy, just add the directive as an attribute with your site key.

<div vc-recaptcha key=“‘—–YOUR SITE KEY ——‘></div>

Add the below to you code just after the password field in your HTML.

index.html
.....
..
<!--Recaptcha Widget--->
<div vc-recaptcha key="recap.publicKey"></div>
...
.....

Then in your controller add the public key. Make sure you have injected vcRecaptcha as dependency in your module.

app.js
.controller('recapCtrl',[function(){
        var vm = this;
       
        vm.publicKey = "----YOUR------SITE--------KEY---";

               vm.signup = function(){

        }
...
...
......

 

Get g-captcha-response after user verifies

Now that we have the reCaptcha widget in our UI, the user can resolve the captcha. What we need now is the g-capthca-response string after the user resolves the captcha.

The angular-recaptcha library provides us with the vcRecaptchaService that has a getResponse() method, which provides us with g-captcha-response string after the user has successfully solved the captcha.

Have a look at the code below.

app.js
.controller('recapCtrl',['vcRecaptchaService','$http',function(vcRecaptchaService,$http){
        var vm = this;
        vm.publicKey = "----YOUR------SITE--------KEY---";
       
        vm.signup = function(){
           
            /* vcRecaptchaService.getResponse() gives you the g-captcha-response */
           
            if(vcRecaptchaService.getResponse() === ""){ //if string is empty
                alert("Please resolve the captcha and submit!")
            }else {
                var post_data = {  //prepare payload for request
                    'name':vm.name,
                    'email':vm.email,
                    'password':vm.password,
                    'g-recaptcha-response':vcRecaptchaService.getResponse()  //send g-captcah-reponse to our server
                }
               
            }
        }
    }])

Here above we have first injected vcRecaptchaService into our controller, we have also injected $http service which we will need later on to make ajax request to the server.

In our vm.signup() function we are first checking if the value returned by vcRecaptchaService.getResponse() is an empty string, if yes that that means the user has not yet solved the captcha, so we alert them to do so.

In the else block we have also built up our request data, we are storing the user string that is returned by vcRecaptchaService.getResponse() in the key as g-recaptcha-response inside “post_data”

 

Make ajax request to server with g-captcha-response

Now we will send g-captcha-response string to our server via a post ajax request. I’ve created a signup API using php slim framework. Our Signup API takes email, name, password and g-captcha-response as parameters and then at the back-end it verifies the user response (i.e g-captcha-response) with the Google’s siteverify API and then returns relevant response to the client.

app.js
        vm.signup = function(){
           
            /* vcRecaptchaService.getResponse() gives you the g-captcha-response */
           
            if(vcRecaptchaService.getResponse() === ""){ //if string is empty
                alert("Please resolve the captcha and submit!")
            }else {
                var post_data = {  //prepare payload for request
                    'name':vm.name,
                    'email':vm.email,
                    'password':vm.password,
                    'g-recaptcha-response':vcRecaptchaService.getResponse()  //send g-captcah-response to our server
                }
               
               
/* MAKE AJAX REQUEST to our server with g-captcha-string */
                $http.post('http://code.ciphertrick.com/demo/phpapi/api/signup',post_data).success(function(response){
                    if(response.error === 0){
                        alert("Successfully verified and signed up the user");
                    }else{
                        alert("User verification failed");
                    }
                })
                .error(function(error){
               
                })
            }
        }

If the response from the ajax request is success and the error returned is 0, it means we have successfully verified the g-captcha-response string by Googles siteverify API.
See further below what we are doing when the signup API is hit.
 

Verify user’s response with Google

At our server when we receive the “g-captcha-response” string from our signup API, we have to verify the user’s response using the below API provided by google.

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

This api takes three parameters for the POST request.

  1. secret : ————YOUR SECRET KEY ———-
  2. response: g-captcha-response string received from the front-end.
  3. remoteip: —-THE USERS IP ADDRESS———–

 

For this applications implementation I’ve used php slim framework to build my signup Web API. I’ll only explain below, the code that runs when the API is invoked with required parameters. If you need to know more, or learn on how to build Web API’s using PHP Slim, we have an entire separate tutorial on that, click here.

api/routes/site.php (Signup API code)
<?php
$app->post('/signup',function() use($app){
    $req =  $app->request()->getBody(); //get request pramans
    $data = json_decode($req, true); //parse json string
   
    //Should be some validations before you proceed
    //Not in the scope of this tutorial.

    $captcha = $data['g-recaptcha-response']; //Captcha response send by client
       
        //Build post data to make request with fetch_file_contents
        $postdata = http_build_query(
          array(
            'secret' => '-----YOUR SECRET KEY-------', //secret KEy provided by google
            'response' => $captcha,                    // g-captcha-response string sent from client
            'remoteip' => $_SERVER['REMOTE_ADDR']
          )
        );

        //Build options for the post request
        $opts = array('http' =>
          array(
            'method'  => 'POST',
            'header'  => 'Content-type: application/x-www-form-urlencoded',
            'content' => $postdata
          )
        );

        //Create a stream this is required to make post request with fetch_file_contents
        $context  = stream_context_create($opts);

    /* Send request to Googles siteVerify API */
    $response=file_get_contents("https://www.google.com/recaptcha/api/siteverify",false,$context);
    $response = json_decode($response, true);
   

    if($response["success"]===false) { //if user verification failed
       
        /* return error scenario to client */
        echo json_encode(array(
            "error" => 7,
            "message" => "Robots Not allowed (Captcha verification failed)",
            "captchaResult" => $response["success"],
            "captcahErrCodes" => $response["error-codes"]  //error codes sent buy google's siteVerify API
        ));
    } else {
   
             //Should be some Datatbase insertion to sign up the user
             //before you return the success response
             //Not in the scope of this tutorial.

        /* return success scenario to client */
        echo json_encode(array(
        "error" => 0,
        "message" => "Successfully signed up!",
            "email" => $data['email'],
            "captchaResult" => $response["success"]
        ));
    }

});
?>

So when ever there is a request to our signup API the above block of code executes.
Explanation

First we get all the request params in the $req variable, then we use json_decode to parse the json string into $data.
Next we get the g-captcha-response string into $captcha variable.
We build $postdata then $opts and then create a stream from them using php’s stream_context_create($opts) function and put it into $context and then use this as options to make a post request using the file_get_contents(URL,false,$context) function to the below URL.

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

This above API takes 3 parameters which I’ve already described above. This Google API verifies the user’s response string.
The response received from this API is as below.

{
  "success": true|false,
  "error-codes": [...]   // optional
}

The response from the above API is stored in the $response variable.
If the verification is successful success key is returned as “true”, else its “false”. So depending on this we can take action.
If the verification is successful we return success scenario, else we return error and communicate it to the client by our signup API.
And then depending on the response returned to client we can take appropriate action in our UI. For the demo we are only showing an alert message.
 

Conclusion

Captcha’s are a must to protect your website from spam messages but some times they can shoo the actual users, Google’s new reCaptcha makes it much easier for humans to pass, at the same time making it more difficult for bots.
Also the reCaptcha widget looks cool as compared to older ones, plus the integration is very very easy. Hope this tutorial made it a lot more easier.
So go ahead and add this to your website.

Read more about it on Google’s official page.
Google’s official online security blog.

About

Engineer. Blogger. Thinker. Loves programming and working with emerging tech. We can also talk on Football, Gaming, World Politics, Monetary Systems.

Free PDF

Subscribe and get AngularJS Tips PDF. We never spam!
First Name:
Email:

28 comments

    • |

      Yes Chris you are right, it should have been “Users Ip address” over there, thanks for pointing that out to me. Made the correction. 🙂

  1. |

    I am using above code by customizing and getting angular error “Error: vcRecaptchaService.getResponse is not a function”. Please help me out.

    • |

      Can you check if you have injected ‘vcRecaptcha’ into you module.
      And also injected ‘vcRecaptchaService’ into you controller.

  2. |

    Hi!

    I tried your code, but the ReCaptcha does not appear on the page .

    • |

      Hi can you elaborate more on your problem, what steps you followed etc. It should appear if you have followed the steps correctly, validate if you have registered your website with the proper domain name and also added the proper SITE KEY. Check demo for reference.

  3. |

    hi!

    I have registered my site, and I added the publicKey to the vm.publicKey variable, I am using rails so , the tags have also been included in order

    recaptchajs
    angular.js
    angular-recaptcha.js
    main.js < this is where I put your code

    when I see the page source the div has not rendered

    • |

      Okay so if the order of tags is important, then try removing async and defer attributes from the recaptcha API script tags

  4. jonathan
    |

    Hi, I tried your code and the widget didn’t show up on the page. I am running it on local server, is it okay?

    • |

      It should probably work on localhost. Make sure you have a valid reCaptcha Key (You get this when you register your website). Try adding localhost to the list of domain.

    • Bart
      |

      If you are copy&pasting from the above code, you may need to re-type the quotation symbols (“). This fixed the problem for me. (Sometimes the simple things!)

  5. Adrian
    |

    Nice work, but I have a problem. If i use it on my site, were i change the state throught $state.go(…) and i come back to the site that is in a ui-view the widget crashed. with this:
    TypeError: Cannot read property ‘value’ of null
    at Object.Bn [as getResponse] (recaptcha__de.js:312)
    at Object.app.service.$q.getResponse (angular-recaptcha.js:96)

    at angular.js:10846
    at callback (angular.js:19134)
    at Scope.$eval (angular.js:12701)
    at Scope.$apply (angular.js:12799)
    at HTMLButtonElement. (angular.js:19139)
    at HTMLButtonElement.i.event.dispatch (jquery-1.9.0.min.js:14)
    at HTMLButtonElement.v.handle (jquery-1.9.0.min.js:14)
    it seems it has a problem if you have nested views and change between them. once you show the widget you have no chance to change the site and return back and use the recaptcha widget again 🙁 i don’t know how to fix it yet. maybe you have an idea.

    • |

      Ideally this should not happen, I will check this and let you know.

      • Adrian
        |

        this would be fine. if this not happen to you, i can prepare a small example. just say me. you can do it also with one page that has a ui-view in the included view a dropdown box and the widget. if you change the dropdown box make the recaptcha-widget with ng-if invisible and next time visible. the same problem.

        • |

          Okay if you are using ng-if to hide show the widget. I would recommend you to use ng-show/ng-hide instead.
          As ng-if would remove the element from the dom tyerby removing the bindings within.

          • Adrian
            |

            ok for this problem you are right, this fixed it fast. thx. but the other problem is still there. if i have a ui-view part in an index.html and then i change the route through $state.go(..). I change with this the part of index.html. cause index.html is like a masterpage for me. and inside i have views. i switch the context through this. here i can’t use the trick with ng-show and hide. ofc i could put the captcha stuff inside index.html and control this through ng-show. but then i have not the correct position were the box is visible. you know what i mean. so i have to place the recaptcha inside the view that is loaded in the index.html.

      • |

        Nice post, thanks!
        I have encountered the same issue:
        angular.js:13920 TypeError: Cannot read property ‘value’ of null
        at Object.Do [as getResponse] (recaptcha__nl.js:309)
        at Object.getResponse (angular-recaptcha.js:242)
        caused by $state.go.
        Is there a solution available?

  6. Ricardo Campos
    |

    First of all thanks for all of this info! I’ve manage to implement this but i’m wondering if I can reload the captcha widget after receiving the response from the server.

    I’m using ajax and I need to allow users to send the request again but google will only allow one request per captcha verification.

    • Ricardo Campos
      |

      grecaptcha.reset();

  7. Adrian
    |

    Hi, some steps on fixing the problem with the crash if you visit the page through state.go()? Cause now I have in a nested view a guestbook and in other a contactformular. both use the recaptcha. If I open the contactformular and then the guestbook it crashed at checking the recaptcha. vcRecaptchaService.getResponse() with
    TypeError: Cannot read property ‘value’ of null
    at Object.Bn [as getResponse] (recaptcha__de.js:312)
    at Object.app.service.$q.getResponse (angular-recaptcha.js:96)

    and i realy don’t know why 🙁

    • |

      @Adrian. Me too don’t know why. I gave up and implemented a work-around: most users only register once. If during the session it happens that they navigate (with $state.go) to the view with the recaptcha second time, then a location.reload(true) is issued. This gives a flashing of the app which is not nice but at least the recaptcha is working.

  8. Justin
    |

    Hi,

    I tried this solution and I am getting the following error.

    angular.js:10046 TypeError: Cannot read property ‘value’ of null
    at Object.cp [as getResponse] (recaptcha__en.js:349)
    at Object.getResponse (angular-recaptcha.min.js:7)

    Could you please help me to resolve the issue?

    • |

      Is your recaptcha script triggering before the recaptcha is loaded? Try removing async, defer attributes. If you are still facing the issue provide me a sample code, with the issue, I will look into it.

  9. Emiliano Ricci
    |

    Thanks it was really helpful, I used the $scope var instead of creating one with “this” though. But it helped me to get my captcha working. Thanks a lot.

  10. pramodini
    |

    Make ajax request to server with g-captcha-response Instead of this one shall i use node js server.
    can you provide code for this

  11. |

    Nice work dude ! Thank you very much, it works crazy great !!!

  12. vaibhav more
    |

    hi rahil .
    i got one problem in recapthca when i have already login to my gmail account and then try to solve recaptcha ,recaptcha get directly resovle.

    please reply me ….

    thanks.

  13. vaibhav more
    |

    some time it get resolve and some time its working properly .i am not able to get the problem behind it

Leave a Comment