Desired Behaviour
Incorporate reCaptcha JavaScript code in my webpack bundled js file, rather than via inline script tags.
Actual Behaviour
I am getting this error in Chrome dev tools:
Uncaught ReferenceError: grecaptcha is not defined
What I've Tried
The following inline implementation works and I have been using these docs for reference.
However I had to add unsafe-inline to my script-src Content Security Policy in order to allow the inline script to run. More specifically, this was required to implement explicit rendering via the onLoadCallback function.
Google has an FAQ about CSP and reCaptcha, but it only applies to automatic rendering, where there is no callback function or defined parameters.
I'd prefer not to have to use inline scripts.
index.html
<head>
<script type="text/javascript">
var onloadCallback = function() {
grecaptcha.render('g-recaptcha', {
'sitekey': '******',
'size': 'compact'
});
};
</script>
</head>
<body>
<div id="g-recaptcha"></div>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
</body>
</html>
However, when I try adding the JS to my entry.js file like this (to stop using inline script):
index.html
<head>
<script type="module" src="/js/bundle.js"></script>
<script src="https://www.google.com/recaptcha/api.js?render=explicit" async defer></script>
</head>
<body>
<div id="g-recaptcha"></div>
</body>
</html>
entry.js
const onloadCallback = () => {
grecaptcha.render('g-recaptcha', {
'sitekey': '******',
'size': 'compact',
'data-callback': 'ok-you-can-submit-the-form',
'data-expired-callback': 'you-have-to-click-recaptcha-again',
'data-error-callback': 'something-went-wrong-please-try-again'
});
}
$(document).ready(function() {
onloadCallback();
}
I get the error in Chrome dev tools:
Uncaught ReferenceError: grecaptcha is not defined
So I am guessing this is because bundle.js does not have any knowledge of the recaptcha script, or its related variables, defined in the <head> section.
How can I implement google reCaptcha without using the inline script paradigm?
Edit
I think Google's suggestion to use a nonce-based approach (also suggested in this SO answer) only works if you are doing automatic rendering (where only a <script src="****"> tag is required).
If you are using explicit rendering as I am, which requires definition of a callback function inline, then i don't think the nonce approach works.