Concepts: Learn about how Sign in with Email/Phone Number works.
Verifying email and phone number in your mobile app using our React Native SDK consists of the following steps:
Call Cotter's Login function
Setup deep linking
Receive user's email or phone number, and whether or not it's verified
Setup deep linking: Cotter's authentication will redirect back to your application using a URL scheme.
Receive the Token: Include the returned OAuth token and email/phone number in your server
Make sure you're using react-native
version < 0.63
yarn add react-native-cotter react-native-device-info rn-secure-storage react-native-randombytes react-native-camera react-native-svg react-native-securerandom buffer react-native-inappbrowser-reborn react-native-sha256npx pod-install ios
npm install --save react-native-cotter react-native-device-info rn-secure-storage react-native-randombytes react-native-camera react-native-svg react-native-securerandom buffer react-native-inappbrowser-reborn react-native-sha256npx pod-install ios
(Optional) Checkout additional steps for Android, React Native < 0.60, and Manual Installation.
Verify the user's email or phone number
Then create a new user in Cotter if successful
If you passed-in the email/phone into the function: if your user already exists, it will return an error "User already exists"
If you does not pass in the email/phone into the function: users can enter their email/phone in the pop-up browser, but it will NOT check if the user already exists. It will behave like the Log In method below.
Tip: Use the "Sign Up" method and pass in the user's email/phone to differentiate new and existing user. You can have an input text and collect the user's email/phone.
To authenticate a user based on their email.
If the user doesn't exist, this method will automatically create a new user.
Tip: Use the "Log In" method to login or register user on the same page
import { Cotter } from 'react-native-cotter';let cotter = new Cotter(API_KEY_ID); // your API_KEY_IDawait cotter.signUpWithEmailLink( // use Email & Magic Link'myexample://auth_callback', // (setup later) URL Scheme for deep linking(resp) => {console.log(resp)}, // Success Callback Function(err) => {console.log(err)}, // Error Callback Function{email: this.state.email}, // (Optional) , if you leave this blank, user can enter email in the in-app browser);
Magic Link: use cotter.signUpWithEmailLink
OTP: use cotter.signUpWithEmailOTP
Magic Link: use cotter.signInWithEmailLink
OTP: use cotter.signInWithEmailOTP
If no email is specified, the user can enter the email in the in-app browser
import { Cotter } from 'react-native-cotter';let cotter = new Cotter(API_KEY_ID); // your API_KEY_IDawait cotter.signUpWithPhoneLink( // use Phone & Magic Link'myexample://auth_callback', // (setup later) URL Scheme for deep linking(resp) => {console.log(resp)}, // Success Callback Function(err) => {console.log(err)}, // Error Callback Function{phone: this.state.phone, channel: "SMS" }, // (Optional), if you leave this blank, user can enter email in the in-app browser);
Magic Link: use cotter.signUpWithPhoneLink
OTP: use cotter.signUpWithPhoneOTP
Magic Link: use cotter.signInWithPhoneLink
OTP: use cotter.signInWithPhoneOTP
To use SMS: {phone: this.state.phone, channel: "SMS"}
To use WhatsApp: {phone: this.state.phone, channel: "WHATSAPP"}
If no phone number is specified, the user can enter the phone number in the in-app browser and there will be buttons for WhatsApp and SMS available (based on your settings in the Dashboard > Branding).
To send code/link via SMS or WhatsApp, you'll need to add some balance to you project in the Dashboard.
Try this now! You should see an in-app browser looking like the image below popping up and ask you to authenticate.
Pick a unique URL scheme for redirecting the user back to your app after the verification in the in-app browser is successful. For this example, we'll use myexample://auth_callback
.
Make sure your URL scheme (the front part before ://
) doesn't have an underscore or other special characters. To test it out, enter your Redirect URL here: https://jsfiddle.net/omd02jn5/
Add this in your android/app/src/main/AndroidManifest.xml
<activityandroid:name=".MainActivity"android:launchMode="singleTask"> <!-- Make launchMode to singleTask --><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter><!-- Setup Deep Linking Here --><intent-filter><action android:name="android.intent.action.VIEW" /><category android:name="android.intent.category.DEFAULT" /><category android:name="android.intent.category.BROWSABLE" /><!-- This is for myexample://auth_callback --><!-- 👇 Change this to your own URL scheme --><data android:scheme="myexample" android:host="auth_callback"/></intent-filter><!-- end --></activity>
Add this in your ios/<YourAppName>/Info.plist
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><!-- ADD THE LINES FROM HERE --><key>CFBundleURLTypes</key><array><dict><key>CFBundleTypeRole</key><string>Editor</string><key>CFBundleURLName</key><string>myexample</string> <!-- 👈 Change this to your own URL Scheme --><key>CFBundleURLSchemes</key><array><string>myexample</string> <!-- 👈 Change this to your own URL Scheme --></array></dict></array><!-- TO HERE --><key>CFBundleDevelopmentRegion</key><string>en</string>
If you're targeting iOS 9.x or newer, add the following lines to YourApp/ios/YourApp/AppDelegate.m:
// Add the header at the top of the file:#import <React/RCTLinkingManager.h>// Add this above `@end`:- (BOOL)application:(UIApplication *)applicationopenURL:(NSURL *)urloptions:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{return [RCTLinkingManager application:application openURL:url options:options];}
If you're targeting iOS 8.x or older, you can use the following code instead, add the following lines to YourApp/ios/YourApp/AppDelegate.m:
// Add the header at the top of the file:#import <React/RCTLinkingManager.h>// Add this above `@end`:- (BOOL)application:(UIApplication *)application openURL:(NSURL *)urlsourceApplication:(NSString *)sourceApplication annotation:(id)annotation{return [RCTLinkingManager application:application openURL:urlsourceApplication:sourceApplication annotation:annotation];}
If your app is using Universal Links, you'll need to add the following code as well, add the following lines to YourApp/ios/YourApp/AppDelegate.m:
// Add this above `@end`:- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivityrestorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler{return [RCTLinkingManager application:applicationcontinueUserActivity:userActivityrestorationHandler:restorationHandler];}
In your App.js
import { createStackNavigator } from 'react-navigation'// Import Cotter's Loading Pageimport { LoadingPage } from 'react-native-cotter';const Main = createStackNavigator({...Register: { screen: Register },// Redirect users Cotter's Handler pageCotterLoadingVerify: {screen: LoadingPage, // Use Cotter's Loading Pagepath: 'auth_callback' // Enable Deep linking redirection},})
If you have Nested Stack Navigator, add path: ''
to every parent stack.
// TARGET STACKconst RegisterStack = createStackNavigator({Register: { screen: Register },CotterLoadingVerify: {screen: LoadingPage, // Use Cotter's Loading Pagepath: 'auth_callback', // Enable Deep linking redirection},});// PARENT 1const RootStack = createStackNavigator({// ADD path: '' hereRegisterStack: { screen: RegisterStack, path: '' },...});// PARENT of PARENT 1const RootSwitch = createSwitchNavigator({Splash: { screen: Splash },// ADD path: '' hereRootStack: { screen: RootStack, path: '' },});
If you're using the newer version of React Navigation, copy paste the code below to your App.js or index.js.
In your App.js or index.js
import { NavigationContainer, useLinking } from '@react-navigation/native';function App() {const ref = React.useRef();const {getInitialState} = useLinking(ref, {prefixes: ['https://myexample.cotter.app', 'myexample://'],config: {CotterLoadingVerify: 'auth_callback', // ADD THIS TO REDIRECT TO COTTER'S HANDLER PAGE},});const [isReady, setIsReady] = React.useState(false);const [initialState, setInitialState] = React.useState();React.useEffect(() => {Promise.race([getInitialState(),new Promise(resolve =>// Timeout in 150ms if `getInitialState` doesn't resolve// Workaround for https://github.com/facebook/react-native/issues/25675setTimeout(resolve, 150)),]).catch(e => {console.error(e);}).then(state => {if (state !== undefined) {setInitialState(state);}setIsReady(true);});}, [getInitialState]);if (!isReady) {return null;}return (<NavigationContainer initialState={initialState} ref={ref}>{/* content 👈 */}</NavigationContainer>);}
In your Router
import {LoadingPage} from 'react-native-cotter';function Router() {return (<Stack.Navigator>...// Add CotterLoadingVerify page<Stack.Screenname="CotterLoadingVerify"component={LoadingPage}options={{headerShown: false}}/></Stack.Navigator>);}
Remember to make sure your callbackURL in Step 2 is correct.
Try it again! You should see the in-app browser redirecting back after you've successfully verified.
The onError
function that you pass in will receive 2 parameters: errorMessage
(string) and errorResponse
(object). The errorResponse
is an http response from attempt to verify the user's email/phone in Cotter's server.
The onSuccess
function that you pass in will receive a response
object that looks like this:
{"identifier": {"ID": "f4286df9-a923-429c-bc33-5089ffed5f68","created_at": "2020-07-21T22:53:21.211367Z","updated_at": "2020-07-21T22:53:21.211367Z","deleted_at": "0001-01-01T00:00:00Z","identifier": "putri@cotter.app", // User's email"identifier_type": "EMAIL","device_type": "BROWSER","device_name": "Mozilla/5.0 (Linux; Android 9; Android SDK built for x86 Build/PSR1.180720.075) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36","expiry": "2020-08-20T22:53:21.19705Z","timestamp": "2020-07-21T22:53:21.19705Z"},"oauth_token": {"access_token": "eyJhbGciOiJFUz...", // Validate this access token"id_token": "eyJhbGciOiJFUzI1...","refresh_token": "27944:lb31DY5pG229n...","expires_in": 3600,"token_type": "Bearer","auth_method": "OTP"},"token": {...},"user": {"ID": "643a42c7-316a-4abe-b27e-f4d0f903bfea", // Cotter uesr ID"identifier": "putri@cotter.app",...}}
This JSON object contains 3 objects, identifier
, oauth_token
and user
.
The identifier object contains information about the user's email or phone number, device type and name, and expiry.
The oauth_token
contains an access_token
that you can validate in your backend.
The user
contains the User object in Cotter, which includes a "Cotter User ID". You should associate your user with this Cotter User ID for reference.
You should include this JSON Object into your call to your backend for Login or Registration. Your backend should then verify that the access token is valid.
Checkout how to verify the OAuth Tokens from Cotter here:
Since you'll be using your API Key from a front-end website or mobile app, your API_KEY_ID
is exposed to anyone inspecting your code. Here are some ways to prevent abuse: