Verify Push and Silent Device Approval 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:
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. We recommend starting with the "poll for the challenge" method, and then supplementing with push notifications for a better user experience. Both approaches are described below.
Once the pending Challenge has been created in the Verify API, your mobile app needs to become aware of it. This can be done by telling your user to open up your mobile app on the registered device, and then having your app check (poll) the Verify API for any pending Challenges whenever it's opened.
Polling implementation tips
You can set up the Verify Push API (technically Notify) to send a visible push notification to your mobile app whenever a pending Challenge is created. This is a great user experience as the user can see the push notification on their device's lock screen. However, this method might fail in certain scenarios like poor connectivity, the app being in a closed state, or users turning off push notifications. This is why we recommend always implementing the previous "poll for the challenge" method as a backup.
Push notification implementation tips
As shown in the screenshots below, TransferWise's implementation illustrates several of the best practices described earlier, such as instructing the user to "approve this login by opening the TransferWise app" and offering the option to "resend push on phone".
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:
No, deleting the app from the device completely unregisters the device from Verify Push.
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.
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.
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. The event will be sent only one time after the app was installed. After this, push notifications will not be sent.
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:
1"more_info": {2"bindingType": "fcm",3"primaryCorrelationId": "RU1997axxxxxxxxxxxxxxxxxx5eb0cd4cd",4"bindingSid": "BS35bc1xxxxxxxxxxxxxxxxxxa120437c1",5"providerMessageId": "RU23c27xxxxxxxxxxxxxxxxxx753723240",6"requestId": "RQ8202exxxxxxxxxxxxxxxxxx6082c6805",7"correlationIds": "[VAf510xxxxxxxxxxxxxxxxxxb8ae2e7251, test-identity, YF0314fxxxxxxxxxxxxxxxxxx1349180db, YC03b4fxxxxxxxxxxxxxxxxxx13491tf45]",8"notificationSid": "NT033xxxxxxxxxxxxxxxxxx487ed02cd34",9"module": "FCMBA",10"description": "401 http response from Fcm Service",11"isPassthrough": "false",12"deliverySid": "DA3e727xxxxxxxxxxxxxxxxxxa3647a384",13"fromReference": "CRe07eaxxxxxxxxxxxxxxxxxx59d45351c"14}
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
iOS APNs recently stopped in November 2020 sending an error, so this debugger webhook will not work for iOS anymore. An alternative solution is to create logic in your backend that looks at whether your app has been active recently and whether previously created challenges have been verified to determine whether the app is still installed or not. If not, then delete the factor. This logic can also work for Android as an additional app uninstall detection method.
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.
Sandbox
option should be checked.
Sandbox
option should be unchecked.
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.
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.
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 iOS, 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
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.
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:
https://verify.singapore.us1.twilio.com/v2/Services/%service_sid%/AccessTokens
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:
You can create a mock for the Verify API using OpenAPI specification. You should use the twilio_verify_v2
resources.
You can create a mock for your backend and use the Verify API mock you created for testing your backend. You will have a different URL or environment to use in your apps.
The SDKs communicate directly with the Verify API, so you will need to change the URL to be used in the SDKs. For this, you can create your own NetworkProvider
to intercept the SDK request and change the URL.
NetworkProvider
to change the URL, you can use the NetworkProvider SDK implementation,
NetworkAdapter
, as a guide
NetworkProvider
when building the
TwilioVerify
instance using the
Builder's networkProvider
method
NetworkProvider
to change the URL, you can use the NetworkProvider SDK implementation,
NetworkAdapter
, as a guide
NetworkProvider
when building the
TwilioVerify
instance using the
TwilioVerifyBuilder's setNewtorkProvider
method
Change the URL of your app to use the mock or the implementation calling the Verify API mock.
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.:
Possible Causes
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
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.
Test credentials are not supported for Verify Push.
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.
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.