Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[🐛] Android: App Check provider factory is only installed from JS, so Firestore/Storage requests go out unattested

Closed
#9,227 7 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
42/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
java, react-native
Domain
mobile, security

Research direction

Start with ReactNativeFirebaseAppCheckModule.java and NativeRNFBTurboAppCheck.java at the configureProvider and activate entry points, then trace Android initialization around FirebaseInitProvider. Reproduce the Firestore and Storage rule-gated requests described in the issue and verify the provider is registered before FirebaseApp initialization. Done means those requests carry a valid App Check token while the existing Functions behavior remains intact.

Written by the indexing model from the issue text.

Description

blocked: customer-response platform: android plugin: app-check Stale type: bug

Issue

On Android, installAppCheckProviderFactory(...) is only reachable from JavaScript. Firebase requires it to be registered before FirebaseApp is configured, and on Android FirebaseApp is auto-initialized by FirebaseInitProvider (a ContentProvider) before any JS runs. The result: Firestore and Storage requests are sent without an App Check token, and any rule using request.app != null rejects them. Cloud Functions is unaffected.

This is not the iOS debug-provider issue fixed by #9166. That PR states the requirement precisely, though:

Firebase requires the provider factory to be registered before FirebaseApp.configure(), which runs before JS.

On Android there is currently no way for an app to satisfy that, because the only install path is a bridge method.

Where

Both call sites are JS-invoked, and the structure is unchanged on main:

  • v23.8.6 — ReactNativeFirebaseAppCheckModule.java:134 (configureProvider), :168 (activate)
  • main — NativeRNFBTurboAppCheck.java:148 (configureProvider), :180 (activate)

There is no ContentProvider, Initializer, Application hook, or static block that installs the factory at process start.

Why Functions works but Firestore/Storage don't

Functions requests an App Check token per invocation, at call time, so a factory installed later is still picked up. Firestore and Storage capture App Check provider state when the client/stream is first created — which happens before JS has installed the factory.

Reproduction

  1. Android app, App Check debug provider, debug token registered in the Firebase Console.
  2. await initializeAppCheck({ provider, isTokenAutoRefreshEnabled: true }) early in app start — before any Firestore or Storage call.
  3. Set a Firestore rule requiring request.app != null, and a Storage rule likewise.
  4. Read a document and upload a file.

Observed:

firestore: [firestore/permission-denied] The caller does not have permission to execute the specified operation.
storage:   [storage/unauthorized] User is not authorized to perform the desired action.

A callable Cloud Function in the same session, in the same app, succeeds with {"auth":"VALID","app":"VALID"}.

The token is genuinely available — it just isn't sent

This is the part that rules out a configuration mistake:

  • RNFBAppCheck: configureProvider - [DEFAULT]/debug/null
  • RNFBAppCheck: Provider::getToken - delegating to native provider
  • The App Check token cache (shared_prefs/com.google.firebase.appcheck.store.*.xml) is rewritten during the failing run, which only happens after a successful token exchange with the backend.
  • App data was never cleared, so the debug secret is the one already allowlisted in the Console.

So a valid token was minted and cached before the failing requests, and Functions demonstrably transmits it. Firestore and Storage do not.

Control

Same APK, same session, same token. The only variable changed is the rule's gate:

Rules Firestore read Storage upload
hasAppCheck() → request.app != null hangs, never returns [storage/unauthorized]
same file, gate body replaced with return true succeeds succeeds

Every other condition in the Storage rule (uid-matches-path, size cap, content type, filename pattern, ban check) is satisfied by the exact request the gate rejected.

Also worth fixing: the Firestore failure is silent

A rules rejection on a Firestore transaction does not reject the promise — the SDK retries indefinitely. With no error surfaced, the call simply never settles. On a cold start this presents as an app hanging on its loading state with nothing at all in logcat, which makes it very hard to attribute. A snapshot listener with an error callback does report permission-denied correctly; it's the transaction path that's silent.

Environment

@react-native-firebase/app          23.8.6
@react-native-firebase/app-check    23.8.6
@react-native-firebase/firestore    23.8.6
@react-native-firebase/storage      23.8.6
@react-native-firebase/functions    23.8.6
react-native                        0.76.9
expo                                52.0.0
newArchEnabled                      false
Android                             API 34 emulator (Play Store image)

Source citations above are against main, so this does not appear to be fixed in 26.x.

Suggested direction

Expose a native-side registration path that runs before FirebaseApp initialization — e.g. an Initializer/ContentProvider ordered ahead of FirebaseInitProvider, or a documented Application.onCreate() hook — so the factory can be installed with the provider choice supplied by build config rather than by JS. Alternatively, document that Android cannot support rule-level App Check for Firestore/Storage today, since the current docs imply otherwise.

Dominant language
TypeScript
Stars
12.3k
Forks
2.3k
Avg merge
7d 4h
Merged PRs (30d)
20

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from invertase/react-native-firebase

All issues in invertase/react-native-firebase

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.