-
Notifications
You must be signed in to change notification settings - Fork 1.1k
fix(emulator, auth): allow SMS MFA finalization with obfuscated number #9062
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
Conversation
This works in practice against cloud auth but fails on the emulator. The emulator should succeed if cloud auth succeeds
There was a problem hiding this 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
-
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. ↩
There was a problem hiding this 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.
src/emulator/auth/operations.ts
Outdated
| (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; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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;
}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
russellwheatley
left a comment
There was a problem hiding this 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>
joehan
left a comment
There was a problem hiding this 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!
src/emulator/auth/operations.ts
Outdated
| const enrollment = user.mfaInfo?.find( | ||
| (enrollment) => enrollment.unobfuscatedPhoneInfo === phoneNumber, | ||
| (enrollment) => { | ||
| // All but firebase-ios-sdk finalize with unobfuscated phone number. |
There was a problem hiding this comment.
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...
| // All but firebase-ios-sdk finalize with unobfuscated phone number. | |
| // All but firebase-ios-sdk finalize with unobfuscated phone number. |
There was a problem hiding this comment.
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
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
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 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? |
|
This is on my list to retest today, glad I built it in to our test app versus testing as a one off initially! |
|
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 |
|
@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:
If I find anything related that indicates issues about your issue, I will notify again. Thank you for your efforts! |
|
@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 |




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