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
Open the Firebase console
url
from ActionCodeSettings needs to be included hereFor IOS - you need to have an ios app configured - Add an app or specify the following throughout the firebase console
For Android - you just need to have an Android app configured with a package name
Enable Firebase Dynamic Links - open the Dynamic Links section
(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 /_/", "/"
]
}
]
}
}
applinks:your_dynamic_links_domain
Android doesn’t need additional configuration for default or custom domains.
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
dynamicLinks
package can be replaced with react-native's own Linking module and the code would be almost identicalExact packages used:
"@react-native-firebase/app": "^6.7.1",
"@react-native-firebase/auth": "^6.7.1",
"@react-native-firebase/dynamic-links": "^6.7.1",
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.jsximport 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
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
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
xcrun simctl openurl booted {paste_the_link_here}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With