fix(auth,app-check): Fix Auth/AppCheck ReCAPTCHA Enterprise conflict#9991
fix(auth,app-check): Fix Auth/AppCheck ReCAPTCHA Enterprise conflict#9991hsubox76 wants to merge 7 commits into
Conversation
🦋 Changeset detectedLatest commit: 1f9ee8d The changes in this PR will be included in the next version bump. This PR includes changesets to release 5 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
Code Review
This pull request addresses a conflict between Auth and App Check when both utilize ReCAPTCHA Enterprise by ensuring the script is loaded with the render=explicit parameter in App Check and tracking the injection state in Auth. The reviewer identified a performance regression where the injection flag was defined as an instance property rather than a static one, leading to redundant script loads across multiple verifier instances. Feedback was also provided to ensure this static state is properly reset between tests to maintain isolation.
Fixes #9405
App Check and Auth (when using phone number verification) do not work when both are using ReCAPTCHA Enterprise in the same app. It causes an Auth error.
This bug was caused by two issues, one in Auth and one in App Check.
Auth
The Auth SDK was detecting (with
isEnterprise()) if awindow.grecaptcha.enterpriseobject existed on the page, and if so, did not download the ReCAPTCHA Enterprise (abbreviated RCE from here on out) script, assuming it was ready to use. Unfortunately, this check passes if it sees the ReCAPTCHA Enterprise instance downloaded by App Check (or any other source), which is not sufficient for Auth. In order for RCE to work the way Auth is set up to use it, Auth needs to initiate its own script download with the "render" param set to the user's RCE sitekey.Auth needs to know when this script is ready (it has both finished downloading, AND has initialized) before it can call
grecaptcha.execute(), or there will be an error (as in the issue linked above). It turns out thatgrecaptcha.ready()is not reliable when more than one RCE script is being loaded on the page, as it fires when any script is ready, even though the one you are callingexecuteon may not be ready.script.onloadon the script tag used to download the script also isn't reliable, as there is a small delay between the download of the script and when it finishes its initialization on the page.The one event that does seem reliable is a callback which must be placed on the global
windownamespace, and its name passed to theonloadurl param of the recaptcha script download url (not to be confused withscript.onloadon the script tag).To track this, I have added a new static property:
RecaptchaEnterpriseVerifier.scriptInjectionDeferred, a deferred object (a promise that can be resolved from outside). This deferred object is resolved whenwindow.onFirebaseAuthREInstanceReady()(the new callback we create and pass to the onload url param) is called. Calls toretrieveRecaptchaToken()(which calls execute()) nowawaitthe resolution of this promise.Auth tests
Auth tests needed to be changed as almost all of them now call loadJS, which won't work in a test environment. loadJS has been stubbed in all relevant tests, and the stub calls
window.onFirebaseAuthREInstanceReady()to ensure the deferred is resolved and the code can continue.Also fixed an async test that was incorrect and did not await its result, causing a race condition with the next test.
App Check
App Check does not include the sitekey in the url for downloading the RCE script, as part of its design to allow multiple sitekeys. Instead, it manually renders a widget. When you do this, you are supposed to set a
render=explicitparam on the url, which we didn't. It still worked by itself, but caused this clash with Auth.When both of these changes are made, Auth and App Check both work together.