
Intégration de Recaptcha avec le framework Astro components
par Rebeca Murillo • 21 décembre 2023
Introduction
Afin de renforcer la sécurité du formulaire de contact de mon site web, j’ai décidé d’intégrer reCaptcha V3 de Google avec une vérification du token côté serveur. Après avoir configuré les scripts, j’ai rencontré un problème de CORS lors du chargement du script reCaptcha. Dans ce guide, je mettrai en évidence les points clés pour assurer une intégration fluide et éviter le problème de CORS.

Cette intégration de reCaptcha invoque un défi et valide le comportement de l’utilisateur en arrière-plan, offrant ainsi une expérience utilisateur plus fluide.
Guide étape par étape
Les prérequis pour ce guide :
- Connaissance de base de Node.js et du framework Astro
1. Créer un site Google reCaptcha
Pour créer une configuration de site Google reCaptcha, créez un nouveau site dans la console d’administration Google reCaptcha.
- Accédez à l’administration Google reCaptcha
- Créez un nouveau site
- Sous le type, sélectionnez Score basé (v3)
- Dans Domaines, saisissez le domaine de votre site web. Par exemple : “mywebsite.com”
- Récupérez la clé du site pour votre site front-end. Identifiée comme MY_reCAPTCHA_SITE_ID dans ce tutoriel
- Récupérez la clé secrète pour la validation du token côté backend. Identifiée comme MY_reCAPTCHA_SECRET_KEY

2. Intégrer le script reCaptcha dans un site Astro
Le script requis pour intégrer reCaptcha dans un site web est expliqué dans la documentation de Google pour V3 - Invoquer le défi de manière programmatique.
Pour un site web est implémenté avec le framework Astro en tant que site statique (CSR rendu côté client), il faut prendre note des informations suivantes.
Le script reCaptcha doit être ajouté dans l’élément <head> de la page, avec les attributs async defer, afin que le script soit téléchargé sans bloquer le chargement de la page. Cela garantira que le JavaScript compilé pour le composant Astro est chargé correctement.
Plus d’informations sur les attributs async defer dans cette documentation JavaScript.
<head>
<script
src="https://www.google.com/recaptcha/api.js?render=MY_reCAPTCHA_SITE_ID" async defer
></script>
</head>
3. Générer un jeton de défi reCaptcha lors de la soumission du formulaire
Créez un nouveau composant Astro avec vos champs de formulaire. Dans l’exemple suivant, le formulaire est composé de champs de nom, d’email et de message. Ensuite, lors de la soumission du formulaire, les données du formulaire sont envoyées au backend, qui est responsable de la vérification du jeton généré par le défi reCaptcha.
Fichier src/components/Contact.astro
<script>
const successMessageElement = document.getElementById("success-message");
const errorMessageElement = document.getElementById("error-message");
const informationMessageElement = document.getElementById(
"information-message"
);
function onSuccess() {
successMessageElement?.classList.remove("hidden");
errorMessageElement?.classList.add("hidden");
informationMessageElement?.classList.add("hidden");
}
function onError() {
successMessageElement?.classList.add("hidden");
errorMessageElement?.classList.remove("hidden");
informationMessageElement?.classList.add("hidden");
}
function onInformation() {
successMessageElement?.classList.add("hidden");
errorMessageElement?.classList.add("hidden");
informationMessageElement?.classList.remove("hidden");
}
function sendEmail({ name, email, message }) {
grecaptcha.ready(function () {
grecaptcha
.execute("MY_reCAPTCHA_SITE_ID", {
action: "submit",
})
.then(function (recaptchaToken) {
postMessage(
{ name, email, message, recaptchaToken },
onSuccess,
onError
);
});
});
}
async function postMessage(
{ name, email, message, recaptchaToken },
onSuccess,
onError
) {
const url = `https://my.backend.api/message`;
const data = {
from: email,
text: message + `\n` + name,
subject: `Contact message from ${name}`,
recaptchaToken: recaptchaToken,
};
try {
const response = await fetch(url, {
method: "POST",
body: JSON.stringify(data),
});
if (response.ok) {
onSuccess();
} else {
onError();
}
} catch (e) {
onError();
}
}
const btnContactSend = document.getElementById("btn-contact-send");
btnContactSend?.addEventListener("click", function (event) {
event.preventDefault();
const name = document.getElementById("input-name")?.value;
const email = document.getElementById("input-email")?.value;
const message = document.getElementById("input-message")?.value;
if (name?.length > 0 && email?.length > 0 && message?.length > 0) {
sendEmail({ name, email, message });
} else {
onInformation();
}
});
</script>
<div id="contact" class="flex flex-col w-full md:w-8/12 lg:w-6/12 m-auto px-1">
<h2 class="text-center">My contact form</h2>
<div
class="col-span-1 flex flex-col p-5 rounded-xl my-2 lg:m-10 border-solid border shadow-lg border-gray-950 bg-gray-400"
>
<form id="contact-form" class="flex flex-col p-2 lg:p-8 gap-6">
<Input id="input-name" label="Name" type="text" />
<Input id="input-email" label="Email" type="text" />
<Input id="input-message" label="Message" type="textarea" />
<span class="hidden text-red-500" id="error-message">
Error sending the email
</span>
<span class="hidden text-blue-800" id="information-message">
The fields are incorrect
</span>
<span class="hidden text-green-500" id="success-message">
Message was sent successfully
</span>
<Button id="btn-contact-send" label="Send" type="primary" />
</form>
</div>
</div>
Vous pouvez maintenant appeler votre composant Contact Astro dans votre page index.astro.
<head>
<script
src="https://www.google.com/recaptcha/api.js?render=MY_reCAPTCHA_SITE_ID" async defer
></script>
</head>
<body>
<Contact />
</body>
4. Vérifiez le jeton de défi reCaptcha dans votre serveur backend
Pour vérifier le jeton depuis votre serveur backend, appelez la route /siteverify. Plus d’informations sur la route et les codes de réponse possibles dans la documentation Guide reCaptcha Vérification de la réponse de l’utilisateur

Voici un exemple de contrôleur de route API backend, qui prend un corps contenant les entrées du formulaire et le défi reCaptcha. Cette fonction est publié à travers d’une fonction serverless, plus d’informations à ce sujet dans mon tutoriel CI/CD Envoyer un e-mail avec une fonction serverless sur AWS Lambda
async function validateCaptcha(recaptchaToken) {
const response = await fetch(
"https://www.google.com/recaptcha/api/siteverify",
{
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
secret: "MY_reCAPTCHA_SECRET_KEY",
response: recaptchaToken,
}),
}
);
const data = await response.json();
console.log("recaptcha response: ", data);
return data;
}
exports.handler = async (event) => {
console.log("event: ", event);
const { recaptchaToken, from, subject, text } = JSON.parse(event.body);
// Step 1: Validate the reCAPTCHA response
const captchaValidationResult = await validateCaptcha(recaptchaToken);
if (!captchaValidationResult.success) {
return response(400, { message: "reCAPTCHA verification failed" });
}
// Step 2... continue
}

