How to setup sendSignInLinkToEmail() from Firebase in react-native?

最后都变了- 提交于 2021-01-22 05:08:12

问题


Working on a react-native project using @react-native-firebase/app v6 we recently integrated signing in with a "magic link" using auth.sendSignInLinkToEmail

We couldn't find a good example on how to setup everything in react-native and had different problems like - auth/invalid-dynamic-link-domain - The provided dynamic link domain is not configured or authorized for the current project. - auth/unauthorized-continue-uri - Domain not whitelisted by project

Searching for information and implementing the "magic link login" I've prepared a guide on how to have this setup in react-native


回答1:


Firebase project configuration

Open the Firebase console

Prepare firebase instance (Email Link sign-in)

  1. open the Auth section.
  2. On the Sign in method tab, enable the Email/Password provider. Note that email/password sign-in must be enabled to use email link sign-in.
  3. In the same section, enable Email link (passwordless sign-in) sign-in method.
  4. On the Authorized domains tab (just bellow)
  5. Add any domains that will be used
    • For example the domain for the url from ActionCodeSettings needs to be included here

Configuring Firebase Dynamic Links

  1. For IOS - you need to have an ios app configured - Add an app or specify the following throughout the firebase console

    • Bundle ID
    • App Store ID
    • Apple Developer Team ID
  2. For Android - you just need to have an Android app configured with a package name

  3. Enable Firebase Dynamic Links - open the Dynamic Links section

    • “Firebase Auth uses Firebase Dynamic Links when sending a link that is meant to be opened in a mobile application. In order to use this feature, Dynamic Links need to be configured in the Firebase Console.”

(ios only) You can verify that your Firebase project is properly configured to use Dynamic Links in your iOS app by opening the following URL: https://your_dynamic_links_domain/apple-app-site-association

It should show something like:

{
     "applinks": {
         "apps": [],
         "details": [
             {
                 "appID": "AP_ID123.com.example.app",
                 "paths": [
                     "NOT /_/",                     "/"
                 ]
             }
         ]
     }
 }

IOS Xcode project configuration for universal links

  1. Open the Xcode project and go to the Info tab create a new URL type to be used for Dynamic Links.
  2. Enter a unique value in Identifier field and set the URL scheme field to be your bundle identifier, which is the default URL scheme used by Dynamic Links.
  3. In the Capabilities tab, enable Associated Domains and add the following to the Associated Domains list: applinks:your_dynamic_links_domain
    • (!) This should be only the domain - no https:// prefix

Android

Android doesn’t need additional configuration for default or custom domains.


Packages

A working react-native project setup with react-native-firebase is required, this is thoroughly covered in the library own documentation, here are the specific packages we used

  • Note: using the dynamicLinks package can be replaced with react-native's own Linking module and the code would be almost identical

Exact packages used:

"@react-native-firebase/app": "^6.7.1",
"@react-native-firebase/auth": "^6.7.1",
"@react-native-firebase/dynamic-links": "^6.7.1",

Sending the link to the user email

The module provides a sendSignInLinkToEmail method which accepts an email and action code configuration. Firebase sends an email with a magic link to the provided email. Following the link has different behavior depending on the action code configuration.

The example below demonstrates how you could setup such a flow within your own application:

EmailLinkSignIn.jsx
import React, { useState } from 'react';
import { Alert, AsyncStorage, Button, TextInput, View } from 'react-native';
import auth from '@react-native-firebase/auth';

const EmailLinkSignIn = () => {
  const [email, setEmail] = useState('');

  return (
    <View>
      <TextInput value={email} onChangeText={text => setEmail(text)} />
      <Button title="Send login link" onPress={() => sendSignInLink(email)} />
    </View>
  );
};

const BUNDLE_ID = 'com.example.ios';

const sendSignInLink = async (email) => {
  const actionCodeSettings = {
    handleCodeInApp: true,
    // URL must be whitelisted in the Firebase Console.
    url: 'https://www.example.com/magic-link',
    iOS: {
      bundleId: BUNDLE_ID,
    },
    android: {
      packageName: BUNDLE_ID,
      installApp: true,
      minimumVersion: '12',
    },
  };

  // Save the email for latter usage
  await AsyncStorage.setItem('emailForSignIn', email);

  await auth().sendSignInLinkToEmail(email, actionCodeSettings);

  Alert.alert(`Login link sent to ${email}`);
  /* You can also show a prompt to open the user's mailbox using 'react-native-email-link'
  * await openInbox({ title: `Login link sent to ${email}`, message: 'Open my mailbox' }); */
};

