I work in asp.net forms, but this solution can be applicable in any language. The problem of the expired token is annoying.
The token has a validity time of 2 minutes in v3, but the practice of leaving a timer refreshing the token every 2 minutes is not recommended by google. They recommend the token be refreshed only when required.
I opted for a javascript solution, forcing the client to click on a button that refreshes the token.
It should be noted that if "recaptcha.ready" is executed when refreshing the recaptcha, an error is thrown, so I had to separate the "ready" from the "execute" and with this the recaptcha is refreshed without errors.
<script type="text/javascript" >
grecaptcha.ready(function () {
captcha_execute();
});
function captcha_execute() {
grecaptcha.execute('<%=System.Configuration.ConfigurationManager.AppSettings("recaptcha-public-key").ToString %>', { action: 'ingreso_usuario_ext' }).then(function (token) {
document.getElementById("g-recaptcha-response").value = token;
});
}
function los_dos(token_viejo) {
captcha_execute()
clase_boton(token_viejo);
}
async function clase_boton(token_viejo) {
btn_act = document.getElementById("Btn_Refrescar");
btn = document.getElementById("Btn_Ingresar");
btn.setAttribute("class", "button_gris");
btn_act.style.display = "none";
btn.style.display = "initial";
btn.disabled = true;
//token_viejo = document.getElementById("g-recaptcha-response").value;
strToken = token_viejo;
varCant = 0;
while (strToken == token_viejo && varCant < 30) {
strToken = document.getElementById("g-recaptcha-response").value;
await sleep(100);
varCant++;
}
btn.setAttribute("class", "button_azul");
btn.disabled = false;
setTimeout(refrescar_token, 120000);
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function refrescar_token() {
btn_ing = document.getElementById("Btn_Ingresar");
btn_act = document.getElementById("Btn_Refrescar");
btn_act.style.display = "initial";
btn_ing.style.display = "none";
}
</script>
In the body
<body style="background-color: #dededc;" onload="clase_boton('');" >
Buttons
<asp:Button ID="Btn_Ingresar" runat="server" Text="Ingresar" CssClass="button_gris" Enabled="false" />
<input type="button" id="Btn_Refrescar" name="Btn_Refrescar" class="button_verde" value="Refrescar Token" title="Refrescar Token" onclick="los_dos(document.getElementById('g-recaptcha-response').value);" style="display: none;" />
With javascript, I wait for the token to be populated and when it is populated, I enable the login button. If the process takes too long (due to some error), I still enable it. This is a matter of choice.
After 2 minutes ("setTimeout"), the login button becomes invisible and I show the button to refresh the token.
I hope this helps/guides you solve your problem.