Skip to content

Conversation

@mikehardy
Copy link
Contributor

Description

Hi there 👋 - I'm one of the maintainers of react-native-firebase on behalf of Google

I'm trying to enable MFA testing with SMS as the second factor for the iOS platform, and I noticed a problem. This patch fixes it.

SMS MFA works using firebase-js-sdk and firebase-android-sdk against the emulator - these send unobfuscated phone numbers for the finalization step allowing successful enrollment location

firebase-ios-sdk sends an obfuscated phone number during the finalization step though and the enrollment isn't found, leading to SMS MFA failures against the emulator despite the same code working against cloud auth.

By allowing the enrollment lookup to check both unobfuscated and obfuscated numbers for enrollment id, the emulator will successfully finalize an MFA login with SMS as the second factor, on all platforms

Scenarios Tested

See description

Sample Commands

See descriptoin

This works in practice against cloud auth but fails on the emulator. The emulator should succeed if cloud auth succeeds
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @mikehardy, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves an issue where SMS Multi-Factor Authentication (MFA) finalization failed when using the Firebase iOS SDK against the Firebase Auth emulator. The change allows the emulator to correctly identify MFA enrollments by checking for both unobfuscated and obfuscated phone numbers, aligning its behavior with the cloud auth service and enabling consistent MFA testing across all platforms.

Highlights

  • SMS MFA Compatibility: Implemented a fix in the mfaSignInFinalize function to correctly handle SMS MFA finalization when the firebase-ios-sdk sends an obfuscated phone number to the emulator. This ensures that MFA enrollments can be found regardless of whether the phone number is obfuscated or not.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses an issue with SMS MFA finalization for iOS clients, which send obfuscated phone numbers. The change correctly allows the emulator to look up MFA enrollments using both unobfuscated and obfuscated numbers. My feedback focuses on improving the implementation of this new logic for better maintainability and robustness. I've suggested refactoring the hardcoded obfuscation logic to enhance readability and use safer string manipulation, while also highlighting an inconsistency with an existing obfuscation function that should be reconciled.

Comment on lines 2224 to 2231
(enrollment) => {
return
// all but firebase-ios-sdk finalize with unobfuscated phone number which we find easily...
enrollment.unobfuscatedPhoneInfo === phoneNumber ||
// ...but firebase-ios-sdk finalizes with obfuscated
// This works against cloud auth, so emulator should attempt to find enrollment obfuscated as well.
('+********' + enrollment.unobfuscatedPhoneInfo.substring(enrollment.unobfuscatedPhoneInfo.length - 4)) === phoneNumber;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While this change fixes the issue with the iOS SDK, the implementation introduces a new way of obfuscating phone numbers that is inconsistent with the existing obfuscatePhoneNumber function (line 2949). This could cause confusion and maintenance issues down the line.

The hardcoded logic '+********' + ... is also not very robust. Using slice(-4) would be safer for strings of different lengths than substring(length - 4).

I've refactored the logic to be more readable and robust. If the obfuscation logic for iOS is indeed different from obfuscatePhoneNumber, it might be worth extracting this new logic into its own function in a follow-up to address the code duplication.

    (enrollment) => {
      // All but firebase-ios-sdk finalize with an unobfuscated phone number.
      if (enrollment.unobfuscatedPhoneInfo === phoneNumber) {
        return true;
      }

      // But firebase-ios-sdk finalizes with an obfuscated number. This works against
      // cloud auth, so the emulator should also attempt to find the enrollment
      // using an obfuscated number.
      const obfuscatedForIOS = `+********${enrollment.unobfuscatedPhoneInfo.slice(-4)}`;
      return obfuscatedForIOS === phoneNumber;
    }

mikehardy added a commit to invertase/react-native-firebase that referenced this pull request Sep 1, 2025
on iOS they attempt to verify a masked number for 2FA not an unmasked one
- works fine against cloud auth, so it is an emulator-specific issue
- in emulator you can fix it with a patch that looks for unobfuscated *or* obfuscated verification

See firebase/firebase-tools#9062
Copy link
Member

@russellwheatley russellwheatley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - happy with code suggestion as well 👍

Co-authored-by: Mike Hardy <github@mikehardy.net>
Copy link
Contributor

@joehan joehan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the contribution!

const enrollment = user.mfaInfo?.find(
(enrollment) => enrollment.unobfuscatedPhoneInfo === phoneNumber,
(enrollment) => {
// All but firebase-ios-sdk finalize with unobfuscated phone number.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

linter might not be happy with this spacing nit...

Suggested change
// All but firebase-ios-sdk finalize with unobfuscated phone number.
// All but firebase-ios-sdk finalize with unobfuscated phone number.

Copy link
Contributor Author

@mikehardy mikehardy Sep 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, the linter argument with the patch is much more involved than that - with apologies, I did not run lint locally, I proposed the patch via textbox-coding in the github web UI (since my effective patch for react-native-firebase CI/CD was against the transpiled JS files...) - I can pull the branch local and run lint though if needed, though you may have a local workspace set up to do so quite efficiently - just let me know

mikehardy added a commit to invertase/react-native-firebase that referenced this pull request Sep 2, 2025
on iOS they attempt to verify a masked number for 2FA not an unmasked one
- works fine against cloud auth, so it is an emulator-specific issue
- in emulator you can fix it with a patch that looks for unobfuscated *or* obfuscated verification

See firebase/firebase-tools#9062
mikehardy added a commit to invertase/react-native-firebase that referenced this pull request Sep 3, 2025
on iOS they attempt to verify a masked number for 2FA not an unmasked one
- works fine against cloud auth, so it is an emulator-specific issue
- in emulator you can fix it with a patch that looks for unobfuscated *or* obfuscated verification

See firebase/firebase-tools#9062
@joehan joehan merged commit e183833 into firebase:master Sep 3, 2025
14 checks passed
@github-project-automation github-project-automation bot moved this from Approved [PR] to Done in [Cloud] Extensions + Functions Sep 3, 2025
@mikehardy mikehardy deleted the patch-3 branch September 4, 2025 00:21
@DJ2695
Copy link

DJ2695 commented Nov 24, 2025

@mikehardy is it possible, that the issue still remains after initial MFA rollout, when you want to re-verify? Cause the initial rollout works seamlessly with the initial verification. The phonenumber is unobscured also in the console. But after I try to sign in a 2nd time, which prompts for revivification, I get a code with corresponding to the phone number obscured in the console, and entering it just results in 'resolve-signin-failed'. I have done some research and your PR was the closest I came to a helpful fix.

Also there is following issue in firebase/firebase-ios-sdk#11079 still unresolved. Could they be related?

@mikehardy
Copy link
Contributor Author

This is on my list to retest today, glad I built it in to our test app versus testing as a one off initially!

@mikehardy
Copy link
Contributor Author

I had no problem today when I re-tested this using react-native-firebase 23.5.0 (but with updated firebase-ios-sdk 12.6.0 in it), and current firebase-tools (14.26.0).

You can see my full test scenario with logs coming out of the emulator, emulator Auth UI visible, and logs coming out of the test app while recording - approx 3min 30secs (and reencoded to crush it down to approx 6MB) to do the full sign up + verify email + enroll phone SMS MFA + sign out + start sign in again + request code for MFA + verify code + success

it may be that our test scenarios are different thus the video - perhaps there is still something "off" here ?

Firebase-iOS-PhoneAuthMFA-Test.mp4

@DJ2695
Copy link

DJ2695 commented Nov 26, 2025

@mikehardy thank you for the test. That is really odd. I did my test almost identical (just with flutter ui) and I also get the code with an obscure phone number in the console. But in my app it is not working after the login.

I will do more digging cause I am now not sure if its maybe a firebase_auth (flutter) issue or an implementation issue on my side, as this is the result:

piia-mfa-issue-1 piia-mfa-issue-2 piia-mfa-issue-3 piia-mfa-issue-4

If I find anything related that indicates issues about your issue, I will notify again. Thank you for your efforts!

@mikehardy
Copy link
Contributor Author

@DJ2695 you've probably already done this - but only just in case - triple check that you have the latest firebase-tools so you are running the emulator that accepts the hashed numbers from firebase-ios-sdk. Also, before that patch to the emulator it worked against real auth in the cloud. It always worked there as far as I know, before the patch here. Just a couple things to check in case you hadn't. Either way, does seem like a mystery. If you figure it out I'd love to know the reason - I personally worked pretty hard getting MFA working up from iOS through react-native, against real auth and emulator auth so I'm interested in the whole area. Cheers

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants