Cotter
  • 🚀Getting Started
  • Features & Concepts
    • 💬Sign In with Email/Phone Number
    • 🔐Sign In with Device
      • How it works
    • 🧬Sign In with WebAuthn
  • 📌Quickstart Guides
    • All Guides & Tutorials
    • HTML – Sign in with Email/Phone
    • React – Sign in with Email/Phone
    • React – WebAuthn
    • ▲ Next.js
    • Angular
    • Webflow
    • Bubble.io
    • Python SDK for a CLI
    • React Native – Sign in with Device
    • iOS – Sign in with Device
    • Flutter – Sign in with Device
  • 📘SDK Reference
    • Web
      • Sign In with Email/Phone Number
        • Customize the Form
        • Checking the email or phone before sending a verification code
        • Sending Code or Link via WhatsApp
        • Styling
        • Older SDK
          • Customize the Form
      • Sign in with Social Login
        • Getting Access Tokens from Social Login Providers
        • Github Instructions
        • Google Instructions
      • Sign In with WebAuthn
        • Register WebAuthn for a logged-in user
      • Sign In with Device
        • Steps for Pop Up Authentication Prompt
        • Advanced Customization for Login Form
        • Advanced Customization for Pop Up Authentication Prompt
      • Getting Access Token and Logged-In User Info
      • Sending Successful Form Submission
      • FAQ & Troubleshooting
    • React Native
      • Installation
      • Sign In with Device
        • Add Email/Phone Verification
        • Authenticate from a Non-Trusted Device
        • Add a new Trusted Device
        • Remove Trusted Device
      • Sign In with Email/Phone Number
      • Getting Stored OAuth Tokens and User Information
      • FAQ
      • Older SDK Versions
        • Sign in with Email/Phone
        • Sending Code via WhatsApp
        • Sign In with Device
          • Authenticate from a Non-Trusted Device
          • Add a new Trusted Device
          • Customization
    • Flutter
      • Sign In with Device
        • Add Email/Phone Verification
        • Authenticate from a Non-Trusted Device
      • Sign in with Email/Phone Number
      • Getting the Logged-in User
      • Getting OAuth Tokens
      • Signing a User Out
    • iOS
      • Sign In with Email/Phone Number
      • Sign In with Device
        • Authenticate from a Non-Trusted Device
        • Push Notification
        • Check if Trusted Device is Enrolled
        • Add a New Trusted Device
        • Remove Trusted Device
      • Older Versions
        • Biometric/Pin
    • Android
      • Sign In with Device
        • Authenticate from a Non-Trusted Device
        • Check if Trusted Device is Enrolled
        • Add a new Trusted Device
        • Remove Trusted Device
        • Customization
      • Sign In with Email/Phone Number
      • Biometric/Pin
        • Advanced Methods
        • Customization
        • Setting Strings
        • Styling
      • Older SDK Version
        • Sign In with Device
          • Authenticate from a Non-Trusted Device
    • Python (for CLI)
    • API for Other Mobile Apps or CLI
      • Verify Email/Phone Number
        • Handling URL Scheme
    • Backend: Handling Response
  • 🛡️ Protecting Your Account
    • Only Allow Your Website/App to Use Your API Key
    • Rate Limit
    • Enable reCAPTCHA to Protect Against Automated Abuse
  • 🗝️ Getting Access Token
    • Cotter's OAuth 2.0 Tokens Specification
    • Getting the Tokens
      • Get Tokens during Authentication
      • Using the Refresh Token
    • Storing and Removing Tokens
    • Renewing Expired Tokens
    • Verifying JWT Tokens
    • Requesting Custom Fields on your JWT Token
    • Older API
      • Using HTTP Requests
      • Getting the Tokens
        • During Authentication
          • During Email/Phone Verification
        • During enrolling Trusted Devices
  • 🔌API Reference
    • User API
      • User Object
    • OAuth Tokens API
      • Verify JWT Token using API (serverless)
      • Requesting Custom Claims on your Access Token
      • Older API
    • OAuth Tokens from Social Login
    • Event Object
    • Reset PIN API
  • Older API
    • Validating Cotter's Identity Token
    • Validating Cotter's Event Response
Powered by GitBook
On this page
  • Overview
  • What you're building
  • Steps
  • Step 1: Import Cotter as a dependency
  • Step 2: Call Cotter's Verify function
  • Step 3: Setup Deep Linking
  • Setup in Android
  • Setup in iOS
  • Setup in React Native Project
  • Step 4: Receiving the Token in onSuccess or onError
  • Validating Cotter's Access Token
  • 🎉 You're done!
  • Securing your Project
  1. SDK Reference
  2. React Native
  3. Older SDK Versions

Sign in with Email/Phone

Our React Native SDK offers the easiest way to integrate Cotter 's email/phone verification. You can simply call a function and it does most of the heavy lifting and authentication for you.

PreviousOlder SDK VersionsNextSending Code via WhatsApp

Last updated 4 years ago

Concepts: Learn about how works.

Overview

Verifying email and phone number in your mobile app using our React Native SDK consists of the following steps:

  1. Call Cotter's Login function

  2. Setup deep linking

  3. Receive user's email or phone number, and whether or not it's verified

What you're building

Steps

Step 1: Import Cotter as a dependency

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-sha256
npx 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-sha256
npx pod-install ios

Step 2: Call Cotter's Verify function

Cotter's verify function will open a Custom Chrome Tab or ASWebAuthenticationSession in your app to authenticate the user. You have 2 choices

  1. Open the web browser with no predefined input. The user can enter email or phone in the in-app browser.

// ADD Cotter's Verify Class
import { Verify } from 'react-native-cotter';

class Register extends PureComponent {
  ...
  openCotterAuth = async () => {
    var verify = new Verify(
      'myexample://auth_callback',     // (setup later) URL Scheme for deep linking
      API_KEY_ID,                      // your API_KEY_ID
      this.onError,                    // error callback Function, receives (errorMessage, errorObject)
      this.onSuccess,                  // error callback Function, receives (errorMessage, errorObject)
    );
    await verify.openAuth('EMAIL'); // EMAIL or PHONE
    // You will need balance to send SMS. Otherwise, use "EMAIL"
  };
  onError = (errorMessage, errorObject) => {
    alert(errorMessage);
    console.log(errorObject);
  };
  onSuccess = response => {
    alert("Success");
    console.log(response);
  };
  ...
}

2. Open the web browser after the user entered their email or phone number in your app's input field

import { Verify } from 'react-native-cotter';

class Register extends PureComponent {
  ...
  openCotterAuth = async () => {
    var verify = new Verify(
      'myexample://auth_callback',     // (setup later) URL Scheme for deep linking
      API_KEY_ID,                      // your API_KEY_ID
      this.onError,                    // error callback Function, receives (errorMessage, errorObject)
      this.onSuccess,                  // error callback Function, receives (errorMessage, errorObject)
    );
    await verify.openAuthWithInput('EMAIL', this.state.email); // EMAIL or PHONE
  };
  onError = (errorMessage, errorObject) => {
    alert(errorMessage);
    console.log(errorObject);
  };
  onSuccess = response => {
    alert("Success");
    console.log(response);
  };
  ...
}

Try this now! You should see an in-app browser looking like the image below popping up and ask you to authenticate.

Send Code via WhatsApp

Step 3: Setup Deep Linking

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 .

Setup in Android

<activity
    android: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>

Setup in iOS

<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>
// Add the header at the top of the file:
#import <React/RCTLinkingManager.h>

// Add this above `@end`:
- (BOOL)application:(UIApplication *)application
   openURL:(NSURL *)url
   options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
  return [RCTLinkingManager application:application openURL:url options:options];
}
// Add the header at the top of the file:
#import <React/RCTLinkingManager.h>

// Add this above `@end`:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
  return [RCTLinkingManager application:application openURL:url
                      sourceApplication:sourceApplication annotation:annotation];
}
// Add this above `@end`:
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
 restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
 return [RCTLinkingManager application:application
                  continueUserActivity:userActivity
                    restorationHandler:restorationHandler];
}

Setup in React Native Project

In your App.js

import { createStackNavigator } from 'react-navigation'

// Import Cotter's Loading Page
import { LoadingPage } from 'react-native-cotter';
 
const Main = createStackNavigator(
  {
    ...
    Register: { screen: Register },
    
    // Redirect users Cotter's Handler page
    CotterLoadingVerify: { 
      screen: LoadingPage, // Use Cotter's Loading Page
      path: 'auth_callback' // Enable Deep linking redirection
    },
    
  }
)

If you have Nested Stack Navigator, add path: '' to every parent stack.

// TARGET STACK
const RegisterStack = createStackNavigator(
  {
    Register: { screen: Register },
    CotterLoadingVerify: {
      screen: LoadingPage, // Use Cotter's Loading Page
      path: 'auth_callback', // Enable Deep linking redirection
    },
  }
);

// PARENT 1
const RootStack = createStackNavigator(
  {
    // ADD path: '' here
    RegisterStack: { screen: RegisterStack, path: '' },
    ...
  }
);

// PARENT of PARENT 1
const RootSwitch = createSwitchNavigator(
  {
    Splash: { screen: Splash },
    // ADD path: '' here
    RootStack: { screen: RootStack, path: '' },
  }
);

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/25675
        setTimeout(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.Screen
        name="CotterLoadingVerify"
        component={LoadingPage}
        options={{headerShown: false}}
      />
      
    </Stack.Navigator>
  );
}

Try it again! You should see the in-app browser redirecting back after you've successfully verified.

Step 4: Receiving the Token in onSuccess or onError

onError

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.

onSuccess

The onSuccess function that you pass in will receive a response object that looks like this:

{
  "identifier": {
    "ID": "3e61e1e9-3528-48d7-a7a2-b985141f4d67",
    "created_at": "2020-02-15T03:45:25.656423Z",
    "update_at": "2020-02-19T06:55:19.121863Z",
    "deleted_at": null,
    "identifier": "+12345678910",
    "identifier_type": "PHONE",
    "public_key": "hU1ZOLxyfq548Vh45TcOlqHug/WHqVJfoxApgq8Wfks=",
    "device_type": "BROWSER",
    "device_name": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.100 Safari/537.36",
    "expiry": "2020-03-20T06:55:19.121783Z"
  },
  "token": {
    "identifier": "+12345678910",
    "identifier_type": "PHONE",
    "receiver": "<your API_KEY_ID>",
    "expire_at": "1584687591",
    "signature": "G8dOKR6qLj+GiB0pD2aggVVdYddFoyy..."
  }
}

This JSON object contains 2 objects, identifier and token .

  • The identifier object contains information about the user's email or phone number, device type and name, and expiry.

  • The token contains the user's phone number, your API_KEY_ID in the receiver field, and a signature to ensure this is from Cotter. The token tells you that this identifier is verified.

For example, if you have an existing Register function:

class Register extends PureComponent {
  ...
  // YOUR BUTTON SHOULD INVOKE openCotterAuth ON PRESS
  openCotterAuth = async () => {
    var verify = new Verify(
      'myexample://auth_callback',     // (setup later) URL Scheme for deep linking
      API_KEY_ID,                      // your API_KEY_ID
      this.onError,                    // error callback Function, receives (errorMessage, errorObject)
      this.onSuccess,                  // error callback Function, receives (errorMessage, errorObject)
    );
    await verify.openAuthWithInput("EMAIL", this.state.email); // EMAIL or PHONE
    // You will need balance to send SMS. Otherwise, use "EMAIL"
  };

  onError = (errorMessage, errorObject) => {
    alert(errorMessage);
    console.log(errorObject);
  };
  
  onSuccess = response => {
    this.submitRegister(response.identifier.identifier, response.token);
  };

  // YOUR Register API post email and token
  submitRegister = (email, token) => {
    axios
      .post(
        "https://example.com/user/register",
        { email: email, token: token }, // SEND Cotter's token to your backend
        false
      )
      .then(response => {
        ...
        this.props.navigation.navigate("Dashboard");
      })
      .catch(error => {});
  };
  ...
}

Validating Cotter's Access Token

Checkout how to verify the OAuth Tokens from Cotter here:

🎉 You're done!

Securing your Project

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:

: This function will handle the WebView, verifying phone number or email, and request the identity from Cotter's server.

: Cotter's authentication will redirect back to your application using a URL scheme.

: Include the returned token and email/phone number in your server

(Optional) Checkout additional steps .

Instead of using SMS, you can also

Add this in your

Add this in your

If you're targeting iOS 9.x or newer, add the following lines to :

If you're targeting iOS 8.x or older, you can use the following code instead, add the following lines to :

If your app is using Universal Links, you'll need to add the following code as well, add the following lines to :

If you're using the , copy paste the code below to your App.js or index.js.

Remember to make sure your is correct.

You should include this JSON Object into your call to your backend for Login or Registration. Your backend should then verify that the is valid.

📘
Import Cotter as a dependency
Call Cotter's Verify function
Setup deep linking
Receive the Token
for Android, React Native < 0.60, and Manual Installation
send the verification code via WhatsApp.
AndroidManifest.xml
Info.plist
YourApp/ios/YourApp/AppDelegate.m
YourApp/ios/YourApp/AppDelegate.m
YourApp/ios/YourApp/AppDelegate.m
newer version of React Navigation
callbackURL in Step 2
signature of the token
Verifying JWT Tokens
Only allow your website/app to use your API Key
Rate Limit the number of authentication requests
Enable reCAPTCHA to prevent automated abuse
Sign in with Email/Phone Number
Cotter's React Native SDK on Android and iOS