Reputation: 1178
In my VueJS app with the node module vue-recaptcha-v3
, reCAPTCHA v3 constantly fails in the verification step. The "protected by reCAPTCHA" banner appears on the page like it should, and the response I get before the verification step is fine. When I try to POST
the token to https://www.google.com/recaptcha/api/siteverify
via fetch
:
// Execute reCAPTCHA with action "login".
const response = await this.$recaptcha('contact');
const data = {
secret: secretKey,
response,
};
try {
const validationResponse = await fetch(validationUrl, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
[...]
I simply get the error Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://www.google.com/recaptcha/api/siteverify. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
So I use mode: 'no-cors'
instead:
[...]
const validationResponse = await fetch(validationUrl, {
method: 'POST',
mode: 'no-cors',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
[...]
which then leads to this response:
{
"success": false,
"error-codes": [
"missing-input-response",
"missing-input-secret"
]
}
I suppose you can't send a content-type of json in no-cors
mode (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Supplying_request_options), so I use multipart/form-data
as a content type instead:
const response = await this.$recaptcha('contact');
const formData = new FormData();
formData.append('secret', secret_key);
formData.append('response', response);
try {
const validationResponse = await fetch(validationUrl, {
method: 'POST',
mode: 'no-cors',
headers: {
Accept: 'application/json',
'Content-Type': 'multipart/form-data',
},
body: formData,
});
[...]
But this only leads to this response from Google:
<HTML>
<HEAD>
<TITLE>Bad Request</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Bad Request</H1>
<H2>Error 400</H2>
</BODY>
</HTML>
I really don't know what to do any more - what am I missing?
Upvotes: 0
Views: 1747
Reputation: 1178
Ok, I finally found the answer here at StackOverflow: reCAPTCHA - error-codes: 'missing-input-response', 'missing-input-secret' when verifying user's response (missing details on POST) - long story short: Googles reCAPTCHA verification server only seems to accept "Content-Type": "application/x-www-form-urlencoded"
, so the data sent in my case needs to be
body: 'secret=' + secretKey + '&response=' + response
.
With these settings no error occurs (Please note: Data sent like this needs to be sanitized vie URLencode! I left that out in this example.) But still it's confusing that e.g. Firefox shows the correct response from Google, but the Vue application can't read it at all - response.ok euqals false!
The reason: The browser/client can't deal with a no-cors
response by itself. The server has to do this! So the reCAPTCHA response has to be sent to your server and the server (e.g. PHP) has to send the data to Google's verification script. There's no other way around this. Google reCAPTCHA's docs are missing all these important points.
Also - to my own shame I just realized this now - it totally makes sense, because for the reCAPTCHA validation you need your secret reCAPTCHA key, and that one should definitely not be stored in your JS application that's sent to the client. You never give away your secret.
Upvotes: 2