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.69k stars 2.21k forks source link

[🐛] revokeToken API does not work #7273

Closed WinstonNau closed 1 year ago

WinstonNau commented 1 year ago

Issue

I am using Apple Sign-In in my Application. Since Apple requires all App Store Apps, which create accounts to be able to delete them as well, I added a delete feature. Additionally, Apple requires to revoke the Apple Authentication Token from the App, where the revokeToken API comes in. But the issue is, it does not work. It neither reauthenticates me to delete the user from the firebase, nor does it remove the token from my Apple ID.

The warning which gets thrown is: [auth/invalid-credential] The supplied auth credential is malformed or has expired. and I do not know what I did wrong since I copied the documentation 1-to-1. I would really appreciate some help, since this is a time sensitive matter as well.

You can find the implemented code here:

if (currentUser.providerData[0].providerId === 'apple.com') {
      currentUser
        .getIdToken(true)
        .then(token => {
          deleteAccount(token, async () => {
            await revokeSignInWithAppleToken();
            currentUser
              .delete()
              .then(() => {
                setLoading(false);
                Snackbar.show({
                  text: 'Account deleted!',
                  duration: Snackbar.LENGTH_SHORT,
                });
                navigation.dispatch(StackActions.replace('Login'));
              })
              .catch(() => {
                setLoading(false);
                Snackbar.show({
                  text: 'Unable to delete account!',
                  duration: Snackbar.LENGTH_SHORT,
                });
              });
          });
        })
        .catch(() => {
          setLoading(false);
          Snackbar.show({
            text: 'Unable to get token!',
            duration: Snackbar.LENGTH_SHORT,
          });
        });
    }

The deleteAccount() function is an API call to delete user information from the database. This works without issues and is not the root of the problem.

The revokeSignInWithAppleToken() function is the same as in the documentation, but I will put it here as well, just for an overview:

async function revokeSignInWithAppleToken() {
  // Get an authorizationCode from Apple
  const {authorizationCode} = await appleAuth.performRequest({
    requestedOperation: appleAuth.Operation.REFRESH,
  });

  // Ensure Apple returned an authorizationCode
  if (!authorizationCode) {
    throw new Error('Apple Revocation failed - no authorizationCode returned');
  }

  // Revoke the token
  return auth().revokeToken(authorizationCode);
}

Project Files

Javascript

Click To Expand

#### `package.json`: ```json { "name": "SomeName", "version": "0.0.2", "private": true, "scripts": { "android": "react-native run-android", "ios": "react-native run-ios", "lint": "eslint .", "start": "react-native start", "test": "jest" }, "dependencies": { "@invertase/react-native-apple-authentication": "^2.2.2", "@react-native-async-storage/async-storage": "^1.19.1", "@react-native-community/checkbox": "^0.5.16", "@react-native-community/geolocation": "^3.0.6", "@react-native-firebase/app": "^18.3.0", "@react-native-firebase/auth": "^18.3.0", "@react-native-firebase/storage": "^18.3.0", "@react-native-google-signin/google-signin": "^10.0.1", "@react-navigation/bottom-tabs": "^6.5.7", "@react-navigation/native": "^6.1.6", "@react-navigation/native-stack": "^6.9.12", "@rneui/base": "^4.0.0-rc.7", "@rneui/themed": "^4.0.0-rc.7", "@stripe/stripe-react-native": "^0.28.0", "react": "18.2.0", "react-hook-form": "^7.43.9", "react-native": "0.71.8", "react-native-actions-sheet": "^0.8.29", "react-native-date-picker": "^4.2.13", "react-native-dropdown-picker": "^5.4.6", "react-native-fbsdk-next": "^11.2.1", "react-native-image-picker": "^5.3.1", "react-native-linear-gradient": "^2.6.2", "react-native-maps": "^1.7.1", "react-native-open-maps": "^0.4.2", "react-native-qrcode-svg": "^6.2.0", "react-native-reanimated": "2.17.0", "react-native-safe-area-context": "^4.5.3", "react-native-screens": "^3.20.0", "react-native-select-dropdown": "^3.3.4", "react-native-snackbar": "^2.6.2", "react-native-svg": "^13.9.0", "react-native-vector-icons": "^9.2.0", "react-native-vision-camera": "^2.15.4", "vision-camera-code-scanner": "^0.2.0" }, "devDependencies": { "@babel/core": "^7.20.0", "@babel/preset-env": "^7.20.0", "@babel/runtime": "^7.20.0", "@react-native-community/eslint-config": "^3.2.0", "@tsconfig/react-native": "^2.0.2", "@types/jest": "^29.2.1", "@types/react": "^18.0.24", "@types/react-test-renderer": "^18.0.0", "babel-jest": "^29.2.1", "eslint": "^8.19.0", "jest": "^29.2.1", "metro-react-native-babel-preset": "0.73.9", "prettier": "^2.4.1", "react-test-renderer": "18.2.0", "typescript": "4.8.4" }, "jest": { "preset": "react-native" } } ``` #### `firebase.json` for react-native-firebase v6: ```json # N/A ```

iOS

Click To Expand

#### `ios/Podfile`: - [ ] I'm not using Pods - [x] I'm using Pods and my Podfile looks like: ```ruby require_relative '../node_modules/react-native/scripts/react_native_pods' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' platform :ios, 13.0 prepare_react_native_project! # If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. # because `react-native-flipper` depends on (FlipperKit,...) that will be excluded # # To fix this you can also exclude `react-native-flipper` using a `react-native.config.js` # ```js # module.exports = { # dependencies: { # ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), # ``` flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled linkage = ENV['USE_FRAMEWORKS'] if linkage != nil Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green use_frameworks! :linkage => static end target 'WgwApp' do config = use_native_modules! use_frameworks! :linkage => :static $RNFirebaseAsStaticFramework = true # Flags change depending on the env values. flags = get_default_flags() pre_install do |installer| installer.pod_targets.each do |pod| if pod.name.eql?('RNReanimated') || pod.name.eql?('vision-camera-code-scanner') || pod.name.eql?('VisionCamera') def pod.build_type Pod::BuildType.static_library end end end end use_react_native!( :path => config[:reactNativePath], # Hermes is now enabled by default. Disable by setting this flag to false. # Upcoming versions of React Native may rely on get_default_flags(), but # we make it explicit here to aid in the React Native upgrade process. :hermes_enabled => flags[:hermes_enabled], :fabric_enabled => flags[:fabric_enabled], # Enables Flipper. # # Note that if you have use_frameworks! enabled, Flipper will not work and # you should disable the next line. # :flipper_configuration => flipper_config, # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/.." ) target 'WgwAppTests' do inherit! :complete # Pods for testing end post_install do |installer| react_native_post_install( installer, # Set `mac_catalyst_enabled` to `true` in order to apply patches # necessary for Mac Catalyst builds :mac_catalyst_enabled => false ) __apply_Xcode_12_5_M1_post_install_workaround(installer) end end ``` #### `AppDelegate.m`: ```objc #import "AppDelegate.h" #import #import #import #import #import @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [FIRApp configure]; [[FBSDKApplicationDelegate sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions]; self.moduleName = @"WgwApp"; // You can add your custom initial props in the dictionary below. // They will be passed down to the ViewController used by React Native. self.initialProps = @{}; return [super application:application didFinishLaunchingWithOptions:launchOptions]; } - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; #else return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif } /// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. /// /// @see: https://reactjs.org/blog/2022/03/29/react-v18.html /// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). /// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`. - (BOOL)concurrentRootEnabled { return true; } - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { return ([[FBSDKApplicationDelegate sharedInstance]application:app openURL:url options:options] || [RCTLinkingManager application:app openURL:url options:options]) || [RNGoogleSignin application:app openURL:url options:options]; } @end ```


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:** ``` System: OS: macOS 13.4 CPU: (10) arm64 Apple M2 Pro Memory: 56.67 MB / 16.00 GB Shell: 5.9 - /bin/zsh Binaries: Node: 18.17.0 - /usr/local/bin/node Yarn: 1.22.19 - ~/.yarn/bin/yarn npm: 9.6.7 - /usr/local/bin/npm Watchman: Not Found Managers: CocoaPods: 1.12.1 - /usr/local/bin/pod SDKs: iOS SDK: Platforms: DriverKit 22.4, iOS 16.4, macOS 13.3, tvOS 16.4, watchOS 9.4 Android SDK: Not Found IDEs: Android Studio: 2022.3 AI-223.8836.35.2231.10406996 Xcode: 14.3.1/14E300c - /usr/bin/xcodebuild Languages: Java: 16.0.2 - /usr/bin/javac npmPackages: @react-native-community/cli: Not Found react: 18.2.0 => 18.2.0 react-native: 0.71.8 => 0.71.8 react-native-macos: Not Found npmGlobalPackages: *react-native*: Not Found ``` - **Platform that you're experiencing the issue on**: - [X] iOS - [ ] Android - [ ] **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:** - `18.3.0` - **`Firebase` module(s) you're using that has the issue:** - `@react-native-firebase/app` and `@react-native-firebase/auth` - **Are you using `TypeScript`?** - `Y` & `4.8.4`


WinstonNau commented 1 year ago

The solution lies in this GitHub Pull Request: https://github.com/invertase/react-native-firebase/pull/7239 Make sure to read the "Test Plan" part and follow the instructions on the official react native firebase iOS documentation, specifically creating a private key with Apple and filling out the Services ID and OAuth code flow portions on Firebase correctly.

And for the Admins, please add the instruction, which were also noted in the PR, to the official firebase react native social auth documentation to prevent confusion and long hours trying to fix this issue.

efstathiosntonas commented 1 year ago

@WinstonNau I experienced the same issue, everything is done according to docs specified on the Test Plan above. What did the trick for me was:

import auth from "@react-native-firebase/auth";

  if (currentUser().providerData[0].providerId === "apple.com") {
      await auth().currentUser?.getIdToken?.(true); <---- added this, if it's not there malformed credentials error is thrown
      await revokeSignInWithAppleToken();
    }

You're refreshing the user's token on your code example above, just wanted to point this out.

kockar96 commented 1 year ago

Follow this: https://medium.com/swlh/sign-in-with-apple-for-web-using-firebase-auth-js-b13eb7a0e104

bvanderdrift commented 10 months ago

Anyone still banging their head against the wall: if you're using an iOS Simulator try 'Device' -> 'Erase all content and settings' and re-install the app.

We in the past have changed our app's bundle ID, and I think somehow the iOS Simulator still had some corrupted auth state from the old bundle ID which it was matching to the current bundle ID.

Motter10 commented 9 months ago

I had the same problem, my solution was in the firebase console, in the authentication part and in Apple activation, add the OAuth code flow configuration (Apple Team ID, key id, and private key, all generated from the tutorial: https://firebase.google.com/docs/auth/ios/apple#configure_sign_in_with_apple )