Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[🐛] auth.PhoneAuthProvider.credential is undefined on IOS release build #8444

Open
2 of 10 tasks
tux2nicolae opened this issue Apr 4, 2025 · 5 comments
Open
2 of 10 tasks

Comments

@tux2nicolae
Copy link

tux2nicolae commented Apr 4, 2025

Issue

Just noticed our phone authentication does not work anymore (only on release builds), it seems very very similar to this issue

#8315

More specifically when calling auth.PhoneAuthProvider.credential

Image

Project Files

Javascript

Click To Expand

import auth, {
  FirebaseAuthTypes,
  getAuth,
  signInWithCredential,
  verifyPhoneNumber,
} from '@react-native-firebase/auth';
import React, {useCallback} from 'react';
import {UNKNOWN_ERROR} from '../../shared/utils/translateError';

const AUTOVERIFY_TIME = 10;
const RESEND_DELAY = 30;

export const useFirebasePhoneAuth = (phoneNumber: string) => {
  const [canResend, setCanResend] = React.useState(false);

  const timerRef = React.useRef<NodeJS.Timeout | null>(null);

  const phoneAuthSnapshotRef =
    React.useRef<FirebaseAuthTypes.PhoneAuthSnapshot | null>(null);

  const startResendTimer = useCallback(() => {
    setCanResend(false);

    if (timerRef.current) {
      clearTimeout(timerRef.current);
    }

    timerRef.current = setTimeout(
      () => setCanResend(true),
      RESEND_DELAY * 1000,
    );
  }, [setCanResend]);

  const sendCode = useCallback(
    async (force: boolean) => {
      startResendTimer();

      phoneAuthSnapshotRef.current =
        await new Promise<FirebaseAuthTypes.PhoneAuthSnapshot>(
          (resolve, reject) => {
            verifyPhoneNumber(
              getAuth(),
              phoneNumber,
              AUTOVERIFY_TIME,
              force,
            ).on(
              'state_changed',
              phoneAuthSnapshot => {},
              error => {
                reject(error);
              },
              phoneAuthSnapshot => {
                resolve(phoneAuthSnapshot);
              },
            );
          },
        );

      // try auto retrieve the code on android
      if (phoneAuthSnapshotRef.current.code) {
        return phoneAuthSnapshotRef.current.code;
      }
    },
    [phoneNumber, startResendTimer],
  );

  const authenticateWithCode = useCallback(
    async (code: string) => {
      if (!phoneAuthSnapshotRef.current) {
        throw {code: UNKNOWN_ERROR};
      }

      const credential = auth.PhoneAuthProvider.credential(
        phoneAuthSnapshotRef.current.verificationId,
        code,
      );

      let userCredential: FirebaseAuthTypes.UserCredential | null = null;

      // Upgrading current anonymous user has some limitations, please check :
      // https://github.com/firebase/flutterfire/issues/6006
      // https://github.com/firebase/flutterfire/issues/3949
      //
      // We can't use linkWithCredential because if an user already exists
      // with that specific phone number we will get a session expired exception
      // and will be forced to resend a new SMS code
      //
      // const {currentUser} = firebase.auth();
      // if (currentUser && currentUser.isAnonymous) {
      //   try {
      //     userCredential = await currentUser.linkWithCredential(credential);
      //   } catch (error) {
      //     console.log(error);
      //   }
      // }

      if (!userCredential) {
        userCredential = await signInWithCredential(getAuth(), credential);
      }

      return userCredential.user;
    },
    [phoneAuthSnapshotRef],
  );

  // proper cleanup on unmount
  React.useEffect(() => {
    return () => {
      timerRef.current && clearTimeout(timerRef.current);
    };
  }, []);

  return {sendCode, authenticateWithCode, canResend};
};

