How to fix it?
ReCaptcha is a Google service that can be utilized in Magento as part of the features provided by Magento, in which and Administrator can protect a site from abuse and spam.
Since security risks are getting more challenging, this service is being constantly updated by both Google and Magento; reducing the changes for any risk or attack.
However, an upgrade between Magento versions 2.4.3 and 2.4.4 caused a bug that will not allow the Administrator to normally login into the backend site. The Administrator sometimes could be able to login only after several attempts but the issue will re-occur after logout or the session is expired.
How to reproduce it?
If one needs to make sure the issue exists in the current page, the following steps are necessary to reproduce the issue:
- Go to Configuration > Security > Google reCAPTCHA Admin Panel
- Add your Google API Website Key & Google API Secret Key to any reCAPTCHA below:
reCAPTCHA v2 (“I am not a robot”)
reCAPTCHA v2 Invisible
reCAPTCHA v3 Invisible
- Select your reCAPTCHA version (with API keys above) for either below:
Enable for Login
Enable for Forgot Password - Save config
- Flush cache
- Logout from admin backend.
After these steps, besides not being able to login back as Administrator, the following log line will be generated in your log files:
main.ERROR: Can not resolve reCAPTCHA parameter. {“exception”:”[object] (Magento\\Framework\\Exception\\InputException(code: 0): Can not resolve reCAPTCHA parameter. at /var/www/html/magento/vendor/magento/module-re-captcha-ui/Model/CaptchaResponseResolver.php:25)”} []
What is the root cause?
The reason for this is that the JavaScript client isn’t getting the token on submission. So the ReCaptcha param it is looking for is empty.
The client isn’t resolving correctly, because it’s being loaded asynchronously and the way it’s coded, will only activate the form interception after the the file
vendor/magento/module-re-captcha-user/view/adminhtml/templates/recaptcha.phtml
More specifically in the following lines:
const element = document.createElement(‘script’);
const scriptTag = document.getElementsByTagName(‘script’)[0];
element.async = true;
element.src = ‘https://www.google.com/recaptcha/api.js‘
+ ‘?onload=globalOnRecaptchaOnLoadCallback&render=explicit’;
Solution
In order to solve the issue the whole file recaptcha.phtml from above needs to be refactored as follows in order to resolved the captcha correctly.
Step 1
Create a new module (not covered in this article)
Step 2
Create a new template at the folder YourModel/YourCompany/view/adminhtml/templates with any name you want, being in this case recaptcha html
Step 3
Copy and paste the following content in the new template:
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
/** @var $block Magento\ReCaptchaUi\Block\ReCaptcha */
$config = $block->getCaptchaUiConfig();
$renderingOptions = $config[‘rendering’] ?? [];
$isInvisible = !empty($config[‘invisible’]);
?>
<div class=”admin__field <?= /* @noEscape */ $isInvisible ? ‘field-invisible-recaptcha’ : ‘field-recaptcha’ ?>”>
<div
id=”admin-recaptcha”
class=”admin-recaptcha-content<?= /* @noEscape */ !empty($renderingOptions[‘size’]) ?
‘ size-‘ . $renderingOptions[‘size’] : ” ?>”>
</div>
</div>
<script>
require([
‘jquery’
], function (
$
) {
const element = document.createElement(‘script’);
const scriptTag = document.getElementsByTagName(‘script’)[0];
element.async = true;
element.src = ‘https://www.google.com/recaptcha/api.js’
+ ‘?onload=globalOnRecaptchaOnLoadCallback&render=explicit’;
let isRecaptchaLoaded = false;
let token = ”;
let maxRetryAttempts = 5;
let attempts = 0;
let widgetId = 0;
<?php if ($isInvisible): ?>
$(‘#login-form’).submit(function (event) {
if (!token) {
event.preventDefault(event);
event.stopImmediatePropagation();
event.stopPropagation();
let attemptRecaptcha = () => {
attempts++;
if (attempts > maxRetryAttempts){
console.error(“Could not fetch invisible ReCaptcha token. ” +
“Please refresh the page and try again.”);
return;
}
if (!isRecaptchaLoaded) {
setTimeout(() => {
attemptRecaptcha()
}, 1000);
return;
}
grecaptcha.execute(widgetId)
.then( () => {
event.preventDefault(event);
event.stopImmediatePropagation();
event.stopPropagation();
}, (reason) => { })
.catch(err => { console.error(err); });
}
attemptRecaptcha();
}
});
<?php endif; ?>
window.globalOnRecaptchaOnLoadCallback = function () {
isRecaptchaLoaded = true;
widgetId = grecaptcha.render(‘admin-recaptcha’, {
<?php foreach ($renderingOptions as $key => $value): ?>
‘<?= $block->escapeJs($key) ?>’: ‘<?= $block->escapeJs($value) ?>’,
<?php endforeach; ?> ‘callback’: function (_token) {
<?php if ($isInvisible): ?>
token = _token;
$(‘#login-form’).unbind(‘submit’);
$(‘#login-form’).submit();
<?php endif; ?> }
});
}
scriptTag.parentNode.insertBefore(element, scriptTag);
});
</script>
Step 4
Create two new layout files called adminhtml_auth_forgotpassword.xml and adminhtml_auth_login.xml inside the folder YourModule/YouCompanyNamer/view/adminhtml/layout
Step 5
Copy and paste the original content from those files located at vendor/magento/module-re-captcha-user/view/adminhtml/layout
Step 6
Change the template name for the one you created in step 3 in both new layouts.
After this, the reCaptcha login issue will be solved and the Administrator will be able to login back successfully at first attempt.
Before implementing the solution please be sure to double check the issue is reproducible in your environment in order to avoid adding unnecessary modules or extensions to your project.