export default EmailLinkSignIn;

We're setting handleCodeInApp to true since we want the link from the email to open our app and be handled there. How to configure and handle this is described in the next section.

The url parameter in this case is a fallback in case the link is opened from a desktop or another device that does not have the app installed - they will be redirected to the provided url and it is a required parameter. It's also required to have that url's domain whitelisted from Firebase console - Authentication -> Sign in method

You can find more details on the supported options here: ActionCodeSettings

Handling the link inside the app

Native projects needs to be configured so that the app can be launched by an universal link as described above

You can use the built in Linking API from react-native or the dynamicLinks @react-native-firebase/dynamic-links to intercept and handle the link inside your app

EmailLinkHandler.jsx
import React, { useState, useEffect } from 'react';
import { ActivityIndicator, AsyncStorage, StyleSheet, Text, View } from 'react-native';
import auth from '@react-native-firebase/auth';
import dynamicLinks from '@react-native-firebase/dynamic-links';

const EmailLinkHandler = () => {
  const { loading, error } = useEmailLinkEffect();

  // Show an overlay with a loading indicator while the email link is processed
  if (loading || error) {
     return (
      <View style={styles.container}>
        {Boolean(error) && <Text>{error.message}</Text>}
        {loading && <ActivityIndicator />}
      </View>
    );
  }

  // Hide otherwise. Or show some content if you are using this as a separate screen
  return null;
};

const useEmailLinkEffect = () => {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    const handleDynamicLink = async (link) => {
      // Check and handle if the link is a email login link
      if (auth().isSignInWithEmailLink(link.url)) {
        setLoading(true);

        try {
          // use the email we saved earlier
          const email = await AsyncStorage.getItem('emailForSignIn');
          await auth().signInWithEmailLink(email, link.url);

          /* You can now navigate to your initial authenticated screen
            You can also parse the `link.url` and use the `continueurl` param to go to another screen
            The `continueurl` would be the `url` passed to the action code settings */
        }
        catch (e) {
          setError(e);
        }
        finally {
          setLoading(false);
        }
      }
    };

    const unsubscribe = dynamicLinks().onLink(handleDynamicLink);

     /* When the app is not running and is launched by a magic link the `onLink`
        method won't fire, we can handle the app being launched by a magic link like this */
    dynamicLinks().getInitialLink()
      .then(link => link && handleDynamicLink(link));

    // When the component is unmounted, remove the listener
    return () => unsubscribe();
  }, []);

  return { error, loading };
};

const styles = StyleSheet.create({
  container: {
    ...StyleSheet.absoluteFill,
    backgroundColor: 'rgba(250,250,250,0.33)',
    justifyContent: 'center',
    alignItems: 'center',
  },
});

const App = () => (
  <View>
    <EmailLinkHandler />
    <AppScreens />
  </View>
);

You can use the component in the root of your app as in this example

Or you can use it as a separate screen/route - in that case the user should be redirected to it after the sendSignInLinkToEmail action

Upon successful sign-in, any onAuthStateChanged listeners will trigger with the new authentication state of the user. The result from the signInWithEmailLink can also be used to retrieve information about the user that signed in


Testing the email login link in the simulator

  1. Have the app installed on the running simulator
  2. Go through the flow that will send the magic link to the email
  3. Go to your inbox and copy the link address
  4. Open a terminal and paste the following code
xcrun simctl openurl booted {paste_the_link_here}
  • This will start the app if it’s not running
  • It will trigger the onLink hook (if you have a listener for it like above)

References

  • Deep Linking In React Native Using Firebase Dynamic Links
  • React Native Firebase - Dynamic Links
  • React Native Firebase - auth - signInWithEmailLink
  • firebase.google.com - Passing State In Email Actions
  • firebase.google.com - Authenticate with Firebase Using Email Link in JavaScript


来源:https://stackoverflow.com/questions/61564203/how-to-setup-sendsigninlinktoemail-from-firebase-in-react-native

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!