invertase / react-native-firebase

πŸ”₯ A well-tested feature-rich modular Firebase implementation for React Native. Supports both iOS & Android platforms for all Firebase services.
https://rnfirebase.io
Other
11.7k stars 2.21k forks source link

[πŸ›] iOS Bug auth/network-request-failed when user has stable wifi #4934

Closed watadarkstar closed 3 years ago

watadarkstar commented 3 years ago

Issue

We have a ton of sentry logs indicating that getIdToken is failing with auth/network-request-failed:

 let token
  try {
    token = await currentUser.getIdToken()
  } catch (e) {
    logError(e, 'getConnectionParams: getIdToken failed')
    throw e
  }

But you can see in the provided screenshot that the user clearly has a stable wifi connection:

Screen Shot 2021-02-19 at 2 57 46 PM

Project Files

Javascript

Click To Expand

#### `package.json`: ```json "dependencies": { "@apollo/client": "^3.2.9", "@eva-design/eva": "^2.0.0", "@react-native-community/async-storage": "^1.11.0", "@react-native-community/cameraroll": "^4.0.0", "@react-native-community/clipboard": "^1.2.3", "@react-native-community/masked-view": "^0.1.10", "@react-native-community/netinfo": "^5.9.10", "@react-native-community/push-notification-ios": "^1.7.1", "@react-native-firebase/analytics": "^7.6.7", "@react-native-firebase/app": "^8.4.5", "@react-native-firebase/auth": "^9.3.0", "@react-native-firebase/dynamic-links": "^7.5.9", "@react-native-firebase/functions": "^7.4.8", "@react-native-firebase/messaging": "^7.9.0", "@react-native-firebase/storage": "^7.4.9", "@react-navigation/bottom-tabs": "^5.11.2", "@react-navigation/compat": "^5.3.10", "@react-navigation/material-top-tabs": "^5.3.10", "@react-navigation/native": "^5.8.10", "@react-navigation/stack": "^5.12.8", "@segment/analytics-react-native": "1.4.1", "@segment/analytics-react-native-amplitude": "1.4.1", "@sentry/react-native": "^2.1.0", "@ui-kitten/components": "^5.0.0", "@welldone-software/why-did-you-render": "^4.2.6", "apollo3-cache-persist": "^0.9.1", "dayjs": "^1.10.4", "graphql": "^15.4.0", "libphonenumber-js": "^1.9.9", "lodash": "^4.17.20", "patch-package": "^6.2.2", "postinstall-postinstall": "^2.1.0", "prop-types": "^15.7.2", "react": "16.13.1", "react-native": "0.63.4", "react-native-actionsheet": "^2.4.2", "react-native-bootsplash": "^2.2.5", "react-native-check-notification-enable": "^1.3.0", "react-native-code-push": "^6.3.0", "react-native-config-reader": "^4.1.0", "react-native-console-time-polyfill": "^1.2.1", "react-native-device-info": "^7.2.1", "react-native-fast-image": "^8.3.4", "react-native-flipper": "^0.64.0", "react-native-gesture-handler": "^1.9.0", "react-native-gifted-chat": "^0.16.3", "react-native-haptic-feedback": "^1.9.0", "react-native-image-crop-picker": "^0.35.3", "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^3.1.2", "react-native-image-resizer": "^1.3.0", "react-native-image-view": "^2.1.9", "react-native-iphone-x-helper": "^1.2.1", "react-native-modal": "^11.6.1", "react-native-parsed-text": "^0.0.22", "react-native-permissions": "^2.0.8", "react-native-push-notification": "^3.1.9", "react-native-reanimated": "^1.4.0", "react-native-root-siblings": "^4.0.6", "react-native-safe-area-context": "^3.1.8", "react-native-screens": "^2.9.0", "react-native-svg": "^9.13.3", "react-native-swiper": "^1.6.0-rc.3", "react-native-tab-view": "^2.15.2", "react-redux": "^7.2.2", "redux": "^4.0.4", "redux-flipper": "^1.4.2", "redux-persist": "^6.0.0", "redux-thunk": "^2.3.0", "rn-fetch-blob": "^0.12.0", "subscriptions-transport-ws": "^0.9.18", "uuid": "^3.3.2" }, "devDependencies": { "@babel/core": "^7.8.4", "@babel/runtime": "^7.8.4", "@coorpacademy/eslint-plugin-coorpacademy": "^10.2.0", "@expo/spawn-async": "^1.5.0", "@graphql-codegen/cli": "^1.19.4", "@graphql-codegen/introspection": "^1.18.1", "@graphql-codegen/typescript": "^1.19.0", "@graphql-codegen/typescript-operations": "^1.17.12", "@graphql-codegen/typescript-react-apollo": "^2.2.1", "@react-native-community/eslint-config": "^2.0.0", "@testing-library/jest-native": "^3.4.3", "@testing-library/react-native": "^7.1.0", "@types/jest": "^26.0.1", "@types/lodash": "^4.14.165", "@types/react": "^16.9.35", "@types/react-native": "^0.63.46", "@types/react-native-push-notification": "^3.0.9", "@types/react-redux": "^7.1.11", "@types/react-test-renderer": "^16.9.2", "babel-jest": "^26.6.3", "babel-plugin-module-resolver": "^4.0.0", "babel-plugin-transform-remove-console": "^6.9.4", "detox": "^17.3.6", "dotenv": "^8.2.0", "eslint": "^7.7.0", "eslint-plugin-prettier": "^3.3.1", "eslint-plugin-react-perf": "^3.2.4", "flipper-plugin-react-native-performance": "^0.5.0", "husky": ">=4", "imageoptim-cli": "^3.0.2", "jest": "^25.0.0", "jest-circus": "^26.0.1", "lint-staged": ">=10", "metro-react-native-babel-preset": "^0.59.0", "prettier": "^2.0.5", "react-native-svg-transformer": "^0.14.3", "react-test-renderer": "16.13.1", "reactotron-react-native": "^5.0.0", "typescript": "^4.0.5" },``` #### `firebase.json` for react-native-firebase v6: ```json # N/A ```

iOS

Click To Expand

``` Family | iOS Model | iPhone 11 (N104AP) ``` #### `ios/Podfile`: - [ ] I'm not using Pods - [x] I'm using Pods and my Podfile looks like: ```ruby # Intermittent CDN issues #10078 # https://github.com/CocoaPods/CocoaPods/issues/10078 # Remove this in a few days time. source 'https://cocoapods-cdn.netlify.app/' require_relative '../node_modules/react-native/scripts/react_native_pods' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' platform :ios, '10.0' def shared_pods config = use_native_modules! use_react_native!(:path => config["reactNativePath"]) # Pods for Foo permissions_path = '../node_modules/react-native-permissions/ios' pod 'Permission-PhotoLibrary', :path => "#{permissions_path}/PhotoLibrary.podspec" pod 'Permission-Microphone', :path => "#{permissions_path}/Microphone.podspec" pod 'Permission-Notifications', :path => "#{permissions_path}/Notifications.podspec" pod 'Permission-Camera', :path => "#{permissions_path}/Camera.podspec" pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info' pod 'RNReactNativeHapticFeedback', :path => '../node_modules/react-native-haptic-feedback' pod 'flipper-plugin-react-native-performance', :path => "../node_modules/flipper-plugin-react-native-performance/ios" # Pod install can't find Sentry 6.0.9 without the following line pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git', :tag => '6.0.9' end # Enables Flipper. # # Note that if you have use_frameworks! enabled, Flipper will not work and # you should disable these next few lines. use_flipper!(configurations: ['Debug','DevDebug']) post_install do |installer| flipper_post_install(installer) end def firebase_pods pod 'Firebase/Messaging' end project 'Foo', 'Debug' => :debug, 'DevDebug' => :debug, 'Release' => :release target 'Foo' do shared_pods firebase_pods end target 'Foo-staging' do shared_pods firebase_pods end target 'Foo-tests' do shared_pods firebase_pods end target 'Foo-tvOS' do # Pods for Foo-tvOS target 'Foo-tvOSTests' do inherit! :complete # Pods for testing end end ``` #### `AppDelegate.m`: ```objc #import "AppDelegate.h" #import #import #import #import #import #import #import #import #import "RNFBMessagingModule.h" #import "RNBootSplash.h" @import Firebase; #if RCT_DEV #import #endif #if DEBUG #ifdef FB_SONARKIT_ENABLED #import #endif #endif #ifdef FB_SONARKIT_ENABLED #import #import #import #import #import #import static void InitializeFlipper(UIApplication *application) { FlipperClient *client = [FlipperClient sharedClient]; SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults]; [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]]; [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]]; [client addPlugin:[FlipperKitReactPlugin new]]; [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]]; [client addPlugin: [FlipperReactPerformancePlugin sharedInstance]]; [client start]; } #endif @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { #ifdef FB_SONARKIT_ENABLED InitializeFlipper(application); #endif if ([FIRApp defaultApp] == nil) { [FIRApp configure]; } RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; #if DEBUG #ifdef FB_SONARKIT_ENABLED [[FlipperReactPerformancePlugin sharedInstance] setBridge:bridge]; #endif #endif #if RCT_DEV [bridge moduleForClass:[RCTDevLoadingView class]]; #endif NSDictionary *appProperties = [RNFBMessagingModule addCustomPropsToUserProps:nil withLaunchOptions:launchOptions]; RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"Foo" initialProperties:appProperties]; rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; // Define UNUserNotificationCenter UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; center.delegate = self; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIViewController *rootViewController = [UIViewController new]; rootViewController.view = rootView; self.window.rootViewController = rootViewController; [self.window makeKeyAndVisible]; [RNBootSplash initWithStoryboard:@"BootSplash" rootView:rootView]; return YES; } //Called when a notification is delivered to a foreground app. -(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler { completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge); } // Required to register for notifications - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { [RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings]; } // Required for the register event. - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { [RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; } // Required for the notification event. You must call the completion handler after handling the remote notification. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; } // Required for the registrationError event. - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { [RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error]; } // IOS 10+ Required for localNotification event - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { [RNCPushNotificationIOS didReceiveNotificationResponse:response]; completionHandler(); } // IOS 4-10 Required for the localNotification event. - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { [RNCPushNotificationIOS didReceiveLocalNotification:notification]; } - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; #else return [CodePush bundleURL]; #endif } - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { return [RCTLinkingManager application:application openURL:url sourceApplication:sourceApplication annotation:annotation]; } // Only if your app is using [Universal Links](https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html). - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler { return [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler]; } @end ```


Android (Not a bug on Android)

Click To Expand

#### Have you converted to AndroidX? - [ ] my application is an AndroidX application? - [ ] I am using `android/gradle.settings` `jetifier=true` for Android compatibility? - [ ] I am using the NPM package `jetifier` for react-native compatibility? #### `android/build.gradle`: ```groovy // N/A ``` #### `android/app/build.gradle`: ```groovy // N/A ``` #### `android/settings.gradle`: ```groovy // N/A ``` #### `MainApplication.java`: ```java // N/A ``` #### `AndroidManifest.xml`: ```xml ```


Environment

Click To Expand

**`react-native info` output:** ``` info Fetching system and libraries information... System: OS: macOS 10.15.7 CPU: (8) x64 Intel(R) Core(TM) i5-8257U CPU @ 1.40GHz Memory: 278.34 MB / 8.00 GB Shell: 3.1.2 - /usr/local/bin/fish Binaries: Node: 14.7.0 - ~/.nvm/versions/node/v14.7.0/bin/node Yarn: 1.22.4 - ~/.yarn/bin/yarn npm: 6.14.7 - ~/.nvm/versions/node/v14.7.0/bin/npm Watchman: 4.9.0 - /opt/local/bin/watchman Managers: CocoaPods: 1.10.0 - /usr/local/bin/pod SDKs: iOS SDK: Platforms: iOS 14.1, DriverKit 19.0, macOS 10.15, tvOS 14.0, watchOS 7.0 Android SDK: API Levels: 28, 29, 30 Build Tools: 28.0.3, 29.0.2, 30.0.2 System Images: android-29 | Google APIs Intel x86 Atom, android-30 | Google APIs Intel x86 Atom Android NDK: Not Found IDEs: Android Studio: 4.0 AI-193.6911.18.40.6626763 Xcode: 12.1/12A7403 - /usr/bin/xcodebuild Languages: Java: 1.8.0_261 - /usr/bin/javac Python: 2.7.16 - /usr/bin/python npmPackages: @react-native-community/cli: Not Found react: 16.13.1 => 16.13.1 react-native: 0.63.4 => 0.63.4 react-native-macos: Not Found npmGlobalPackages: *react-native*: Not Found ``` - **Platform that you're experiencing the issue on**: - [x] iOS - [ ] Android - [x] **iOS** but have not tested behavior on Android - [ ] **Android** but have not tested behavior on iOS - [ ] Both - **`react-native-firebase` version you're using that has this issue:** - `e.g. 5.4.3` - **`Firebase` module(s) you're using that has the issue:** - `e.g. Instance ID` - **Are you using `TypeScript`?** - `Y/N` & `VERSION`


mikehardy commented 3 years ago

I'm 99% sure this is going to be in firebase-ios-sdk - strongly recommend getting a reproduction together at that level based on their quickstart https://github.com/firebase/quickstart-ios/tree/master/authentication and/or searching their issues list

watadarkstar commented 3 years ago

@mikehardy What does the auth/network-request-failed code mean? I assume it means the user's network is down but is that always true or does it represent other things as well? I feel like this user had a stable network connection based on the NetInfo log shown below and the Sentry timestamps.

Error:

[auth/network-request-failed] A network error has occurred, please try again.

NetInfo:

networkState.type = wifi
    networkState.isInternetReachable = null
    networkState.isConnected = true

Also the fact that the error occurred and sentry received the error immediately after with a few seconds of latency:

Screen Shot 2021-02-19 at 5 49 30 PM

You guys have this error in this codebase but I'm not sure what it signifies: https://github.com/invertase/react-native-firebase/blob/02132ce322b0f1d06b11ddc7f66ab919ab2c1b1f/packages/auth/ios/RNFBAuth/RNFBAuthModule.h#L42

The ios sdk has this: https://github.com/firebase/firebase-ios-sdk/blob/289e093f89f5dd4ba44377cf57dbf6062e8354c3/FirebaseAuth/Sources/Utilities/FIRAuthInternalErrors.h#L59-L61

But this error happens to users with a good Wifi connection so I'm stumped as to why they are getting this error.

I'll post in that repo but want to get your input :)

mikehardy commented 3 years ago

Glad you grep'ed through the codebase(s), that was actually my next thought. The error message descriptions themselves are "as expected" I'd say but that's not really much help.

It would definitely help to see when that constant from FIRAuthInternalError.h is used to see what possible scenarios could generate it

As a thought exercise, I wonder if there is some confusion on when things are attempted, vs when they return, vs when they are reported. By which I mean, perhaps the wall clock way things are happening is more like:

I have no actual evidence to base that scenario / hypothesis on but if you are able to reproduce this (maybe you have some friendly beta tester that gets it all the time?) you could put a bunch more logging / instrumentation in at each step - taking care to log time the event happened vs time it was received on server) and perhaps learn something

Other than that hand-wavy thought I do not have any direct experience or other ideas on this one at the moment, sorry

mikehardy commented 3 years ago

Cross-linking as this should be part of a VPN sweep #4978 / #4998

stale[bot] commented 3 years ago

Hello πŸ‘‹, to help manage issues we automatically close stale issues. This issue has been automatically marked as stale because it has not had activity for quite some time. Has this issue been fixed, or does it still require the community's attention?

This issue will be closed in 15 days if no further activity occurs. Thank you for your contributions.

stale[bot] commented 3 years ago

Closing this issue after a prolonged period of inactivity. If this is still present in the latest release, please feel free to create a new issue with up-to-date information.

perrosnk commented 3 years ago

I am having the same issue on iOS and I am not using a VPN. @watadarkstar Have you found any solution?

traviswimer commented 3 years ago

I wanted to share my specific scenario. I am getting this error, but only when attempting to use the Firebase Authentication Emulator.

In production, I am not experiencing any issues like this. Hopefully this might provide a little insight into what might be the root cause. I'm experiencing this issue both with and without a VPN running.

This bug is unfortunate, because it also means the functions emulator is completely useless to me, since my functions also depend on authentication.

mikehardy commented 3 years ago

@traviswimer that is still unexpected, we are certainly using the auth emulator in our e2e test harness - #4552 - and have been for nearly a year :thinking:

https://github.com/invertase/react-native-firebase/blob/aabb07595f6c8b4e86f20f3d6ebfcb7e91a1819a/tests/app.js#L51

traviswimer commented 3 years ago

@mikehardy Thanks for pointing me in the direction of the e2e tests. This helped me eventually figure out the solution to my problem.

In my last comment, I forgot to clarify that I am experience this while using firebase.auth().signInWithCredential(), not getIdToken(). I was getting the same A network error has occurred, please try again. error when the network appears to be fine though, so I imagine the problem is at least related.

Anyway, I figured out that this error only occurs when I am using a real iOS device, and it seems to work fine on the iPhone simulator.

The problem is that passing a localhost URL to userEmulator() will not work. You instead need to pass the actual IP address for the machine that is running the emulators. Eventually I found another issue posted on this repo with a nice solution to avoid hard-coding the IP address: https://github.com/invertase/react-native-firebase/issues/4810#issuecomment-764774413

I'm not entirely certain why, but I also needed to update firebase.json to use 0.0.0.0 as the host:

{
    "emulators": {
        "auth": {
            "host": "0.0.0.0",
            "port": 9099
        }
    }
}

So, I don't think this issue is really a bug, but it's also not ideal/intuitive. I think the reason I was so confused by this error is that all my other network requests were working fine and were using localhost as the URL.

I guess I assumed that react-native was doing some kind of magic to automatically make localhost work, but apparently that functionality is coming from the individual libraries.

Also, I am using react-native-debugger to view network requests, and the requests to the Auth emulator were not showing up. This led to my false assumption that the error was occurring prior to even making any actual network request.

So, without having much knowledge of the inner-workings of react-native-firebase, my thoughts for improvements would be:

  1. Support real iOS devices. Possibly by updating the useEmulator() method to convert localhost to an IP address.
  2. Support network request debugging. (I don't know what the cause of this problem is)
  3. Add documentation about using "host": "0.0.0.0", although I'm not entirely certain why this is necessary. It's possible this is specific to my local environment.

Do you think it would be worthwhile for me to open feature requests for these ideas?

mikehardy commented 3 years ago

We already do re-mapping for DX improvement on the android side:

https://github.com/invertase/react-native-firebase/blob/aabb07595f6c8b4e86f20f3d6ebfcb7e91a1819a/packages/auth/lib/index.js#L362-L377

Seems like for the iOS side this could be considered a natural extension - as long as it was boldly logged (to avoid the confusion, I can't think of a better way?) something like this could go through, sure

SKempin commented 1 month ago

@traviswimer I'm currently experiencing the same issue - unable to use the emulator on a real iOS device, but can access it fine with iOS simulator. I'm using auth().signInWithEmailAndPassword

Constantly getting this error with a real device:

Error: [auth/network-request-failed] A network error has occurred, please try again.

I've updated firebase.json config to add the host to auth:

{
  "emulators": {
    "auth": {
      "host": "0.0.0.0",
      "port": 9099
    },
    "firestore": {
      "port": 8080
    },
    "ui": {
      "enabled": true
    },
    "singleProjectMode": true
  }
}

And these addresses run the emulator fine in iOS simulator:

  firestore().useEmulator('127.0.0.1', 8080);
  auth().useEmulator('http://127.0.0.1:9099');
  console.log('Firestore emulators running!');

I updated the IP to my hostname but that still results in the same network error.

  firestore().useEmulator('127.0.0.1', 8080);
auth().useEmulator('http://192.168.86.24:9099');
console.log('Firestore emulators running!');

Any ideas what I may be missing? Thanks

SKempin commented 2 weeks ago

Have submitted a separate issue for this https://github.com/invertase/react-native-firebase/issues/8060