Menu

Expand
Rate this page:

Verify Push Best Practices for Production use

Purpose

Verify Push is designed for global, web-scale use. The Twilio Verify platform that it's built on verifies over 200 million users annually. To fully realize the benefits of Verify Push in your own real-world production implementation, we've compiled a running list of best practices to consider. These best practices are organized as Q&A under these topics:

  1. Conversion Rate

  2. Security

  3. Client App

  4. Web Client SDK Security

  5. Performance

  6. Project Management

  7. Common Issues

Conversion Rate

1. What are methods to ensure that the device receives the challenge?

A critical step in the Verify Push verification sequence is for the app on the registered device and the user to be made aware that a pending challenge has been created by the customer backend/Verify Push API. The basic method for achieving this is through the Verify Push API (technically Notify) sending a visible push notification to the app. However, this method might fail in certain scenarios like poor connectivity, the app being in a closed state, or users turning off push notifications. For production use, we suggest implementing additional methods to robustly handle all scenarios:

Basic methods that address common scenarios
  1. Configure app to receive push notifications, including background notifications that can still be received by the app even if the user has disabled visible push notifications when the app is in foreground.
  2. If the app is closed when it receives the push notification, it should attempt to store the challenge_sid and factor_sid contained in the push notification's payload, so that it can immediately poll the Verify Push API with that data when it’s next opened.
  3. The app should poll for pending challenges whenever it’s opened, in case it wasn’t able to receive/store a push notification that was sent when it was closed.
  4. Tell the user to open the app on the registered device to view the push approval, in case they didn't see a visible push notification.
  5. Give the user the option to request another push if they didn't get the first one. This can be done by creating a new challenge. The app should have logic to de-duplicate challenges that are approving the same action (don’t show the same approval twice). For example, the app can check in the customer backend if the challenge is still valid for the action to be approved. The customer backend can store the challenge_sid after creating it.
  6. Offer the user fall-back verification options if available.
Example of methods 4-6 in Transferwise's UI

Screen Shot 2020-10-07 at 11.15.27 AM.jpg

Screen Shot 2020-10-07 at 11.15.35 AM.jpg

Additional methods

In addition to the basic methods, consider these additional ones:

  1. Nudge the user to enable visible push notifications after they register their device, so that they will see a push notification on the lock screen of their device.
  2. Have the app send a confirmation to the customer backend when it receives a push notification from Verify Push (Notify). If the customer backend doesn’t receive a confirmation from the app after an expected latency from when the challenge was created, then the customer backend should assume that the push notification failed and create a new challenge.
  3. Customer backend should subscribe to debugger webhooks for the Verify Service. These webhooks contain error codes published by Verify Push, including errors related to push notification failures.
  4. Display a button in the app for the user to “check pending push approval requests”. When the user taps the button, the app polls for a list of pending challenges and displays them.

2. In which countries does it work?

Unlike SMS, which has country-specific constraints due to Carriers being country-specific, Verify Push works whenever there’s an internet/data connection and on any device that runs standard iOS, Android, or a supported web browser. The exceptions to this that we are aware of are:

  • Android devices built by Huawei that don’t support Google Messaging Services, including Firebase Cloud Messaging, won’t be able to receive push notifications. However there are workarounds to this as explained in “what are methods to ensure that the device receives the challenge?
  • Country prohibitions defined in Twilio’s general export control policy (e.g. Iran)

Security

1. If a user installs the app on their device, registers the device, deletes the app, and then reinstalls it on the same device, will the device become registered again?

No, deleting the app from the device completely unregisters the device from Verify Push.

2. How do I support multiple devices per user?

From a technical perspective, a user can register multiple devices as factors. From a security policy perspective, the decision of whether to allow a user to enroll more than one device as a factor is up to you. The benefit of doing so is that it makes it more convenient for the user to respond to a push from multiple devices and it creates redundancy if they were to lose one device. The downside is that it increases the attack surface for a fraudster. Note that querying the SDK on an enrolled device will only return the factor(s) created on the same device, so a fraudster wouldn’t be able to discover all of a user’s registered device.

3. Can the user receive/approve a push if they aren’t logged into our app

You can configure Verify Push such that the user can receive/approve a push in the app on the registered device, even if they aren’t logged into their account on that app. Conversely, you can require that they login first (using a different verification) before approving the push.

Client App

1. How do I know if the user uninstalls my app?

When the app is uninstalled, if you send a challenge to a user, your backend will receive an OK about creating the challenge, but your Twilio debugger will receive an error because the push notification couldn't be sent:

You can add a webhook for Twilio debugger and you will receive an event when this error happens.

You can identify the factor, entity and service sid related to the error. The Payload.more_info will contain the values in the correlationIds field:

"more_info": {
 "bindingType": "fcm",
 "primaryCorrelationId": "RU1997axxxxxxxxxxxxxxxxxx5eb0cd4cd",
 "bindingSid": "BS35bc1xxxxxxxxxxxxxxxxxxa120437c1",
 "providerMessageId": "RU23c27xxxxxxxxxxxxxxxxxx753723240",
 "requestId": "RQ8202exxxxxxxxxxxxxxxxxx6082c6805",
 "correlationIds": "[VAf510xxxxxxxxxxxxxxxxxxb8ae2e7251, test-identity, YF0314fxxxxxxxxxxxxxxxxxx1349180db, YC03b4fxxxxxxxxxxxxxxxxxx13491tf45]",
 "notificationSid": "NT033xxxxxxxxxxxxxxxxxx487ed02cd34",
 "module": "FCMBA",
 "description": "401 http response from Fcm Service",
 "isPassthrough": "false",
 "deliverySid": "DA3e727xxxxxxxxxxxxxxxxxxa3647a384",
 "fromReference": "CRe07eaxxxxxxxxxxxxxxxxxx59d45351c"
}

You can get the factor sid from the correlationIds field, and delete the factor in the verify push backend from your backend.

Keep in mind

  • There is not a specific order of the correlationIds values. So you will not always receive them in that order.
  • The debugger events cannot be filtered by verify service sid as verify webhooks. The debugger webhooks are configured for your account, but you will receive the verify service in the correlationIds field.
  • If you remove your app from your device and then send a push notification to it, you should expect to receive the uninstalled app error. However, if this was the last push-enabled app on the device (e.g. development signed iOS apps), it will not show up in the Twilio debugger. This is because deleting the last app tears down the persistent connection to the push service before the notice of the deletion can be sent. You can work around this by leaving at least one push-enabled app on the device in order to keep the persistent connection up.
    • To keep the persistent connection to the production environment up, just install any free push-enabled app from the App Store and you should then be able to delete your app and see it appear in the Twilio debugger webhook.
    • To keep the persistent connection to the sandbox environment up, install another development push-enabled app.
  • For iOS, Apple has implemented changes to APN and receiving the uninstalled app event could take over a week. Apple has stated that this is an intentional change for privacy reasons.

2. How do I handle different dev environments?

We recommend creating different Verify Services for each environment (e.g. one for testing, one for production). Also, take into account that iOS uses different APN environments according to the signing certificate.

  • For development, you should use an 'Apple Push Notification service SSL (Sandbox)' certificate or an 'Apple Push Notification service SSL (Sandbox & Production)' certificate, and your push credential's Sandbox option should be checked.
  • For production, you should use an 'Apple Push Notification service SSL (Sandbox & Production)' certificate,
  • and your push credential's Sandbox option should be unchecked.
  • It is better to use a different push credential for each verify service per environment

3. How do I support user language preferences?

Verify push receives the message and details that could be shown to the user (depends on your implementation). We recommend using the user language preference for your app to send the message and details in the correct language. For example, if your user language in your app is French, you should send the challenge's message and details in French.

4. How do I handle users who disable push notification for my app?

Some users may choose to disable push notifications from your app in their OS settings. This just means that the user won't see the notification in the OS's notifications drawer/center. However, APNs and FCM will still work behind-the-scenes. Pushes will still be delivered directly to your app, if it's in the foreground. Specifically:

For Android, if notifications are disabled, your user won't see a notification outside of your app, but you will still receive the push in your app if it is in foreground and the push token won't change.

For iOS, if notifications are disabled, the system delivers all remote notifications to your app silently so you will receive the push if it is in foreground in the method userNotificationCenter(_:willPresent:withCompletionHandler:). Getting the device token will depend on your implementation. For example, if you call registerForRemoteNotifications only if notification permission is enabled, you won't get a device token, see sample app.

5. How do I get the push token?

You will need the device push token to create factors.

For Android, you should get the push token before creating a factor and validate your app has a value for it. Getting a registration token can fail, and you will receive an exception.

For Android, you should get a push token before creating a factor and validate your app has a value for it. Getting a device token can fail, and you will receive a call for the method application(_:didFailToRegisterForRemoteNotificationsWithError:)

Take into account that the device/registration token could change, so the app should identify this case and update all the factors in the device, for reference: updated push token for Android and updated push token for iOS

6. How do I de-duplicate challenges that are approving the same action?

Your backend can generate an action_id that is unique to the verification action that needs to be approved by your user, and provide it in the HiddenDetails property of the Challenge. The HiddenDetails value of a Challenge is visible to the mobile client and can be used to de-dup Challenges with the same action_id without querying the your customer backend.

However, your mobile client will still need to query your backend to find if a given Challenge and associated action_id was approved, especially if the user has the option of simultaneously verifying the same action via another verification method, like SMS OTP.

Web Client SDK Security

1. How is the private key and factor information stored?

As with all of Verify Push, the Web Client SDK uses public-private key cryptography to turn a browser installed on a device into a push factor for a given service/entity. When a browser installation is registered as a factor, a unique keypair is generated. Therefore, two different browser installations (e.g. Chrome and Edge browser installed on a Mac) will be registered as two factors. As shown in the Sample App screenshot, the keypair is stored in the browser’s IndexedDB, and the private key is set to “extractable: false”. In addition to the keypair, a separate local encryption key is also stored in the IndexedDB and set to “extractable: false”:

web client sdk indexedDB.png

This Sample App screenshot also shows the factor information stored in the browser’s localStorage. This factor information is first encrypted by the local encryption key before storage:

web client sdk local storage.png

2. How could the factor be removed by the end-user without going through my app?

An end-user who somehow clears their browser’s localStorage and/or IndexedDB will delete the factor information and keypair, and therefore won’t be able to respond to challenges in the future. They will need to re-register the browser installation as a new factor. Clearing of the localStorage/IndexedDB can happen if the browser is uninstalled, if it’s directly cleared via a browser’s developer tools, or if it’s indirectly cleared via a setting like Chrome’s clear “cookies and other site data.” If the localStorage/IndexedDB has been cleared, the Verify Push API will respond with an Error 52103 after a create challenge request is made, and the end-user can be directed to try an alternate verification method. An app can also periodically check whether the localStorage/IndexedDB has been cleared, by calling the SDK method to get all factors (TwilioVerify.getAllFactors) to see if a factor exists for the current browser installation. If not, then it can re-register the browser installation as a new factor.

3. What if my end-user stores their account’s password using a password manager that has a browser extension (e.g. 1Password)? Would using Web Client SDK still be considered an additional auth factor?

Passwords are considered a “what you know” factor, whereas Verify Push is a “what you have” factor. So requiring a user to pass both types of authentication would qualify as two-factor authentication. Even though password managers can convert a “what you know” factor into a “what you have” factor temporarily, they generally still require that the user periodically authenticate themselves with a master password or biometric to unlock the password manager. A password can also be stolen/phished/copied/reused across different devices and applications, whereas the private key of the Web Client SDK doesn’t leave the browser installation and is unique to an application.

Performance

1. What is the expected latency for API responses?

The overall Verify API SLA for the latency of responses to requests is 300ms. This is measuring the time from when the request is received by the Verify API to when it sends the response. A different latency measure is the round-trip-time (RTT) latency, which is measured from when the request is sent by the requester to when the requester receives the response from the Verify API. RTT latency will be longer than the responses-to-requests latency, and will vary depending on the physical distance of the requester to Verify API’s servers, which are located in the US East Coast by default. If you want to reduce RTT latency, try two things:

  1. Try to reduce the overall number of requests you’re making to the Verify API. While this won’t reduce the RTT of an individual request, it will reduce the overall latency experienced by your users. One example optimization: when you’re registering a new user and device, you don’t need to make a separate Create Entity call, because the Create Factor call will both create an Entity and a Factor at the same time.
  2. Send your requests to a public Edge Location that is physically closer to where you’re requesting from compared to the default US East Coast location. While Verify API does not fully support Edge Locations currently, RTT latency can still be lowered, because the shared Twilio API gateway services that Verify uses supports Edge Locations. Note that using Edge Locations might actually increase latencies when reusing connections, and so you’ll need to try and see if this is acceptable. You can switch to an Edge Location by changing the request URL. For example, to send to the Singapore edge, the request AccessTokens URL should be: https://verify.singapore.us1.twilio.com/v2/Services/%service_sid%/AccessTokens

Project Management

1. How much work is it to implement Verify Push?

Your mileage may vary. We’ve consistently heard that understanding Verify Push is the easy part. The complexity level of your existing apps/backend (e.g. how many places in your UX do you need to insert Verify Push?) is the major driver of the overall amount of work. As general guidance, we suggest budgeting the following amount of time based on feedback from customers who’ve done it:

  • Setting up the Verify Push Sample App/Backend and understanding how Verify Push works in general takes 1-3 days.
  • Integrating Verify Push as a prototype into your own app(s), backend, and existing login flows takes 1-2 weeks.
  • Getting to production-grade, including testing, could take an additional couple weeks.

Common Issues

1. Pushes not arriving?

The Challenge will be created, so to troubleshoot the issue, start by checking your Twilio debugger to get the error code. Then visit Twilio error codes to understand the issue and possible solutions, e.g.:

  • Error code 52143: Application device token and certificate subject must have the same bundle id

2. Getting an Invalid APNs device token (Error code 52134) for iOS?

Possible Causes

  • APNs device token format is invalid.
  • Trying to use a development certificate for a production application or vice-versa.

For development signing certificates, e.g. running your app from xcode with debug build configuration or debugging application, you will need to enable the Sandbox option for your push credential

For distribution signing certificates, e.g. archiving app or running the release build configuration, you will need to disable the Sandbox option for your push credential

3. How do I get notified when a challenge was received by my app?

As the push notification implementation is handled by your app, only your app will know when the push notification is received. Your Verify webhook will only receive challenge.approved and challenge.denied events for Challenges, so your backend should provide a way to be notified that a notification for a challenge was received from your app.

4. Using test credentials?

Test credentials are not supported for Verify Push.

5. Getting fewer factors than expected for a user from the SDK?

The SDK will return the factors stored in the device, so if you call getAllFactors method, you will get only the factors in the device (e.g. 2 factors), and if you have another device (e.g. 3 factors), the user will have 5 factors, but each device will return only the factors stored in the device.

6. Factor deletion or TwilioVerify initialization throwing an error?

The SDK uses Keychain to save the information in a secure way, so Keychain operations could throw an error, for example when deleting a factor (Keychain delete operation) and TwilioVerify initialization (migrating information from one version to a new one). You should implement an alternative flow in case of an error.

Rate this page:

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.

        
        
        

        Thank you for your feedback!

        We are always striving to improve our documentation quality, and your feedback is valuable to us. How could this documentation serve you better?

        Sending your feedback...
        🎉 Thank you for your feedback!
        Something went wrong. Please try again.

        Thanks for your feedback!

        Refer us and get $10 in 3 simple steps!

        Step 1

        Get link

        Get a free personal referral link here

        Step 2

        Give $10

        Your user signs up and upgrade using link

        Step 3

        Get $10

        1,250 free SMSes
        OR 1,000 free voice mins
        OR 12,000 chats
        OR more