Google Recaptcha not working with axios - node.js

I am encountering an error while trying to verify my recaptcha witch axios
try{
let result = await axios.post(
'https://www.google.com/recaptcha/api/siteverify',
{
secret: '6LcarRkTAAAAAPDNrruugUg1fJqOJnH-uvVa5KIL',
response: response
},
{
headers: {
"Content-Type": "application/json"
}
});
let data = result.data || {};
if(!data.success){
throw({
success: false,
error: 'response not valid'
})
}
}catch(err){
console.log(err);
throw err.response ? err.response.data : {success: false, error: 'verifyCatpcha Error'}
}
I am always getting the error
{ success: false,
'error-codes': [ 'missing-input-response', 'missing-input-secret' ] }
I tried it with postman and it works fine. Something wrong with my header?

You need to add one more key to your request: secret. The error message is caused by missing response and secret parameters when sending POST request.
UPDATE: The POST params in the doc are not JSON, they must be passed as query string. That's why the error says it's missing both missing-input-response and missing-input-secret
axios.post(
`https://www.google.com/recaptcha/api/siteverify?secret=${secret}&response=${response}`,
{},
{
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8"
},
},
);
Reference: Doc

I managed to solve it be adding params.
I will accept Ryan Wus answer cause it is basically the same with different writing.
try{
let result = await axios({
method: 'post',
url: 'https://www.google.com/recaptcha/api/siteverify',
params: {
secret: '6LcarRkTAAAAAPDNrruugUg1fJqOJnH-uvVa5KIL',
response: response
}
});
let data = result.data || {};
if(!data.success){
throw({
success: false,
error: 'response not valid'
})
}
}catch(err){
console.log(err);
throw err.response ? err.response.data : {success: false, error: 'captcha_error'}
}

https://stackoverflow.com/a/48083886/5426839
The POST params in the doc are not JSON, they must be passed as query string. That's why the error says it's missing both missing-input-response and missing-input-secret
Not opposite to the highest answer, just shorter syntax:
axios.post('https://www.google.com/recaptcha/api/siteverify', undefined, {
params: {
secret: RECAPTCHA_V3_SECRET,
response: recaptchaToken
}
})

Related

Keep getting 422 unprocessable entity

Below is my code I keep getting error that it is unprocessable i looked it up and it said
to assign headers to content-type : "application/json" and i am still getting the errors.
export async function action({ request, params }) {
const data = await request.formData();
const eventData = {
title: data.get("title"),
Image: data.get("image"),
date: data.get("date"),
description: data.get("description"),
};
console.log(JSON.stringify(eventData));
const stringData = JSON.stringify(eventData);
const response = await fetch("http://localhost:8080/events", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: stringData,
});
console.log(response);
if (!response.ok) {
throw json({ message: "Could not save event" }, { status: 500 });
}
return redirect("/events");
}
it says server is expecting json and i have converted the data to json and still getting the error

POST request with JSON payload with NodeJS

I'm trying to hit the Intercom API to retrieve a list of conversations and I can't figure out what's wrong. Here is the code:
const request=require('request')
const search_intercom=(admin_id, callback) => {
const options = {
url: 'https://api.intercom.io/conversations/search',
method: 'POST',
headers: {
Authorization: 'Bearer <token>'
},
json: {
query: JSON.stringify({
"field": "teammate_ids",
"operator": "=",
"value": admin_id
})
}
};
request(options, (error, {body} = {}) => {
if (error) {
callback('unable to connect to intercom API', undefined)
} else if (body.length === 0) {
callback('something went wrong', undefined)
} else {
callback(undefined, {
conversation_id: body.conversations[0].id,
client_name: body.conversations[0].source.author.name
})
console.log(body)
}
})
}
module.exports = search_intercom
I was able to wire it up correctly with the web server, so when I debug, options.json.query.admin_id does contain a valid id.
It breaks and says
conversation_id: body.conversations[0].id,
TypeError: Cannot read property '0' of undefined
Here is the content of the body response:
{
type: 'error.list',
request_id: '<some request_id>',
errors: [ { code: 'server_error', message: 'Server Error' } ]
}
Where should I look? I've tried a few different variations of options for sending the payload and I am guessing this is the issue, but I can't find the winning formula...
It looks like I got the body all wrong.
options should look like this instead:
const options = {
url: 'https://api.intercom.io/conversations/search',
method: 'POST',
headers: {
Authorization: 'Bearer <token>'
},
json: true,
body: {
query: {
"field": "teammate_ids",
"operator": "=",
"value": JSON.stringify(admin_id)
}
}
};

Request Module returning null for google API

I was trying Gmail APIs. Using POSTMAN I have created oAuth 2.0 token and was able to hit the URL https://www.googleapis.com/gmail/v1/users/xyz#gmail.com/profile. But when I was trying same with my node project where I invoked the same using :
app.get('/getMail',getMail); in my index.js where getMail is as follows
exports.getMail = (req, res) => {
request({
url: "https://www.googleapis.com/gmail/v1/users/xyz#gmail.com/profile",
method: "GET",
headers: {
Authorization: 'Bearer token'
},
json: true
}, function(response) {
console.log(JSON.stringify(response, null, 4));
return res.json(response);
});
But I am getting the response as null. Any help would be appreciated.
Please change the callback function to include error. The callbacks are usually error-first callbacks meaning first argument is always error.
exports.getMail = (req, res) => {
request({
url: "https://www.googleapis.com/gmail/v1/users/xyz#gmail.com/profile",
method: "GET",
headers: {
Authorization: 'Bearer token'
},
json: true
// Here -> error
}, function(error, response) {
if (error) throw new Error(error); // Handle the error here.
console.log(JSON.stringify(response, null, 4));
return res.json(response);
});

How to fix "Could not handle the request" on google functions node js

So.. I have a problem here, I've created multiple functions. My objective is to call them using simple AJAX requests.
For example:
function createPost(title,description,category,subcategory,tags){
let data = {"kind":"Posts","key":""+title+"","value":{"category":""+category+"","description":""+description+"","subcategory":""+subcategory+"",
"tags":"{'tags' : [{'name':'Lince','color':'blue'},{'name':'BUG','color':'orange'}]}"}};
$.ajax({
type: "POST",
url: "https://"+REGION+"-"+PROJECT_ID+".cloudfunctions.net/"+DATASTORE_CREATE_POST+"",
data: JSON.stringify(data),
crossDomain: true,
dataType: 'json',
contentType: 'application/json',
success: function(response) {
console.log(response);
},
error: function(response) {
console.log(response);
},
});}
I have this function to save a new Kind key:
exports.set = (req, res) => {
//SET CORS
res.set('Access-Control-Allow-Origin', "*")
res.set('Access-Control-Allow-Methods', '*')
res.set('Access-Control-Allow-Headers','*')
// The value contains a JSON document representing the entity we want to save
if (!req.body.value) {
throw new Error(
'Value not provided. Make sure you have a "value" property in your request'
);}
const key = getKeyFromRequestData(req.body);
const entity = {
key: key,
data: req.body.value,
};
return datastore
.save(entity)
.then(() => res.status(200).send(`Entity ${key.path.join('/')} saved.`))
.catch(err => {
console.error(err);
res.status(500).send(err.message);
return Promise.reject(err);
});
};
If a test this function on google site, the result is OK:
But, If I want to call the same function on AJAX request like I said before.. I get:
Error: could not handle the request

Google nocaptcha post from server to siteverify says details are missing

[ { 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{}
});
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
});
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);

Resources