2

I'm trying to use recaptcha on my website. Nodejs server with express framework. The site isn't being hosted, I'm still working on it locally. On the homepage, after the user enters his info to create an account, and solves the recaptcha, I send the results

$("#g-recaptcha-response").val()

to the server. And on my server,

https.get("https://www.google.com/recaptcha/api/siteverify?secret=" + SECRET + "&response=" + key, function(res) {
            var data = "";
            res.on('data', function (chunk) {
                    data += chunk.toString();
            });
            res.on('end', function() {
                    try {
                            var parsedData = JSON.parse(data);
                            console.log(parsedData);
                            callback(parsedData.success);
                    } catch (e) {
                            callback(false);
                    }
            });
    });

where key is the response and SECRET is the secret key they give you. I declared a variable SECRET and stored the secret key as a string in it.

Every single time, the for the

console.log(parsedData); 

It's saying

{ success: false, 'error-codes': [ 'invalid-input-secret' ] }

I copied and pasted the secret key, how could it be invalid. It's only supposed to show this error if "The secret parameter is invalid or malformed" as it says on their website. I followed this tutorial.

Rockstar5645
  • 4,376
  • 8
  • 37
  • 62
  • Does the secret include any “special” characters, that might have a defined meaning in a URL? (Such as question mark or ampersand, or non-ASCII characters) Perhaps you just need to URL-encode the value properly? – CBroe Aug 23 '15 at 12:48
  • @CBroe the secret contains some underscores _, how would I URL-encode the value? – Rockstar5645 Aug 23 '15 at 13:10
  • Nah, those should be no problem. But looking at the documentation you linked to, it says it needs to be a POST request, whereas you are doing a GET right now. – CBroe Aug 23 '15 at 14:08
  • I just copied and pasted what I saw on that website (the tutorial) and he used a get. I tried replacing it but got some errors. Do I need to be hosting my website right now for this to work, because I'm not, I'm just doing all this on my local server. – Rockstar5645 Aug 23 '15 at 14:11
  • The updated solution has been posted here : https://stackoverflow.com/a/66900684/11636916 – Sarthik Gupta Apr 01 '21 at 08:09

2 Answers2

2

I followed the tutorial too and then bumped into the same error that you have reported here. Looking closely at the screenshot in the tutorial it shows

Send a GET request with these parameters enter image description here

And checking the Google reCaptcha website it says

Send a POST request with these parameters enter image description here

I am curious whether Google changed their mind about POST instead of GET or the screenshot in the tutorial is from a different source.

Regardless, I have tweaked the version of code in the tutorial to make POST request (below code uses querystring module), see below:

var SECRET = "YourSecretHere";

// Helper function to make API call to recatpcha and check response
function verifyRecaptcha(key, callback) {
  //declare above var querystring = require('querystring') on top
  var post_data = querystring.stringify({
    'secret' : SECRET,
    'response': key
  });

  var post_options = {
    host: 'www.google.com',
    port: '443',
    method: 'POST',
    path: '/recaptcha/api/siteverify',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Content-Length': Buffer.byteLength(post_data)
    }
  };
  var req = https.request(post_options, function(res) {
    var data = "";
    res.on('data', function (chunk) {
      data += chunk.toString();
    });
    res.on('end', function() {
      try {
        var parsedData = JSON.parse(data);
        callback(parsedData.success);
      } catch (e) {
        callback(false);
      }
    });
  });
  req.write(post_data); 
  req.end();
  req.on('error',function(err) {
    console.error(err);
  });
}

I also wanted to add that remoteip field is optional but, you can pass that value too if you want too. In order to do that, you need to retrieve the remoteIpAddress from connection object or simply enable trust proxy on your app as shown below:

app.enable('trust proxy'); 

and then pass the ip address to the verifyRecaptcha and the call would look like follow:

verifyRecaptcha(req.ip, req.body["g-recaptcha-response"], function(success) {
   if(success) { ...} else { ... } 
}); 

You then need to modify the post_params to include remoteip field as follow:

var post_data = querystring.stringify({
    'secret' : SECRET,
    'response': key,
    'remoteip': ip
  });

app.enable('trust proxy'); allows req.ip and req.ips which is an array of ip addresses. For more info on getting the ip address of request see this SO question.

If you are developing and you get fed up with all tricky famous and the most annoying Street Names reCaptcha, then I recommend that you use the test Site and Secret keys provided by Google to override captcha solving in order to speed up development. See here

Community
  • 1
  • 1
Raf
  • 7,505
  • 1
  • 42
  • 59
  • I logged in just to upvote your answer, nice catch!!! Although I had the same problem after that as Rockstar5645 said, I had to add the variable SECRET directly. Also you have a small typo in the 4th line "rqeuire" :P – Light Flow Dec 25 '15 at 16:40
  • @LightFlow glad the answer was helpful. Btw, I updated the answer to show up to add **remoteip** which is optional. I have also provided instructions on using the default development site and secret keys to speed up development (skips reCaptcha solving). Solving the street signs reCaptcha is very annoying :( – Raf Dec 25 '15 at 21:56
1

This is really stupid, and I can't believe I wasted this much time on it but instead of using the variable SECRET, I just added my secret key to the url and it worked.

Rockstar5645
  • 4,376
  • 8
  • 37
  • 62
  • I tried adding the SECRET directly but, didn't work for me :( and then I tried to transform the GET to POST request and managed to get it working. Posted my solution, in case it is useful to others having the same issue. – Raf Dec 22 '15 at 23:28