I am setting an invisible reCAPTCHA in my web application and having trouble verifying the user's response. (even though I am passing the correct POST parameters)
I am programmatically invoking the challenge by calling grecaptcha.execute();
on the client-side. And submitting the form afterwards (registrationForm.submit();
) using the recaptcha callback:
<div class="g-recaptcha" data-sitekey="SITE_KEY" data-callback="onSubmit" data-size="invisible"> </div>
Now after reading "Verifying the user's response" documentation, I figured that the response token is passed as a POST parameter to g-recaptcha-response
:
For web users, you can get the user’s response token in one of three ways:
- g-recaptcha-response POST parameter when the user submits the form on your site
- ...
So I am using Fetch to create a POST request on the server side to the verification endpoint with the required body data:
verify(req, res, next) { const VERIFY_URL = "https://www.google.com/recaptcha/api/siteverify"; return fetch(VERIFY_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ secret: process.env.RECAP_INVIS_SECRET_KEY, response: req.body['g-recaptcha-response'], }), }) .then(response => response.json()) .then(data => { res.locals.recaptcha = data; return next(); }); }
But I keep getting the following response:
{ success: false, error-codes: [ 'missing-input-response', 'missing-input-secret' ] }
Even though I am passing the response and secret as JSON data in the POST body.
Am I doing something wrong? Regards.
Help for reCAPTCHA usersMake sure your browser is fully updated (see minimum browser requirements) Check that JavaScript is enabled in your browser. Try disabling plugins that might conflict with reCAPTCHA.
This means the website believes your actions may be those of a bot. Don't worry, it is programmed to be over-cautious for your security. If you see this error there are a few things you can try: Refresh the page and try to complete the task again. Try a different internet browser to complete the task.
Doing a bit of research and digging around the reCaptcha Google forums, It seems that this endpoint only accepts the default content type; application/x-www-form-urlencoded
.
Which means you should not use JSON to send your response token and site key. Instead, send the value as how the application/x-www-form-urlencoded
defined:
Forms submitted with this content type must be encoded as follows:
- Control names and values are escaped. Space characters are replaced by '+', and then reserved characters are escaped as described in [RFC1738], section 2.2: Non-alphanumeric characters are replaced by '%HH', a percent sign and two hexadecimal digits representing the ASCII code of the character. Line breaks are represented as "CR LF" pairs (i.e., '%0D%0A').
- The control names/values are listed in the order they appear in the document. The name is separated from the value by '=' and name/value pairs are separated from each other by '&'.
Therefore, you got two ways of doing this, either by passing the POST parameters through the URL (query strings) and sending it as a POST request:
https://www.google.com/recaptcha/api/siteverify?secret=${SECRET_KEY}&response=${req.body['g-recaptcha-response']}
or appending the data to the body manually like so:
verify(req, res, next) { const VERIFY_URL = "https://www.google.com/recaptcha/api/siteverify"; return fetch(VERIFY_URL, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: `secret=${SECRET_KEY}&response=${req.body['g-recaptcha-response']}`, }) .then(response => response.json()) .then(data => { res.locals.recaptcha = data; return next(); }); }
The official Google documentation can be found here:
Recaptcha - Verifying the user's response.
Extending on U-ways answer above (thanks for that), if you wanted to keep a JS object structure instead of formatting inline params, you could make use of URLSearchParams
and Object.entries
:
const recaptchaBody = { secret: RECAPTCHA_SECRET, response: recaptchaResponse, }; // Check recaptcha validity fetch("https://www.google.com/recaptcha/api/siteverify", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams(Object.entries(recaptchaBody)).toString(), }) .then((res) => res.json()) .then((data) => { // If it's not a success.. if (!data?.success) { // ERROR } });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With