package.json:

  "dependencies": {
    // if you need more please let me know
    "@react-native-firebase/analytics": "^21.13.0",
    "@react-native-firebase/app": "^21.13.0",
    "@react-native-firebase/auth": "^21.13.0",
    "@react-native-firebase/messaging": "^21.13.0",
    "react-native": "0.78.2",
  }
  "devDependencies": {
    "@babel/core": "^7.26.10",
    "@babel/preset-env": "^7.26.9",
    "@babel/runtime": "^7.27.0",
    "@react-native-community/cli": "15.1.3",
    "@react-native-community/cli-platform-android": "15.1.3",
    "@react-native-community/cli-platform-ios": "15.1.3",
    "@react-native/babel-preset": "0.78.2",
    "@react-native/eslint-config": "0.78.2",
    "@react-native/metro-config": "0.78.2",
    "@react-native/typescript-config": "0.78.2",
    "@types/jest": "^29.5.14",
    "@types/react": "^19.1.0",
    "@types/react-native-vector-icons": "^6.4.18",
    "@types/react-test-renderer": "^19.1.0",
    "eslint": "^8.57.1",
    "jest": "^29.7.0",
    "patch-package": "^8.0.0",
    "react-test-renderer": "19.0.0",
    "typescript": "^5.8.2"
  },

firebase.json for react-native-firebase v6:

{
  "react-native": {
    "messaging_ios_auto_register_for_remote_messages": true
  }
}

iOS

Click To Expand

ios/Podfile:

  • I'm not using Pods
  • I'm using Pods and my Podfile looks like:
ENV['RCT_NEW_ARCH_ENABLED'] = '0'

def node_require(script)
  # Resolve script with node to allow for hoisting
  require Pod::Executable.execute_command('node', ['-p',
    "require.resolve(
      '#{script}',
      {paths: [process.argv[1]]},
    )", __dir__]).strip
end

node_require('react-native/scripts/react_native_pods.rb')

platform :ios, min_ios_version_supported
prepare_react_native_project!

use_frameworks! :linkage => :static

$RNFirebaseAsStaticFramework = true
$RNFirebaseAnalyticsWithoutAdIdSupport = true

target 'Menoo' do
  config = use_native_modules!(packages_to_skip: ['react-native-compressed-jsbundle'])

  use_react_native!(
    :path => config[:reactNativePath],
    # Hermes should be disabled in AppClip due to size constraints
    # Be aware that "export USE_HERMES=false" is also set in .xcode.env
    :hermes_enabled => false,
    # An absolute path to your application root.
    :app_path => "#{Pod::Config.instance.installation_root}/.."
  )
end

AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  NSLog(@"Menoo");

  [FIRApp configure];

  self.moduleName = @"Menoo";
  // You can add your custom initial props in the dictionary below.
  // They will be passed down to the ViewController used by React Native.
  
  NSDictionary *initProps = [self prepareInitialProps];
  // this is for passing isHeadless parameter
  // https://rnfirebase.io/messaging/usage
  NSDictionary *appProperties = [RNFBMessagingModule addCustomPropsToUserProps:initProps withLaunchOptions:launchOptions];
  
  self.initialProps = appProperties;
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}


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:

// N/A

android/app/build.gradle:

// N/A

android/settings.gradle:

// N/A

MainApplication.java:

// N/A

AndroidManifest.xml:

<!-- N/A -->


Environment

Click To Expand

react-native info output:

System:
  OS: macOS 14.5
  CPU: (8) arm64 Apple M1
  Memory: 72.11 MB / 8.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 18.20.4
    path: ~/.nvm/versions/node/v18.20.4/bin/node
  Yarn: Not Found
  npm:
    version: 10.7.0
    path: ~/.nvm/versions/node/v18.20.4/bin/npm
  Watchman:
    version: 2024.08.26.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.15.2
    path: /opt/homebrew/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 24.2
      - iOS 18.2
      - macOS 15.2
      - tvOS 18.2
      - visionOS 2.2
      - watchOS 11.2
  Android SDK: Not Found
IDEs:
  Android Studio: Not Found
  Xcode:
    version: 16.2/16C5032a
    path: /usr/bin/xcodebuild
Languages:
  Java: Not Found
  Ruby:
    version: 2.6.10
    path: /usr/bin/ruby
npmPackages:
  "@react-native-community/cli":
    installed: 15.1.3
    wanted: 15.1.3
  react:
    installed: 19.0.0
    wanted: 19.0.0
  react-native:
    installed: 0.78.2
    wanted: 0.78.2
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: false
iOS:
  hermesEnabled: false
  newArchEnabled: false
  • Platform that you're experiencing the issue on:
    • 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:
    • 21.13.0
  • Firebase module(s) you're using that has the issue:
    • e.g. Instance ID
  • Are you using TypeScript?
    • Y/N & VERSION


