[firebase_app_check]: The new Firebase App Check token is not being updated in Firestore and other services that have App Check enforced. #12799
Labels
blocked: customer-response
Waiting for customer response, e.g. more information was requested.
platform: android
Issues / PRs which are specifically for Android.
platform: ios
Issues / PRs which are specifically for iOS.
plugin: app_check
Stale
Issue with no recent activity
type: bug
Something isn't working
Is there an existing issue for this?
Which plugins are affected?
App Check
Which platforms are affected?
Android, iOS
Disclaimers
I was able to reproduce the issue on Android, but a similar issue exists on iOS. I just have a hard time reproducing it locally (Crashlytics shows a lot of errors with get, update, set, and listen operations, resulting in permission denied for many users on both iOS and Android). 2% of our user base is impacted by this issue and similar ones related to App Check in one way or another.
This issue is reproduced in debug mode due to the nature of App Check and how difficult it is to reproduce it in a release build.
Scenario
Imagine the following scenario:
I installed the brand new app (the app requires Firebase Auth to proceed further).
I made a successful sign-in to the app (the app requires making a get call to Firestore to fetch the user to proceed further).
I tried to fetch the user, but I was hit with the error:
[cloud_firestore/permission-denied] The caller does not have permission to execute the specified operation.
I started digging and thinking, "Okay, maybe it's the security rules." However, the rules were simple:
allow read if auth != null
, and I had just made a successful sign-in before requesting data from Firestore, so that wasn't the issue. I began wondering what else could be causing the problem, and the only other reason it could fail was because of issues with the App Check token.I thought, "What if the App Check token wasn't fetched properly before making the call to Firestore? This is plausible, maybe it's some kind of race condition." So, I decided to ensure that the token was 100% valid by fetching it beforehand. It sounded like a good idea. I made a fetch and successfully fetched the token. I then made the call to Firestore, thinking that now everything should be rock solid, but no, it threw:
[cloud_firestore/permission-denied] The caller does not have permission to execute the specified operation.
I started thinking again, "WHAT? Okay, I know what it is. Firestore is not picking up the newly fetched token, but why not? Isn't it how it's supposed to work?" I wondered if there was a way to pass it manually to Firestore, but it seemed like there was no way.
So, here's where the issue lies: even if I ensure app attestation by fetching the token, Firestore, Cloud Functions, and Realtime Database will still fail because they won't pick up the new token until the app is restarted.
Yes, you heard me right. If I hot restart the app in debug mode, it picks up the token (which is equivalent to killing the app and opening it again), but this is not a great solution because no user will do this. They will just churn and delete the app, so this is a serious issue here.
Prerequisites
main.dart
as follows:Even though it's part of the story, authentication is not needed here to simplify the case.
Firestore
Make sure your Firestore rules look like this to get them out of the way:
Now, enforce App Check on your Firestore in Firebase.
App Setup
Have 2 buttons ready:
Steps to Reproduce
Build the app for Android in debug mode on a real Android device, making sure you activated App Check in
main.dart
. Copy the App Check debug token from the debug console, you will need it later.Press the 1st button (ensure that the call fails due to App Check).
Press the 2nd button (ensure it fails with a 403 error - app attestation failed).
Since this is debug mode, to emulate App Check behavior, take the debug token you copied in the 1st step and add it to App Check debug tokens for Android (in Firebase).
Once you've added the debug token, press the 2nd button again. The token should now be printed, indicating that you were attested by Firebase without issues.
Now, press the 1st button again, and it should throw
cloud_firestore/permission-denied
.Hot restart the app.
Press the 1st button again, it should fetch without issues.
The issue here is that it should have worked on the 6th step.
To test this multiple times, delete the app and reinstall it again so a new debug token can be generated.
Firebase Core version
2.30.1
Flutter Version
3.22.0
Relevant Log Output
No response
Flutter dependencies
Expand
Flutter dependencies
snippetAdditional context and comments
Maybe related to:
The text was updated successfully, but these errors were encountered: