@react-native-firebase/auth 22.0.0 → 22.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,24 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [22.2.0](https://github.com/invertase/react-native-firebase/compare/v22.1.0...v22.2.0) (2025-05-12)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **auth, expo:** lowercase `String?` in swift using `.lowercased()` ([af435e8](https://github.com/invertase/react-native-firebase/commit/af435e8b8bc84a98e4fab336ade6952178c7f6f8))
11
+ - **auth:** missing PhoneMultiFactorGenerator export ([aaaec03](https://github.com/invertase/react-native-firebase/commit/aaaec03bba10c68d0f700b6c4b26a17c467f71bb))
12
+
13
+ ## [22.1.0](https://github.com/invertase/react-native-firebase/compare/v22.0.0...v22.1.0) (2025-04-30)
14
+
15
+ ### Features
16
+
17
+ - **auth, expo:** add support for AppDelegate.swift ([e4966ef](https://github.com/invertase/react-native-firebase/commit/e4966ef3b692b3b8a3b89fbf54a0a0d59ca06ab6))
18
+
19
+ ### Bug Fixes
20
+
21
+ - **auth, android:** catch native error in signWithEmailLink ([a08580e](https://github.com/invertase/react-native-firebase/commit/a08580e29d672af99e890a60dbef8aba094b697c))
22
+ - **auth:** delegate modular `multiFactor` to MultiFactorUser constructor ([0937c77](https://github.com/invertase/react-native-firebase/commit/0937c77c9642da082de34de39cbf6a1847ae065c))
23
+
6
24
  ## [22.0.0](https://github.com/invertase/react-native-firebase/compare/v21.14.0...v22.0.0) (2025-04-25)
7
25
 
8
26
  ### ⚠ BREAKING CHANGES
@@ -459,18 +459,23 @@ class ReactNativeFirebaseAuthModule extends ReactNativeFirebaseModule {
459
459
  FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
460
460
  FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
461
461
 
462
- firebaseAuth
463
- .signInWithEmailLink(email, emailLink)
464
- .addOnSuccessListener(
465
- authResult -> {
466
- Log.d(TAG, "signInWithEmailLink:onComplete:success");
467
- promiseWithAuthResult(authResult, promise);
468
- })
469
- .addOnFailureListener(
470
- exception -> {
471
- Log.e(TAG, "signInWithEmailLink:onComplete:failure", exception);
472
- promiseRejectAuthException(promise, exception);
473
- });
462
+ try {
463
+ firebaseAuth
464
+ .signInWithEmailLink(email, emailLink)
465
+ .addOnSuccessListener(
466
+ authResult -> {
467
+ Log.d(TAG, "signInWithEmailLink:onComplete:success");
468
+ promiseWithAuthResult(authResult, promise);
469
+ })
470
+ .addOnFailureListener(
471
+ exception -> {
472
+ Log.e(TAG, "signInWithEmailLink:onComplete:failure", exception);
473
+ promiseRejectAuthException(promise, exception);
474
+ });
475
+ } catch (Exception exception) {
476
+ Log.e(TAG, "signInWithEmailLink:onComplete:totalfailure", exception);
477
+ promiseRejectAuthException(promise, exception);
478
+ }
474
479
  }
475
480
 
476
481
  @ReactMethod
package/lib/index.d.ts CHANGED
@@ -1806,17 +1806,27 @@ export namespace FirebaseAuthTypes {
1806
1806
  /**
1807
1807
  * Signs a user in with an email and password.
1808
1808
  *
1809
+ * ⚠️ Note:
1810
+ * If "Email Enumeration Protection" is enabled in your Firebase Authentication settings (enabled by default),
1811
+ * Firebase may return a generic `auth/invalid-login-credentials` error instead of more specific ones like
1812
+ * `auth/user-not-found` or `auth/wrong-password`. This behavior is intended to prevent leaking information
1813
+ * about whether an account with the given email exists.
1814
+ *
1815
+ * To receive detailed error codes, you must disable "Email Enumeration Protection", which may increase
1816
+ * security risks if not properly handled on the frontend.
1817
+ *
1809
1818
  * #### Example
1810
1819
  *
1811
1820
  * ```js
1812
1821
  * const userCredential = await firebase.auth().signInWithEmailAndPassword('joe.bloggs@example.com', '123456');
1813
- * ````
1822
+ * ```
1823
+ *
1814
1824
  * @error auth/invalid-email Thrown if the email address is not valid.
1815
1825
  * @error auth/user-disabled Thrown if the user corresponding to the given email has been disabled.
1816
- * @error auth/user-not-found Thrown if there is no user corresponding to the given email.
1817
- * @error auth/wrong-password Thrown if the password is invalid for the given email, or the account corresponding to the email does not have a password set.
1818
- * @param email The users email address.
1819
- * @param password The users password.
1826
+ * @error auth/user-not-found Thrown if there is no user corresponding to the given email. (May be suppressed if email enumeration protection is enabled.)
1827
+ * @error auth/wrong-password Thrown if the password is invalid or missing. (May be suppressed if email enumeration protection is enabled.)
1828
+ * @param email The user's email address.
1829
+ * @param password The user's password.
1820
1830
  */
1821
1831
  signInWithEmailAndPassword(email: string, password: string): Promise<UserCredential>;
1822
1832
 
@@ -2008,15 +2018,16 @@ export namespace FirebaseAuthTypes {
2008
2018
  sendSignInLinkToEmail(email: string, actionCodeSettings?: ActionCodeSettings): Promise<void>;
2009
2019
 
2010
2020
  /**
2011
- * Returns whether the user signed in with a given email link.
2021
+ * Checks if an incoming link is a sign-in with email link suitable for signInWithEmailLink.
2022
+ * Note that android and other platforms require `apiKey` link parameter for signInWithEmailLink
2012
2023
  *
2013
2024
  * #### Example
2014
2025
  *
2015
2026
  * ```js
2016
- * const signedInWithLink = await firebase.auth().isSignInWithEmailLink(link);
2027
+ * const valid = await firebase.auth().isSignInWithEmailLink(link);
2017
2028
  * ```
2018
2029
  *
2019
- * @param emailLink The email link to check whether the user signed in with it.
2030
+ * @param emailLink The email link to verify prior to using signInWithEmailLink
2020
2031
  */
2021
2032
  isSignInWithEmailLink(emailLink: string): Promise<boolean>;
2022
2033
 
@@ -2095,18 +2106,27 @@ export namespace FirebaseAuthTypes {
2095
2106
  /**
2096
2107
  * Returns a list of authentication methods that can be used to sign in a given user (identified by its main email address).
2097
2108
  *
2109
+ * ⚠️ Note:
2110
+ * If "Email Enumeration Protection" is enabled in your Firebase Authentication settings (which is the default),
2111
+ * this method may return an empty array even if the email is registered, especially when called from an unauthenticated context.
2112
+ *
2113
+ * This is a security measure to prevent leaking account existence via email enumeration attacks.
2114
+ * Do not use the result of this method to directly inform the user whether an email is registered.
2115
+ *
2098
2116
  * #### Example
2099
2117
  *
2100
2118
  * ```js
2101
2119
  * const methods = await firebase.auth().fetchSignInMethodsForEmail('joe.bloggs@example.com');
2102
2120
  *
2103
- * methods.forEach((method) => {
2104
- * console.log(method);
2105
- * });
2121
+ * if (methods.length > 0) {
2122
+ * // Likely a registered user — offer sign-in
2123
+ * } else {
2124
+ * // Could be unregistered OR email enumeration protection is active — offer registration
2125
+ * }
2106
2126
  * ```
2107
2127
  *
2108
2128
  * @error auth/invalid-email Thrown if the email address is not valid.
2109
- * @param email The users email address.
2129
+ * @param email The user's email address.
2110
2130
  */
2111
2131
  fetchSignInMethodsForEmail(email: string): Promise<string[]>;
2112
2132
 
@@ -165,7 +165,8 @@ export interface PopupRedirectResolver {}
165
165
  export function initializeRecaptchaConfig(auth: Auth): Promise<void>;
166
166
 
167
167
  /**
168
- * Checks if an incoming link is a sign-in with email link suitable for signInWithEmailLink().
168
+ * Checks if an incoming link is a sign-in with email link suitable for signInWithEmailLink.
169
+ * Note that android and other platforms require `apiKey` link parameter for signInWithEmailLink
169
170
  *
170
171
  * @param auth - The Auth instance.
171
172
  * @param emailLink - The email link to check.
@@ -778,5 +779,6 @@ export {
778
779
  OAuthProvider,
779
780
  OIDCAuthProvider,
780
781
  PhoneAuthProvider,
782
+ PhoneMultiFactorGenerator,
781
783
  TwitterAuthProvider,
782
784
  } from '../index';
@@ -19,6 +19,7 @@ import { getApp } from '@react-native-firebase/app';
19
19
  import { fetchPasswordPolicy } from '../password-policy/passwordPolicyApi';
20
20
  import { PasswordPolicyImpl } from '../password-policy/PasswordPolicyImpl';
21
21
  import FacebookAuthProvider from '../providers/FacebookAuthProvider';
22
+ import { MultiFactorUser } from '../multiFactor';
22
23
  export { FacebookAuthProvider };
23
24
 
24
25
  /**
@@ -462,7 +463,7 @@ export async function linkWithRedirect(user, provider, resolver) {
462
463
  * @returns {MultiFactorUser}
463
464
  */
464
465
  export function multiFactor(user) {
465
- return user._auth.multiFactor(user);
466
+ return new MultiFactorUser(getAuth(), user);
466
467
  }
467
468
 
468
469
  /**
package/lib/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- module.exports = '22.0.0';
2
+ module.exports = '22.2.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native-firebase/auth",
3
- "version": "22.0.0",
3
+ "version": "22.2.0",
4
4
  "author": "Invertase <oss@invertase.io> (http://invertase.io)",
5
5
  "description": "React Native Firebase - The authentication module provides an easy-to-use API to integrate an authentication workflow into new and existing applications. React Native Firebase provides access to all Firebase authentication methods and identity providers.",
6
6
  "main": "lib/index.js",
@@ -27,7 +27,7 @@
27
27
  "plist": "^3.1.0"
28
28
  },
29
29
  "peerDependencies": {
30
- "@react-native-firebase/app": "22.0.0",
30
+ "@react-native-firebase/app": "22.2.0",
31
31
  "expo": ">=47.0.0"
32
32
  },
33
33
  "devDependencies": {
@@ -43,5 +43,5 @@
43
43
  "access": "public",
44
44
  "provenance": true
45
45
  },
46
- "gitHead": "e9fee87b413c90e243347d5c60272f07f41d99b8"
46
+ "gitHead": "b302210509ceac8078b5fb9fd0b24e68f0641c6a"
47
47
  }
@@ -12,9 +12,12 @@ export declare function withOpenUrlFixForAppDelegate({ config, props, }: {
12
12
  config: ExportedConfigWithProps<AppDelegateProjectFile>;
13
13
  props?: PluginConfigType;
14
14
  }): ExportedConfigWithProps<AppDelegateProjectFile>;
15
+ export declare function modifyAppDelegate(contents: string, language: string): string | null;
15
16
  export declare const appDelegateOpenUrlInsertionPointAfter: RegExp;
16
17
  export declare const multiline_appDelegateOpenUrlInsertionPointAfter: RegExp;
17
18
  export declare function modifyObjcAppDelegate(contents: string): string | null;
19
+ export declare const appDelegateSwiftOpenUrlInsertionPointAfter: RegExp;
20
+ export declare function modifySwiftAppDelegate(contents: string): string | null;
18
21
  export type ExpoConfigPluginEntry = string | [] | [string] | [string, any];
19
22
  export declare function isFirebaseSwizzlingDisabled(config: ExportedConfigWithProps<InfoPlist>): boolean;
20
23
  export declare function ensureFirebaseSwizzlingIsEnabled(config: ExportedConfigWithProps<InfoPlist>): boolean;
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.multiline_appDelegateOpenUrlInsertionPointAfter = exports.appDelegateOpenUrlInsertionPointAfter = exports.withIosCaptchaOpenUrlFix = void 0;
3
+ exports.appDelegateSwiftOpenUrlInsertionPointAfter = exports.multiline_appDelegateOpenUrlInsertionPointAfter = exports.appDelegateOpenUrlInsertionPointAfter = exports.withIosCaptchaOpenUrlFix = void 0;
4
4
  exports.shouldApplyIosOpenUrlFix = shouldApplyIosOpenUrlFix;
5
5
  exports.withOpenUrlFixForAppDelegate = withOpenUrlFixForAppDelegate;
6
+ exports.modifyAppDelegate = modifyAppDelegate;
6
7
  exports.modifyObjcAppDelegate = modifyObjcAppDelegate;
8
+ exports.modifySwiftAppDelegate = modifySwiftAppDelegate;
7
9
  exports.isFirebaseSwizzlingDisabled = isFirebaseSwizzlingDisabled;
8
10
  exports.ensureFirebaseSwizzlingIsEnabled = ensureFirebaseSwizzlingIsEnabled;
9
11
  const config_plugins_1 = require("@expo/config-plugins");
@@ -42,32 +44,37 @@ function shouldApplyIosOpenUrlFix({ config, props, }) {
42
44
  function withOpenUrlFixForAppDelegate({ config, props, }) {
43
45
  const { language, contents } = config.modResults;
44
46
  const configValue = props?.ios?.captchaOpenUrlFix || 'default';
45
- if (['objc', 'objcpp'].includes(language)) {
46
- const newContents = modifyObjcAppDelegate(contents);
47
- if (newContents === null) {
48
- if (configValue === true) {
49
- throw new Error("Failed to apply iOS openURL fix because no 'openURL' method was found");
50
- }
51
- else {
52
- config_plugins_1.WarningAggregator.addWarningIOS('@react-native-firebase/auth', "Skipping iOS openURL fix because no 'openURL' method was found");
53
- return config;
54
- }
47
+ const newContents = modifyAppDelegate(contents, language);
48
+ if (newContents === null) {
49
+ if (configValue === true) {
50
+ throw new Error("Failed to apply iOS openURL fix because no 'openURL' method was found");
55
51
  }
56
52
  else {
57
- if (configValue === 'default') {
58
- config_plugins_1.WarningAggregator.addWarningIOS('@react-native-firebase/auth', 'modifying iOS AppDelegate openURL method to ignore firebaseauth reCAPTCHA redirect URLs');
59
- }
60
- return {
61
- ...config,
62
- modResults: {
63
- ...config.modResults,
64
- contents: newContents,
65
- },
66
- };
53
+ config_plugins_1.WarningAggregator.addWarningIOS('@react-native-firebase/auth', "Skipping iOS openURL fix because no 'openURL' method was found");
54
+ return config;
67
55
  }
68
56
  }
69
57
  else {
70
- // TODO: Support Swift
58
+ if (configValue === 'default') {
59
+ config_plugins_1.WarningAggregator.addWarningIOS('@react-native-firebase/auth', 'modifying iOS AppDelegate openURL method to ignore firebaseauth reCAPTCHA redirect URLs');
60
+ }
61
+ return {
62
+ ...config,
63
+ modResults: {
64
+ ...config.modResults,
65
+ contents: newContents,
66
+ },
67
+ };
68
+ }
69
+ }
70
+ function modifyAppDelegate(contents, language) {
71
+ if (language === 'objc' || language === 'objcpp') {
72
+ return modifyObjcAppDelegate(contents);
73
+ }
74
+ else if (language === 'swift') {
75
+ return modifySwiftAppDelegate(contents);
76
+ }
77
+ else {
71
78
  throw new Error(`Don't know how to apply openUrlFix to AppDelegate of language "${language}"`);
72
79
  }
73
80
  }
@@ -116,6 +123,35 @@ function modifyObjcAppDelegate(contents) {
116
123
  comment: '//',
117
124
  }).contents;
118
125
  }
126
+ // NOTE: `mergeContents()` doesn't support newlines for the `anchor` regex, so we have to replace it manually
127
+ const skipOpenUrlForFirebaseAuthBlockSwift = `\
128
+ // @generated begin @react-native-firebase/auth-openURL - expo prebuild (DO NOT MODIFY)
129
+ if url.host?.lowercased() == "firebaseauth" {
130
+ // invocations for Firebase Auth are handled elsewhere and should not be forwarded to Expo Router
131
+ return false
132
+ }
133
+ // @generated end @react-native-firebase/auth-openURL\
134
+ `;
135
+ exports.appDelegateSwiftOpenUrlInsertionPointAfter = /public\s*override\s*func\s*application\s*\(\n\s*_\s*app\s*:\s*UIApplication,\n\s*open\s*url\s*:\s*URL,\n\s*options\s*:\s*\[UIApplication\.OpenURLOptionsKey\s*:\s*Any\]\s*=\s*\[:\]\n\s*\)\s*->\s*Bool\s*{\n/;
136
+ function modifySwiftAppDelegate(contents) {
137
+ const pattern = exports.appDelegateSwiftOpenUrlInsertionPointAfter;
138
+ const fullMatch = contents.match(pattern);
139
+ if (!fullMatch) {
140
+ if (contents.match(/open url\s*:/)) {
141
+ throw new Error([
142
+ "Failed to apply 'captchaOpenUrlFix' but detected 'openURL' method.",
143
+ "Please manually apply the fix to your AppDelegate's openURL method,",
144
+ "then update your app.config.json by configuring the '@react-native-firebase/auth' plugin",
145
+ 'to set `captchaOpenUrlFix: false`.',
146
+ ].join(' '));
147
+ }
148
+ else {
149
+ // openURL method was not found in AppDelegate
150
+ return null;
151
+ }
152
+ }
153
+ return contents.replace(pattern, `${fullMatch[0]}${skipOpenUrlForFirebaseAuthBlockSwift}\n`);
154
+ }
119
155
  // Search the ExpoConfig plugins array to see if `pluginName` is present
120
156
  function isPluginEnabled(config, pluginName) {
121
157
  if (config.plugins === undefined) {
@@ -62,35 +62,40 @@ export function withOpenUrlFixForAppDelegate({
62
62
  const { language, contents } = config.modResults;
63
63
  const configValue = props?.ios?.captchaOpenUrlFix || 'default';
64
64
 
65
- if (['objc', 'objcpp'].includes(language)) {
66
- const newContents = modifyObjcAppDelegate(contents);
67
- if (newContents === null) {
68
- if (configValue === true) {
69
- throw new Error("Failed to apply iOS openURL fix because no 'openURL' method was found");
70
- } else {
71
- WarningAggregator.addWarningIOS(
72
- '@react-native-firebase/auth',
73
- "Skipping iOS openURL fix because no 'openURL' method was found",
74
- );
75
- return config;
76
- }
65
+ const newContents = modifyAppDelegate(contents, language);
66
+ if (newContents === null) {
67
+ if (configValue === true) {
68
+ throw new Error("Failed to apply iOS openURL fix because no 'openURL' method was found");
77
69
  } else {
78
- if (configValue === 'default') {
79
- WarningAggregator.addWarningIOS(
80
- '@react-native-firebase/auth',
81
- 'modifying iOS AppDelegate openURL method to ignore firebaseauth reCAPTCHA redirect URLs',
82
- );
83
- }
84
- return {
85
- ...config,
86
- modResults: {
87
- ...config.modResults,
88
- contents: newContents,
89
- },
90
- };
70
+ WarningAggregator.addWarningIOS(
71
+ '@react-native-firebase/auth',
72
+ "Skipping iOS openURL fix because no 'openURL' method was found",
73
+ );
74
+ return config;
75
+ }
76
+ } else {
77
+ if (configValue === 'default') {
78
+ WarningAggregator.addWarningIOS(
79
+ '@react-native-firebase/auth',
80
+ 'modifying iOS AppDelegate openURL method to ignore firebaseauth reCAPTCHA redirect URLs',
81
+ );
91
82
  }
83
+ return {
84
+ ...config,
85
+ modResults: {
86
+ ...config.modResults,
87
+ contents: newContents,
88
+ },
89
+ };
90
+ }
91
+ }
92
+
93
+ export function modifyAppDelegate(contents: string, language: string): string | null {
94
+ if (language === 'objc' || language === 'objcpp') {
95
+ return modifyObjcAppDelegate(contents);
96
+ } else if (language === 'swift') {
97
+ return modifySwiftAppDelegate(contents);
92
98
  } else {
93
- // TODO: Support Swift
94
99
  throw new Error(`Don't know how to apply openUrlFix to AppDelegate of language "${language}"`);
95
100
  }
96
101
  }
@@ -147,6 +152,40 @@ export function modifyObjcAppDelegate(contents: string): string | null {
147
152
  }).contents;
148
153
  }
149
154
 
155
+ // NOTE: `mergeContents()` doesn't support newlines for the `anchor` regex, so we have to replace it manually
156
+ const skipOpenUrlForFirebaseAuthBlockSwift: string = `\
157
+ // @generated begin @react-native-firebase/auth-openURL - expo prebuild (DO NOT MODIFY)
158
+ if url.host?.lowercased() == "firebaseauth" {
159
+ // invocations for Firebase Auth are handled elsewhere and should not be forwarded to Expo Router
160
+ return false
161
+ }
162
+ // @generated end @react-native-firebase/auth-openURL\
163
+ `;
164
+
165
+ export const appDelegateSwiftOpenUrlInsertionPointAfter: RegExp =
166
+ /public\s*override\s*func\s*application\s*\(\n\s*_\s*app\s*:\s*UIApplication,\n\s*open\s*url\s*:\s*URL,\n\s*options\s*:\s*\[UIApplication\.OpenURLOptionsKey\s*:\s*Any\]\s*=\s*\[:\]\n\s*\)\s*->\s*Bool\s*{\n/;
167
+
168
+ export function modifySwiftAppDelegate(contents: string): string | null {
169
+ const pattern = appDelegateSwiftOpenUrlInsertionPointAfter;
170
+ const fullMatch = contents.match(pattern);
171
+ if (!fullMatch) {
172
+ if (contents.match(/open url\s*:/)) {
173
+ throw new Error(
174
+ [
175
+ "Failed to apply 'captchaOpenUrlFix' but detected 'openURL' method.",
176
+ "Please manually apply the fix to your AppDelegate's openURL method,",
177
+ "then update your app.config.json by configuring the '@react-native-firebase/auth' plugin",
178
+ 'to set `captchaOpenUrlFix: false`.',
179
+ ].join(' '),
180
+ );
181
+ } else {
182
+ // openURL method was not found in AppDelegate
183
+ return null;
184
+ }
185
+ }
186
+ return contents.replace(pattern, `${fullMatch[0]}${skipOpenUrlForFirebaseAuthBlockSwift}\n`);
187
+ }
188
+
150
189
  export type ExpoConfigPluginEntry = string | [] | [string] | [string, any];
151
190
 
152
191
  // Search the ExpoConfig plugins array to see if `pluginName` is present