Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
aa0bdfc
docs(appcheck): design and implementation plan for reCAPTCHA Enterprise
mikehardy Jun 22, 2026
e607d14
feat(app): plumb recaptchaSiteKey through Firebase app options
mikehardy Jun 22, 2026
431f685
feat(app): add isWeb and isOtherHermes platform helpers
mikehardy Jun 22, 2026
e7c01d6
feat(app-check): add reCAPTCHA provider classes and recaptcha unions
mikehardy Jun 22, 2026
3cf283d
feat(app-check): route web App Check to js-sdk reCAPTCHA providers
mikehardy Jun 22, 2026
6d8757c
feat(app-check): route initializeAppCheck by platform for reCAPTCHA
mikehardy Jun 22, 2026
851f1b6
chore(app-check): update compare-types for reCAPTCHA providers
mikehardy Jun 22, 2026
3d92caf
test(app-check): extend type-test for reCAPTCHA and provider-less init
mikehardy Jun 22, 2026
572a8fd
feat(app-check,android): add recaptcha App Check provider factory
mikehardy Jun 22, 2026
ac3e6fb
feat(app-check,ios): add recaptcha App Check provider with fail-fast …
mikehardy Jun 22, 2026
00fec4c
feat(auth): add initializeRecaptchaConfig across platforms
mikehardy Jun 22, 2026
b0a43b0
docs: add reCAPTCHA Enterprise App Check and Auth guidance
mikehardy Jun 23, 2026
703e23f
docs(okf-bundle): add app-check index and reCAPTCHA coverage notes
mikehardy Jun 23, 2026
95df0ab
test: add reCAPTCHA App Check and Auth e2e smoke coverage
mikehardy Jun 23, 2026
ce19ec7
docs: note Expo plugin recaptchaSiteKey config redownload requirement
mikehardy Jun 23, 2026
682db5f
docs: add reCAPTCHA Enterprise test setup and doctor script
mikehardy Jun 23, 2026
ac5000b
fix: restore App Check prepare types and validation test expectations
mikehardy Jul 24, 2026
dcb883e
fix(auth,android): mark initializeRecaptchaConfig as TurboModule Over…
mikehardy Jul 24, 2026
0a09bb1
test(auth): skip initializeRecaptchaConfig smoke on Auth Emulator gap
mikehardy Jul 24, 2026
956aa44
fix(app-check,ios): define local error domain for recaptcha provider
mikehardy Jul 24, 2026
2c5f374
chore(tests,ios): lock RecaptchaEnterprise CocoaPods for e2e app
mikehardy Jul 24, 2026
b16aec5
test(auth): run initializeRecaptchaConfig smoke on secondaryFromNative
mikehardy Jul 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions .github/scripts/compare-types/configs/app-check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,6 @@ const config: PackageConfig = {
reason:
'RN Firebase re-exports this type from `@react-native-firebase/app` common types rather than mirroring the firebase-js-sdk utility export directly.',
},
{
name: 'ReCaptchaEnterpriseProvider',
reason:
'Web-only reCAPTCHA Enterprise provider from the firebase-js-sdk. RN Firebase uses `ReactNativeFirebaseAppCheckProvider` to configure native platform providers instead.',
},
{
name: 'ReCaptchaV3Provider',
reason:
'Web-only reCAPTCHA v3 provider from the firebase-js-sdk. RN Firebase uses `ReactNativeFirebaseAppCheckProvider` for cross-platform provider configuration.',
},
{
name: 'Unsubscribe',
reason:
Expand Down Expand Up @@ -84,12 +74,22 @@ const config: PackageConfig = {
{
name: 'AppCheckOptions',
reason:
'RN Firebase accepts `CustomProvider`, `ReactNativeFirebaseAppCheckProvider`, or a RN-specific provider config object instead of the firebase-js-sdk reCAPTCHA provider classes.',
'RN Firebase extends `AppCheckOptions.provider` with `ReactNativeFirebaseAppCheckProvider` and `ReactNativeFirebaseAppCheckProviderConfig` for cross-platform native provider selection. firebase-js-sdk accepts only reCAPTCHA and `CustomProvider` instances.',
},
{
name: 'CustomProvider',
reason:
'The RN Firebase `CustomProvider` class is tailored to the React Native/native initialization model, so its public class shape differs from the firebase-js-sdk version.',
'RN Firebase declares public `getToken()` on `CustomProvider` because the class implements `AppCheckProvider`. firebase-js-sdk marks provider `getToken` as internal on the public class declaration.',
},
{
name: 'ReCaptchaEnterpriseProvider',
reason:
'RN Firebase declares public `siteKey` and `getToken()` on the provider class for `initializeAppCheck` routing across native and Other/Web. firebase-js-sdk keeps the site key and token fetch internal to the provider implementation.',
},
{
name: 'ReCaptchaV3Provider',
reason:
'RN Firebase declares public `siteKey` and `getToken()` on the provider class for `initializeAppCheck` routing on Other/Web. firebase-js-sdk keeps the site key and token fetch internal to the provider implementation.',
},
],
};
Expand Down
5 changes: 0 additions & 5 deletions .github/scripts/compare-types/configs/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ const config: PackageConfig = {
nameMapping: {},

missingInRN: [
{
name: 'initializeRecaptchaConfig',
reason:
'iOS/Android: native SDKs own phone verification. Other/Hermes: not applicable (no DOM). Other/Web: not implemented yet; firebase-js-sdk support is possible.',
},
{
name: 'AuthErrorCodes',
reason:
Expand Down
26 changes: 26 additions & 0 deletions .spellcheck.dict.txt
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ utils
Utils
v1
v15
v2
v3
v5
v6
v7
Expand All @@ -277,3 +279,27 @@ Xcode
Xcode.
XCS
XMPP
behaviour
B2
configs
fallbacks
firebase-js-sdk-compatible
flutterfire
IAM
init
JS-created
js-created
js-sdk-compatible
misconfigured
monorepo
pre-warm
redownload
Redownload
redownloaded
reCAPTCHA-based
sideloaded
TTY
tty
auth-
phone-auth
multi-factor-auth
126 changes: 118 additions & 8 deletions docs/app-check/usage/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ This App Check module has built-in support for using the following services as a
- DeviceCheck on iOS
- App Attest on iOS
- Play Integrity on Android (requires distribution from Play Store to successfully fetch tokens)
- SafetyNet on Android (deprecated)
- reCAPTCHA Enterprise on Web, iOS, and Android
- Debug providers on both platforms

> **Legacy:** [SafetyNet](https://firebase.google.com/docs/app-check/android/safetynet-provider) on Android is deprecated. Prefer Play Integrity or reCAPTCHA Enterprise.

App Check currently works with the following Firebase products:

- Realtime Database
Expand All @@ -82,12 +84,16 @@ The [official Firebase App Check documentation](https://firebase.google.com/docs

Before the App Check package can be used on iOS or Android, the corresponding App must be registered in the firebase console.

For instructions on how to generate required keys and register an app for the desired attestation provider, follow **Step 1** in these firebase guides:
For instructions on how to generate required keys and register an app for the desired attestation provider, follow **Step 1** in these Firebase guides:

- [Get started using App Check with DeviceCheck on Apple platforms](https://firebase.google.com/docs/app-check/ios/devicecheck-provider#project-setup)
- [Get started using App Check with App Attest on Apple platforms](https://firebase.google.com/docs/app-check/ios/app-attest-provider#project-setup)
- [Get started using App Check with Play Integrity on Android](https://firebase.google.com/docs/app-check/android/play-integrity-provider#project-setup)
- [Get started using App Check with SafetyNet on Android (deprecated)](https://firebase.google.com/docs/app-check/android/safetynet-provider#project-setup)
- [Get started using App Check with reCAPTCHA Enterprise on Web](https://firebase.google.com/docs/app-check/web/recaptcha-enterprise-provider#project-setup)
- [Android `RecaptchaAppCheckProviderFactory` reference](https://firebase.google.com/docs/reference/android/com/google/firebase/appcheck/recaptcha/RecaptchaAppCheckProviderFactory) (mobile reCAPTCHA Enterprise)
- [iOS `FIRRecaptchaProvider` reference](https://firebase.google.com/docs/reference/ios/firebaseappcheck/api/reference/Classes/FIRRecaptchaProvider) (mobile reCAPTCHA Enterprise, iOS only)

After enabling the reCAPTCHA Enterprise App Check provider in the Firebase console, redownload `google-services.json` and `GoogleService-Info.plist` so they include `recaptchaSiteKey`. Native default apps read the site key from these files at startup. Expo config plugins copy these files from `app.json` and do not generate keys — see [Expo and config plugins](/app/json-config#expo-and-config-plugins).

> Additionally, You can reference the iOS private key creation and registrations steps outlined in the [Cloud Messaging iOS Setup](/messaging/usage/ios-setup#linking-apns-with-fcm-ios).

Expand Down Expand Up @@ -193,7 +199,109 @@ It is through the use of a react-native-specific `ReactNativeFirebaseAppCheckPro

So AppCheck module initialization is done in two steps in react-native-firebase - first you create and configure the custom provider, then you initialize AppCheck using that custom provider.

Starting in v25, the modular App Check helpers and types are exported from `@react-native-firebase/app-check` at the package root to better match the Firebase JS SDK. For example, import `initializeAppCheck`, `AppCheck`, and `AppCheckTokenResult` directly from `@react-native-firebase/app-check` when using the modular API.
Starting in v25, the modular App Check helpers and types are exported from `@react-native-firebase/app-check` at the package root to better match the Firebase JS SDK. For example, import `initializeAppCheck`, `ReCaptchaEnterpriseProvider`, `AppCheck`, and `AppCheckTokenResult` directly from `@react-native-firebase/app-check` when using the modular API.

### Provider routing by platform

React Native Firebase exports the same App Check types on every platform, but runtime behaviour depends on where your app runs. Use this table when copying firebase-js-sdk examples or choosing a provider:

| `initializeAppCheck` provider | iOS / Android | Web (`Platform.OS === 'web'`) | Other / Hermes (macOS, Windows, …) |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- |
| `ReCaptchaEnterpriseProvider` | Maps to native `'recaptcha'`; site key is read from `FirebaseApp` options / native config (`recaptchaSiteKey` in `google-services.json` / `GoogleService-Info.plist`), not the constructor | Delegates to firebase-js-sdk `ReCaptchaEnterpriseProvider` | **Throws** — reCAPTCHA Enterprise requires a DOM environment |
| `ReCaptchaV3Provider` | **Throws** — native attestation uses the reCAPTCHA Enterprise factory, not v3 | Delegates to firebase-js-sdk `ReCaptchaV3Provider` | **Throws** — requires a DOM environment |
| `ReactNativeFirebaseAppCheckProvider` | Existing native `configureProvider` path | Uses `providerOptions.web` (`reCaptchaEnterprise`, `reCaptchaV3`, …) | **No DOM** — Hermes cannot use `providerOptions.web` reCAPTCHA options; `CustomProvider` path only where applicable |
| `CustomProvider` | **Throws** — not supported on native (Other-only); use `ReactNativeFirebaseAppCheckProvider` | firebase-js-sdk `CustomProvider` | firebase-js-sdk `CustomProvider` |
| **Omitted** (`provider` undefined) | **Throws** — native platforms require an explicit provider | Provider-less init via `app.options.recaptchaSiteKey` (firebase-js-sdk 12.15+) | **Throws** — provider-less init requires the web Enterprise bootstrap |

On iOS and Android, if you pass a constructor site key to `ReCaptchaEnterpriseProvider` and it differs from `app.options.recaptchaSiteKey`, React Native Firebase throws rather than silently using the wrong value.

### reCAPTCHA Enterprise on Web

Use the firebase-js-sdk-compatible `ReCaptchaEnterpriseProvider` class, or configure the cross-platform shim with `web: { provider: 'reCaptchaEnterprise', siteKey }`.

```javascript
import { getApp } from '@react-native-firebase/app';
import { initializeAppCheck, ReCaptchaEnterpriseProvider } from '@react-native-firebase/app-check';

const appCheck = await initializeAppCheck(getApp(), {
provider: new ReCaptchaEnterpriseProvider('your-recaptcha-enterprise-site-key'),
isTokenAutoRefreshEnabled: true,
});
```

See [Get started using App Check with reCAPTCHA Enterprise on Web](https://firebase.google.com/docs/app-check/web/recaptcha-enterprise-provider) for console setup and site-key creation.

### Provider-less initialization (Web only)

firebase-js-sdk 12.15+ allows omitting `provider` when the Firebase app has a `recaptchaSiteKey` in its options. React Native Firebase implements this on **Web only** — iOS and Android throw if `provider` is omitted.

```javascript
import { initializeApp, getApp } from '@react-native-firebase/app';
import { initializeAppCheck } from '@react-native-firebase/app-check';

// recaptchaSiteKey comes from Firebase project config / initializeApp options
initializeApp({
apiKey: '...',
appId: '...',
projectId: '...',
recaptchaSiteKey: 'your-recaptcha-enterprise-site-key',
});

const appCheck = await initializeAppCheck(getApp(), {
isTokenAutoRefreshEnabled: true,
});
```

If `recaptchaSiteKey` is missing, initialization throws `AppCheck provider is required`.

### reCAPTCHA Enterprise on iOS and Android

Mobile App Check uses the native `'recaptcha'` attestation provider. The site key is always sourced from `FirebaseApp` options — for the default native app, from your redownloaded config files; for JS-created secondary apps, from `initializeApp({ recaptchaSiteKey, ... })`.

**Option A — js-sdk-compatible class (maps to native `'recaptcha'`):**

```javascript
import { getApp } from '@react-native-firebase/app';
import { initializeAppCheck, ReCaptchaEnterpriseProvider } from '@react-native-firebase/app-check';

const appCheck = await initializeAppCheck(getApp(), {
provider: new ReCaptchaEnterpriseProvider('ignored-on-native'),
isTokenAutoRefreshEnabled: true,
});
```

**Option B — cross-platform shim with `'recaptcha'` on native:**

```javascript
import { getApp } from '@react-native-firebase/app';
import {
initializeAppCheck,
ReactNativeFirebaseAppCheckProvider,
} from '@react-native-firebase/app-check';

const rnfbProvider = new ReactNativeFirebaseAppCheckProvider();
rnfbProvider.configure({
android: {
provider: __DEV__ ? 'debug' : 'recaptcha',
},
apple: {
provider: __DEV__ ? 'debug' : 'recaptcha',
},
web: {
provider: 'reCaptchaEnterprise',
siteKey: 'your-recaptcha-enterprise-site-key',
},
});

const appCheck = await initializeAppCheck(getApp(), {
provider: rnfbProvider,
isTokenAutoRefreshEnabled: true,
});
```

> The `'recaptcha'` native provider is **iOS-only** among Apple platforms. Configuring it on macOS throws a clear error — use `CustomProvider` or another attestation provider on macOS.

Console setup and native SDK references: [Android `RecaptchaAppCheckProviderFactory`](https://firebase.google.com/docs/reference/android/com/google/firebase/appcheck/recaptcha/RecaptchaAppCheckProviderFactory), [iOS `FIRRecaptchaProvider`](https://firebase.google.com/docs/reference/ios/firebaseappcheck/api/reference/Classes/FIRRecaptchaProvider).

### Configure a Custom Provider

Expand All @@ -213,12 +321,14 @@ rnfbProvider.configure({
debugToken: 'some token you have configured for your project firebase web console',
},
web: {
provider: 'reCaptchaV3',
siteKey: 'unknown',
provider: 'reCaptchaEnterprise',
siteKey: 'your-recaptcha-enterprise-site-key',
},
});
```

> On Web you can also use `'reCaptchaV3'` for the legacy v3 provider. Native iOS and Android do not support `ReCaptchaV3Provider` — use `'recaptcha'` or `ReCaptchaEnterpriseProvider` instead.

### Install the Custom Provider

Once you have the custom provider configured, install it in app-check using the firebase-js-sdk compatible API, while saving the returned instance for usage:
Expand Down Expand Up @@ -253,8 +363,8 @@ const appCheck = await initializeAppCheck(getApp(), {
debugToken: 'some token you have configured for your project firebase web console',
},
web: {
provider: 'reCaptchaV3',
siteKey: 'unknown',
provider: 'reCaptchaEnterprise',
siteKey: 'your-recaptcha-enterprise-site-key',
},
},
},
Expand Down
35 changes: 35 additions & 0 deletions docs/app/json-config.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,38 @@ Add the [Config Schema](https://github.com/invertase/react-native-firebase/blob/
"$schema": "./node_modules/@react-native-firebase/app/firebase-schema.json"
}
```

## `recaptchaSiteKey` in Firebase app options

`recaptchaSiteKey` is a Firebase app option used by [App Check reCAPTCHA Enterprise](/app-check/usage#recaptcha-enterprise-on-ios-and-android) and Auth Enterprise flows. It is **not** configured in `firebase.json`; pass it through [`initializeApp`](/app/usage#initializing-secondary-apps) options or read it from native config files.

| App kind | Where `recaptchaSiteKey` comes from |
| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Native default app** (iOS / Android startup) | `google-services.json` / `GoogleService-Info.plist` processed before JS runs — **redownload these files** after enabling reCAPTCHA Enterprise in the Firebase console |
| **Native secondary app** (JS `initializeApp`) | JS options passed to `initializeApp({ recaptchaSiteKey, ... }, name)` — RNFB forwards the value to native `FirebaseOptions` / `FIROptions` |
| **Other / Web** (`Platform.OS === 'web'`) | `initializeApp({ recaptchaSiteKey, ... })` — required for [provider-less App Check init](/app-check/usage#provider-less-initialization-web-only) on Web |
| **Other / Hermes** (macOS, Windows, …) | Stored in JS app options; DOM reCAPTCHA providers still cannot run — use `CustomProvider` for App Check |

> **Native default-app caveat:** JavaScript cannot retroactively change `recaptchaSiteKey` on the default iOS/Android app after native startup. If App Check `'recaptcha'` or Auth Enterprise fails with a missing site key, redownload your native config files rather than setting the key only in JS.

```js
import { initializeApp } from '@react-native-firebase/app';

await initializeApp(
{
apiKey: '...',
appId: '...',
projectId: '...',
recaptchaSiteKey: 'your-recaptcha-enterprise-site-key',
},
{ name: 'SECONDARY_APP' },
);
```

On the default app, inspect `getApp().options.recaptchaSiteKey` after startup to confirm the native config file included the key.

### Expo and config plugins

When using Expo config plugins (`@react-native-firebase/app`, `@react-native-firebase/app-check`, and others), native Firebase config comes from the files referenced by [`expo.android.googleServicesFile`](https://docs.expo.io/versions/latest/config/app/#googleservicesfile-1) and [`expo.ios.googleServicesFile`](https://docs.expo.io/versions/latest/config/app/#googleservicesfile). Plugins copy these files into the native project at prebuild — they **do not** synthesize or inject `recaptchaSiteKey`.

After enabling the App Check reCAPTCHA provider in the Firebase console, redownload `google-services.json` and `GoogleService-Info.plist`, replace the copies in your project, and rebuild (for example `npx expo prebuild --clean` in managed workflows).
Loading
Loading