@Kaizodo
Copy link

Kaizodo commented Apr 7, 2025

having same issue with Google Auth

auth.GoogleAuthProvider.credential

credential part is undefined

this is only happening in production build, i am on latest verion of react native and react native firebase.

LOG CAT

04-07 15:23:19.733 24918 24984 I ReactNativeJS: { [Function: f] <--- this is console.log(auth)
04-07 15:23:19.733 24918 24984 I ReactNativeJS:   AppleAuthProvider: [Function: t],
04-07 15:23:19.733 24918 24984 I ReactNativeJS:   EmailAuthProvider: [Function: t],
04-07 15:23:19.733 24918 24984 I ReactNativeJS:   PhoneAuthProvider: [Function: t],
04-07 15:23:19.733 24918 24984 I ReactNativeJS:   GoogleAuthProvider: [Function: t],
04-07 15:23:19.733 24918 24984 I ReactNativeJS:   GithubAuthProvider: [Function: t],
04-07 15:23:19.733 24918 24984 I ReactNativeJS:   TwitterAuthProvider: [Function: t],
04-07 15:23:19.733 24918 24984 I ReactNativeJS:   FacebookAuthProvider: [Function: t],
04-07 15:23:19.733 24918 24984 I ReactNativeJS:   PhoneMultiFactorGenerator: { [Function: t] FACTOR_ID: 'phone' },
04-07 15:23:19.733 24918 24984 I ReactNativeJS:   OAuthProvider: [Function: t],
04-07 15:23:19.733 24918 24984 I ReactNativeJS:   OIDCAuthProvider: [Function: t],
04-07 15:23:19.733 24918 24984 I ReactNativeJS:   PhoneAuthState: 
04-07 15:23:19.733 24918 24984 I ReactNativeJS:    { CODE_SENT: 'sent',
04-07 15:23:19.733 24918 24984 I ReactNativeJS:      AUTO_VERIFY_TIMEOUT: 'timeout',
04-07 15:23:19.733 24918 24984 I ReactNativeJS:      AUTO_VERIFIED: 'verified',
04-07 15:23:19.733 24918 24984 I ReactNativeJS:      ERROR: 'error' },
04-07 15:23:19.733 24918 24984 I ReactNativeJS:   getMultiFactorResolver: [Function],
04-07 15:23:19.733 24918 24984 I ReactNativeJS:   multiFactor: [Function] }
04-07 15:23:19.733 24918 24984 I ReactNativeJS: [Function] <-- this is console.log(auth.GoogleAuthProvider)
04-07 15:23:19.733 24918 24984 I ReactNativeJS: ERROR AT auth.GoogleAuthProvider.credential
04-07 15:23:19.733 24918 24984 I ReactNativeJS: [TypeError: undefined is not a function]

@MichaelVerdon
Copy link
Collaborator

This issue appears to be similar, can you see if the users solution also works for you? #8315

@tux2nicolae
Copy link
Author

Hi @MichaelVerdon, indeed it's very similar, that's why I've mentioned the issue in the description as well

The user ignored the problem by not using the function at all, which is not an option for us. We still need the credential function in our scenario as attached in the javascript section of the issue,

@mikehardy
Copy link
Collaborator

Very strange - @MichaelVerdon note that I added the ability to do release-mode testing for android and ios recently in our e2e app, so we should be seeing this. It won't be possible to check the GoogleAuthProvider easily as it requires some provisioning the e2e app doesn't have, but the PhoneAuthProvider should be testable (and should already have tests executing!) in the e2e harness. There were a couple other issues only showing up in release mode and I wanted to try to detect debug/release mode skew in CI so this sort of thing wouldn't happen

In fact, we do test this:

https://github.com/invertase/react-native-firebase/actions/workflows/tests_e2e_ios.yml
https://github.com/invertase/react-native-firebase/actions/runs/14307579875/job/40094837715
https://github.com/invertase/react-native-firebase/actions/runs/14307579875/job/40094837715#step:26:689

Why are we not seeing this? 🤔

@tux2nicolae
Copy link
Author

Is it possible that it may have been optimized away somehow by the compiler? I just don't have any other explanation why the function may not be available only on release builds ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants