4
[ { hostname: 'www.google.com',
    path: '/recaptcha/api/siteverify',
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'Content-Length': 556 } },
  '{"secret":"XXXUseThisForCommunicationBetweenYourSiteAndGoogleXXX","response":"03AHJ_VuusXdr5IdGpNzQPRjedGs-Le066Fx9r-Lk1gIfLqlzwxapPx70_LukmcOsw3x-m2DSfpvQVylx060H9IjFP82fy7505_t_rjSivauiwBUyQPrBMp5kTRviq_DD1L2mVMTTrBieUMlQM69AIuG3KwmdOQMyMJS2iJdRuRNnvAmDlPSejkASR4X-7c4IIP3NoMb52Qsl9QPeU6kGaPtxqmf1IpNwbSC3bzLXQD-QV1aI4GgaeqSPfOO8EPfISJMQ5kbCd9wqAwHqDAXMtNSvz10Ty30R71HqmsSk7YHddFQhei1L6y9j7nxnY5QtAxHehhpYwJVNjI96hxeIaG58_CQHGbAufy4aPGAlf-zJ6be_Xtdzd4AnHxiX9OuCKQI8eQlh6DZLGaymxXDmPNu4TijGyyu0VeTPTTKf12zVUg86_0ZmszWZDtALjnNnxBH7bZqrgWXhy","remoteip":"00.00.000.000"}' ]

If I post that and google returns this:

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

I don't see what is happening wrong

https://www.google.com/recaptcha/admin#site/XXXXXX?setup says:

When your users submit the form where you integrated reCAPTCHA, you'll get as part of the payload a string with the name "g-recaptcha-response". In order to check whether Google has verified that user, send a POST request with these parameters: URL: https://www.google.com/recaptcha/api/siteverify secret(required) - XXXXXX, response(required) - The value of 'g-recaptcha-response', remoteip - The end user's ip address.

I have clearly sent all these things! What could be happening here? The error does not say they are wrong, it says they are 'missing'

And the above Quoted text from google clearly says POST not GET Google reCAPTCHA: how to get user response and validate in the server side

But if I try a GET request then the response is [ null, 400, undefined ]

UPDATE

As @mscdex pointed out application/x-www-form-urlencoded is required but the responce still said that it was missing the secret so I url encoded this instead as I figured something bad may be happening to the item at the start of the object.

{'_':'_','secret':'XXXXXX','response':'whateverXXYsgTSG','remoteip':'00.00.000.000'}

And finally it worked:

[ { hostname: 'www.google.com',
    path: '/recaptcha/api/siteverify?',
    method: 'POST',
    headers: 
     { 'Content-Type': 'application/x-www-form-urlencoded',
       'Content-Length': 548 } },
  '"_=_&secret=XXXXXX&response=03AHJ_VuurQFgsftybLlvrdGOwXfNneWp4v7FPJJbOD9CGpiHAkFBaiNy7YWXcHrAkU6SPU5UZpgKCptU3gRX5OPqXEh2qqP3nXJpiBWoxFW_Iv05P2UA23rzzZk0ecScmMSL1PP1uyBCdJ08HpAWEuz2PzL6m6u71k09xQbVbPZ5KT6qnb-mdPNyEkdBxtc9a5oYpnOoHg7ax6q4Ms4Lis4qrNBLCavKmYZ6vAmYitSEI0a0GERnlI3wLSvayhc-Yygv1koKIjg2q8GHXV1UhKLzBa8t8x2ibRBNwXUMBFs3Qj_lfwgiTNtIaU3kEAFPULJulZDOsAcovKpjk5xkyMM2C5YDGYMioeyOMl9ZmyyvkwfrrRe8e9o_tD6SaTTSAcrcxsfYGm-w0_CDbsa2IWSkjiMN-2B9SClOZJGXXVXVIuIYClIK3XuUvTsObCzxJAq2IKwwMTtYX&remoteip=00.00.000.000"' ]
[ { success: true }, 200, undefined ]

But I would like to do this properly not hacky So if anyone can answer how to do it properly that would be swell!

var JSON={
        https:require('https')
    ,   toquery:require('../node_modules/querystring').stringify
    ,   stringify:require('../node_modules/json-stringify-safe')
    ,   parse:require('../node_modules/try-json-parse')
    ,   get:function(url,callback){process.env.NODE_TLS_REJECT_UNAUTHORIZED="0";var req=JSON.https.request(url,function(res){var buffer='';res.setEncoding('utf8');res.on('data',function(chunk){buffer+=chunk;});res.on('end',function(){try{var data=JSON.parse(buffer);callback(data,res.statusCode);}catch(e){console.log(e);}});});req.end();}
    ,   post:function(url,path,data,type,callback){if(!callback){callback=type;type=undefined;}data=JSON.stringify(data);var options={hostname:url,path:path,method:'POST',headers:{'Content-Type':type||'application/json','Content-Length':data.length}};console.dir([options,data]);var req=JSON.https.request(options,function(res){var buffer='';res.setEncoding('utf8');res.on('data',function(chunk){buffer+=chunk;});res.on('end',function(){try{var data=JSON.parse(buffer);callback(data,res.statusCode);}catch(e){console.log(e);}});});req.write(data);req.end();}
        };

JSON.post(
        'www.google.com'
    ,   '/recaptcha/api/siteverify?'
    ,   JSON.toquery({'_':'_','secret':'XXXX','response':response,'remoteip':remoteip})
    ,   'application/x-www-form-urlencoded'
    ,   function(data,result,statusCode){
            console.dir([data,result,statusCode]);
            if(result.success){}
            else{}
            });
Community
  • 1
  • 1
Ben Muircroft
  • 2,936
  • 8
  • 39
  • 66
  • 1
    Are you sure the API allows an `application/json` POST submission? Perhaps it's expecting an `application/x-www-form-urlencoded` POST instead? – mscdex Jul 09 '15 at 16:03
  • Updated my question based on this – Ben Muircroft Jul 09 '15 at 16:42
  • Ok, so show how are you making the request. – mscdex Jul 09 '15 at 17:28
  • Updated to show the code – Ben Muircroft Jul 09 '15 at 19:35
  • That looks alright to me and you said it works. Why do you call it "hacky?" – mscdex Jul 09 '15 at 20:00
  • because I have appended `_:_` to the front of the query (its a variable that google does not expect to be there). I would say at this point that they have a bug. Because I am posing correctly without appending a foo variable to the start. But they seam to eat the first variable every time. so it would seem that the only way to get a proper response from them is to hack and add an extra variable of no meaning whatsoever to the front of the payload. – Ben Muircroft Jul 09 '15 at 22:52
  • Thank you for your help @mscdex I am going to keep this question open for anyone to answer (I will be looking to accept). I will in the mean time use this code but, proceed with caution as; I feel sending an unexpected result to a third party is bad practice and could at any time stop working. – Ben Muircroft Jul 09 '15 at 22:59
  • every other API in the world expects/allows application/json and then there's Google who don't allow it, give no error and don't even mention how you're supposed to send those – creamcheese Nov 22 '18 at 19:46

2 Answers2

1

Here is how I do it in one of my project using superagent. This is my recaptcha-helper.js

var request = require("superagent");

var config = {
  recaptcha: {
    secret: "XXXXX",
    url: "https://www.google.com/recaptcha/api/siteverify",
  },
};

var ERROR_CODES = {
  "missing-input-secret": "Unexpected Server Error (1)",
  "invalid-input-secret": "Unexpected Server Error (2)",
  "missing-input-response": "Missing reCAPTCHA value",
  "invalid-input-response": "Invalid reCATPCHA value",
};

exports.getErrorCode = function (errorCode) {
  if (Array.isArray(errorCode)) {
    var errors = errorCode.map(function (code) {
      return exports.getErrorCode(code);
    });
    return errors.join("\n");
  }
  return ERROR_CODES[errorCode] ||
    (errorCode ? ("Unexpected reCAPTCHA error: " + errorCode) : "Unexpected reCAPTCHA error");
};

exports.parseResponse = function (err, res) {
  if (err) {
    return { success: false, error: err };
  } else if (!res.body.success) {
    var error = new Error(exports.getErrorCode(res.body["error-codes"]));
    return { success: false, error: error };
  } else {
    return { success: true };
  }
};

exports.verify = function (response, ip) {
  if (process.env.NODE_ENV === "test") {
    return response ? Promise.resolve() :
      Promise.reject(new Error("Test reCAPTCHA Error"));
  }

  return new Promise (function (resolve, reject) {
    request.post(config.recaptcha.url)
    .type("form")
    .accept("json")
    .send({
      secret: config.recaptcha.secret,
      response: response,
      remoteip: ip,
    })
    .end(function (err, res) {
      var parsedRes = exports.parseResponse(err, res);
      return parsedRes.success ? resolve() : reject(parsedRes.error);
    });
  });
};

And you can use it doing

var captchaHelper = require('./recaptcha-helper');

captchaHelper.verify(req.body.captcha, req.ip)
  .then(function () {
    // on success
  }).catch(function (err {
   // on error
  });
Hugo Dozois
  • 8,147
  • 12
  • 54
  • 58
0

I solved this by passing secret and response as a query parameter:

Example :

axios.post("https://www.google.com/recaptcha/api/siteverify?secret="
+ 'XXXXXX' + "&response=" + response + "&remoteip=" + req.connection.remoteAddress);
Amit Kumar
  • 91
  • 3
  • 17