diff --git a/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java b/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java index 4ca8585cd3..1776d23bd2 100644 --- a/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java +++ b/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java @@ -459,18 +459,23 @@ private void signInWithEmailLink( FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); - firebaseAuth - .signInWithEmailLink(email, emailLink) - .addOnSuccessListener( - authResult -> { - Log.d(TAG, "signInWithEmailLink:onComplete:success"); - promiseWithAuthResult(authResult, promise); - }) - .addOnFailureListener( - exception -> { - Log.e(TAG, "signInWithEmailLink:onComplete:failure", exception); - promiseRejectAuthException(promise, exception); - }); + try { + firebaseAuth + .signInWithEmailLink(email, emailLink) + .addOnSuccessListener( + authResult -> { + Log.d(TAG, "signInWithEmailLink:onComplete:success"); + promiseWithAuthResult(authResult, promise); + }) + .addOnFailureListener( + exception -> { + Log.e(TAG, "signInWithEmailLink:onComplete:failure", exception); + promiseRejectAuthException(promise, exception); + }); + } catch (Exception exception) { + Log.e(TAG, "signInWithEmailLink:onComplete:totalfailure", exception); + promiseRejectAuthException(promise, exception); + } } @ReactMethod diff --git a/packages/auth/e2e/emailLink.e2e.js b/packages/auth/e2e/emailLink.e2e.js index 8000711d35..3ba0c8ab24 100644 --- a/packages/auth/e2e/emailLink.e2e.js +++ b/packages/auth/e2e/emailLink.e2e.js @@ -96,9 +96,55 @@ describe('auth() -> emailLink Provider', function () { }); }); - // FOR MANUAL TESTING ONLY - xdescribe('signInWithEmailLink', function () { - it('should signIn', async function () { + describe('signInWithEmailLink', function () { + it('sign in via email does not crash with missing apiKey', async function () { + const { getAuth, sendSignInLinkToEmail, signInWithEmailLink } = authModular; + + const auth = getAuth(); + const random = Utils.randString(12, '#aa'); + const email = `${random}@${random}.com`; + const continueUrl = `http://${Platform.android ? '10.0.2.2' : '127.0.0.1'}:8081/authLinkFoo?bar=${random}`; + const actionCodeSettings = { + url: continueUrl, + handleCodeInApp: true, + iOS: { + bundleId: 'com.testing', + }, + android: { + packageName: 'com.testing', + installApp: true, + minimumVersion: '12', + }, + }; + await sendSignInLinkToEmail(auth, email, actionCodeSettings); + const oobInfo = await getLastOob(email); + oobInfo.oobLink.should.containEql(encodeURIComponent(continueUrl)); + + // Specifically remove the apiKey param. Android requires it and needs + // specific error handling or it crashes, See #8360 + let linkNoApiKey = oobInfo.oobLink.replace('&apiKey=fake-api-key', ''); + try { + const signInResponse = await signInWithEmailLink(auth, email, linkNoApiKey); + if (Platform.OS !== 'ios') { + throw new Error('Should have rejected on Android and Other'); + } else { + signInResponse.user.email.should.equal(email); + auth.currentUser.email.should.equal(email); + } + } catch (e) { + if (Platform.OS === 'android') { + e.message.should.containEql('Given link is not a valid email link'); + } else if (Platform.OS === 'macos') { + e.message.should.containEql('auth/argument-error'); + } else { + // ios should have been fine without apiKey + throw e; + } + } + }); + + // FOR MANUAL TESTING ONLY + xit('should signIn', async function () { const auth = getAuth(); const email = 'MANUAL TEST EMAIL HERE'; const emailLink = 'MANUAL TEST CODE HERE'; diff --git a/packages/auth/lib/index.d.ts b/packages/auth/lib/index.d.ts index ca34c640e0..cf2cad3ecc 100644 --- a/packages/auth/lib/index.d.ts +++ b/packages/auth/lib/index.d.ts @@ -2008,15 +2008,16 @@ export namespace FirebaseAuthTypes { sendSignInLinkToEmail(email: string, actionCodeSettings?: ActionCodeSettings): Promise; /** - * Returns whether the user signed in with a given email link. + * Checks if an incoming link is a sign-in with email link suitable for signInWithEmailLink. + * Note that android and other platforms require `apiKey` link parameter for signInWithEmailLink * * #### Example * * ```js - * const signedInWithLink = await firebase.auth().isSignInWithEmailLink(link); + * const valid = await firebase.auth().isSignInWithEmailLink(link); * ``` * - * @param emailLink The email link to check whether the user signed in with it. + * @param emailLink The email link to verify prior to using signInWithEmailLink */ isSignInWithEmailLink(emailLink: string): Promise; diff --git a/packages/auth/lib/modular/index.d.ts b/packages/auth/lib/modular/index.d.ts index d75d52e7b8..f2c2c665d6 100644 --- a/packages/auth/lib/modular/index.d.ts +++ b/packages/auth/lib/modular/index.d.ts @@ -165,7 +165,8 @@ export interface PopupRedirectResolver {} export function initializeRecaptchaConfig(auth: Auth): Promise; /** - * Checks if an incoming link is a sign-in with email link suitable for signInWithEmailLink(). + * Checks if an incoming link is a sign-in with email link suitable for signInWithEmailLink. + * Note that android and other platforms require `apiKey` link parameter for signInWithEmailLink * * @param auth - The Auth instance. * @param emailLink - The email link to check.