Here is a working implementation for ReCaptcha V3:
package.json
"dependencies": {
"@nuxtjs/axios": "^5.13.6",
"@nuxtjs/recaptcha": "^1.0.4",
"h3": "^0.3.9",
},
Note the h3 version. I wasn't able to get it working with a newer version of that because the library is converted to EJS/mjs and TypeScript, which conflicts with Nuxt. Transpiling h3 didn't fix it. It may work with Nuxt V3+.
nuxt.config.js
modules: [
['@nuxtjs/recaptcha', {
siteKey: process.env.RECAPTCHA_SITE_KEY,
version: 3,
}],
],
serverMiddleware: [
{ path: '/api/check-token', handler: '~/middleware/recaptcha' },
],
middleware/recaptcha.js
import { useBody } from 'h3';
import axios from 'axios';
export default async (req, res) => {
res.setHeader('Content-Type', 'application/json');
try {
const { token } = await useBody(req);
if (!token) {
res.end(
JSON.stringify({
success: false,
message: 'Invalid token'
})
);
return;
}
axios.get(`https://www.google.com/recaptcha/api/siteverify?secret=${process.env.RECAPTCHA_SECRET_KEY}&response=${token}`).then((answer) => {
if (answer.status) {
res.end(
JSON.stringify({
success: true,
message: 'Token verified'
})
);
} else {
res.end(
JSON.stringify({
success: false,
message: 'Invalid token'
})
);
}
});
} catch (e) {
console.log('ReCaptcha error:', e);
res.end(
JSON.stringify({
success: false,
message: 'Internal error'
})
);
}
};
.env
RECAPTCHA_SITE_KEY=gosei478htosvei478tvoei478tvge
RECAPTCHA_SECRET_KEY=ios47eos487t6es4897gtv6es487
index.vue
async mounted() {
try {
await this.$recaptcha.init();
} catch (err) {
throw new Error(`index# Problem initializing ReCaptcha: ${err}.`);
}
},
beforeDestroy() {
this.$recaptcha.destroy();
},
methods: {
async submitContactForm() {
try {
const token = await this.$recaptcha.execute('contact')
const formData = {
email: this.contactForm.email,
firstname: name.firstName,
lastname: name.lastName,
phone: this.contactForm.phone,
band_name: this.contactForm.band_name,
initial_message: this.contactForm.message,
}
// note: use POST request
const recaptcha = await this.$axios.post('/api/check-token', { token });
console.log('recaptcha', recaptcha.data);
if (recaptcha.data.success) {
const result = await this.$axios.post(process.env.CONTACT_FORM_API, formData);
// cleanup logic
} else {
// handle error case
}
} catch (err) {
// handle errors
}
},
},
You can read more here: https://www.npmjs.com/package/@nuxtjs/recaptcha
Note the section where it says
Server Side
When you send data + token to the server, you should verify the token on the server side to make sure it does not requested from a bot. You can find out how to verify token on the server side by looking at the server middleware inside v2 example. (The server side is same for both versions)
The above server-side middleware comes from there. It is important to use the version of h3 that I suggest because you need it to access useBody(req). I tried for several hours to find another way to read the request body but it proved too difficult. Your results may vary in a newer version of Nuxt. I suggest trying the newest version of h3 and if that fails with errors when building the application, try the older version.
It is critically important to not expose the ReCaptcha secret key, and this solution keeps it secret in the server-side.
A more optimal solution might be to use your actual server and make an endpoint for validating ReCaptcha tokens. This above solution allows you to do it purely client-side, assuming you are using SSR.