Add silent device approval with Twilio Verify and React Native
Time to read: 7 minutes
What if you could provide ongoing authentication for your users without requiring a password or sending them a one-time passcode? With Twilio's Verify API, you can!
The Verify API includes a powerful open-source client library (SDK) for turning devices into secure keys. This allows your application to register trusted devices and use them as strong, phishing resistant authenticators. When the authentication is done on the registered device, everything can happen silently in the background without any user involvement. This lowers friction, increases usability, and still provides strong security.
Here's the flow you’ll be building in this tutorial:
- User is registered/authenticated (using SMS verification in our example, but could be username/password)
- Device is registered as a secure key ("Factor")
- User attempts to login
- Application silently authenticates user ("Challenge")
Device approval uses a similar workflow to push authentication but does not require any push notifications since this version happens in the background. This tutorial does not cover the Push Notification component, though you can absolutely enable that if you choose to do so.
The completed project is available on my GitHub if you want to skip ahead.
Prerequisites for building silent device approval
To code along with this post you'll need:
- Node.js 14+
- The
yarn
package manager - A free Twilio account; sign into an existing account or sign up here
- A Verify Service which you can create in the console
Set up your development environment
Set up the React Native CLI
For this tutorial you only need to set up one target operating system (Android or iOS). Follow the instructions under the React Native CLI Quickstart tab for your Development OS and Target OS of choice. Stop before "creating a new application".
Deploy two apps from Code Exchange
Before continuing, you’ll need a Verify Push sample backend, which you can deploy from our code exchange in a few clicks. Use the default "hash" value for identity processing, this will obfuscate any PII. To complete this step, you’ll need the Service SID from your Verify Service.
You'll also need to deploy this One-Time Passcode Verification app from Code Exchange in order for the phone verification piece to function. This app will use the same Verify Service SID. After deploying, click Go to live application, which will open a new tab in your browser. Keep this open for now.
Clone the starter application
You’ll need an application to build silent approval into and you can either use:
- An existing application
- The starter application based on the phone verification built in this blog post
If you already have an application to add silent authorization to, you can skip to the next step. If you don’t, keep reading to get the pre-built starter application.
In your terminal, navigate to a suitable working directory and run the following command:
Next, install the dependencies with (npx pod-install is only required for iOS targets):
Open the folder you created with the above commands, verify-push-silent-auth-react-native. In this folder you will see a file called .env.example. Change the name of the file to just .env (remove the .example extension).
Open your .env file in your favorite text editor and look for the following highlighted line:
Find your base URL from the One-Time Passcode app you deployed from Code Exchange. It will be the first part of the URL of the live application. It should look like https://verify-XXXX-bohzzb.twil.io.
Add this BASE_URL
to your .env file (described in detail here).
Test your application
Test your application by running either yarn ios
or yarn android
, depending on your preferred target OS. If you run into any issues there are more details about building and running the app in this blog post.
How to register a device as a secure key: Verify Factors
The first thing you need to do is register the device. You can do this with the Verify Push client library, which will generate a key-pair on the device and send the public key to Twilio so you can just use the API instead of doing your own key management.
You do this by registering a Factor.
In the starter application that you cloned, open up src/screens/RegisterPush.tsx. This is the screen you’ll show once someone has signed up or authenticated and you trust them enough to let them register the device as a secure key. Good times to do this include at sign up or after login.
Replace the contents of the existing RegisterPush
component with the following code:
This will render the following screen:
Hash identity to obfuscate PII
Next you need to actually handle when the user clicks Yes, use this device. Open up src/api/verify.js. You’re going to fill in the createFactor()
function with the following steps:
This code uses the user’s phone number as the basis for the identity so you’ll want to obfuscate that. At the top of the file, right below the exists import
lines, import the sha256
method:
Then add the following code inside the createFactor()
function:
Create Factor
The documentation shows you how to create a Factor and explains that you’ll need the following parameters:
factorName
- ✅
verifyServiceSid
- ✅
identity
pushToken
accessToken
You already have #2 and #3.
The Factor name can be any string but you can also use the react-native-device-info
library to grab the Device Name (like "Kelley's iPhone 12"). Import the library (it should already be installed if you're using the starter project, otherwise follow the installation instructions):
Add the following to the createFactor()
function:
This will take care of both the factorName
and the pushToken
. The last thing you need is an access token to communicate with Twilio's API from the device.
If you haven't already, deploy this Verify Push Backend using your Verify Service SID. Open up your .env
file and add the PUSH_BACKEND_URL
.
Add the following inside the createFactor()
function after hashing the identity:
At this point, you have everything we need to create the factor.
Add the Twilio Verify Push React Native Client Library (SDK)
From the terminal, install the Verify Push SDK:
If your target is iOS also install the Pods:
Back in verify.js, import the components you need to create a Factor:
Add the following code to the createFactor()
function:
Finally, immediately verify the Factor and store the Factor SID for future reference.
Here's what the final createFactor()
function will look like:
Trigger device registration
Back in the RegisterPush.tsx file, update the Yes, use this device button to call your new createFactor()
function.
Import the function:
Replace the onPress()
method (inside the TouchableOpacity
component right below the "Whenever there's a new login" message) with the following code:
Finally, in src/screens/Otp.tsx update the navigation to prompt for the device registration where it has the note // TODO - add a step to allow user to register device as a secure key
:
At this point you can test out the Factor creation. Make sure you source your .env file to pick up new variables and restart the application with yarn ios
or yarn android
. Complete the phone verification and you should be able to click Yes, use this device and be rerouted to the banking image. Potential errors should be logged in the Metro window to help you debug any issues.
Silently authorize future logins
Now that the device is registered, you can use the device like a key instead of sending an SMS OTP or requiring a password.
This section will build the functionality behind the Login button on the welcome screen.
In src/screens/Welcome.tsx, look inside the Welcome()
component function for the line that says // TODO add silent authorization
. It should be somewhere around line 21. Replace this comment with the following navigation:
Then head over to /src/api/verify.js to write your function to issue a Challenge. A Challenge is the Verify API's way of tracking a verification attempt. The client library will talk to the Verify API with your registered Factor to validate that the device is valid. Since you’re doing this all from the device, it can happen seamlessly in the background, hence the "silent" in silent authorization.
There are 4 steps to complete the silent authorization:
- Get identity from storage
- Create new challenge
- Immediately verify challenge
- Check challenge status to validate
Each of these steps will be described in the following sections.
Get identity from storage
The silentAuthorization()
function expects the factorSid
to be passed in, so you only need to fetch the identity from storage in order to create the challenge.
Inside of the try
block in the silentAuthorization()
function, add the following code in place of the TODO
comments:
Create new challenge
You also need the endpoint for creating a challenge. Fortunately the backend you used for the Access Token endpoint includes one. Create a challenge by calling the endpoint after you defined the data. Immediately after the code you added in the previous step, add the following:
Immediately verify challenge
First, import the necessary components. At the top of the same verify.js file, edit your imports to add the following after VerifyPushFactorPayload
:
Add the following code to the end of the try
block in the silentAuthorization()
function, below the code you added in the previous steps, to "update" the challenge - this is what will do the validation.
Check challenge status to validate
Finally, check the status to make sure it's approved and return the result:
Trigger silent authorization at login
Head over to /src/screens/Verifying.tsx to build the authorization check. There's some boilerplate for the component to give the user an idea about what's happening.
You’ll be using a React Hook to trigger the verification on page load since you’re not requiring the user to click any more buttons.
Replace the // TODO
with the following code:
The isFocused
helper from the navigation library is necessary to tell the component there was a state change on page load and trigger the useEffect
hook.
Reload the application and try clicking Login. You should briefly see the verification screen. Because it happens so fast you might consider building in a timeout to display the message to the user for a minimum of 1 or 2 seconds.
What about Push Notifications?
You used the Verify Push API to build this demo but didn't actually do anything with push notifications. You absolutely can add that and use the mobile device as a key for desktop logins, call center authentication, and more. Learn more about how to enable push notifications in the documentation.
One of the challenges with device authorization like this is how to manage account recovery: what happens when the end user loses their device? More developers are seeing the value of Push as a first level of frictionless defense and then will fallback to other channels like one-time passwords if the device is unavailable. The Verify API offers many channels for fallback.
If you have any questions about building with Verify Push or pricing, please get in touch. I can't wait to see what you build and secure!
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.