Verification is an essential first step in your online relationship with a user. By verifying that a new user is who they say they are, you can reduce spam and fraud on your site while ensuring the user's security.
Designing user verification involves more than just picking the right verification channel. Twilio has supported thousands of customers rolling out verification and two-factor authentication (2FA) implementations. This guide will provide recommendations for each step of the user verification process, from collecting phone numbers to account recovery.
These recommendations are written with the Twilio Verify API in mind but many will apply regardless of your verification provider.
If you're ready to start building, check out one of our Verify Quickstarts, available in a variety of programming languages for a variety of verification channels.
Verification and authentication are similar user experiences but have a few key differences in how you can design the user experience.
Verification happens when you first associate details with a customer account. This could be:
- At sign up
- When the user provides new contact information like an email address or phone number
- When the user associates a new device or browser with their account
Authentication, including two-factor authentication (2FA) or multi-factor authentication (MFA) happens during ongoing customer interactions like:
- At login
- During checkout or when making high value transactions
- On customer service calls
- Account changes like resetting a password or updating an address
The Twilio Verify API can be used to both verify and authenticate user identities and can be used for all of these customer interactions.
Like every security solution, you want to make sure that the friction you're adding isn't going to prevent the user from achieving their goals, whether that's signing up for your service or completing a transaction.
The Twilio Verify API supports:
Each channel has different benefits. For example, SMS has the highest end user adoption while TOTP is more secure and works offline. You might ask if email-based 2FA is a good idea (better than no 2FA!).
Most companies support several verification channels and then let their users decide. For example, GitHub supports TOTP, SMS, and security keys and offers even more options for account recovery.
Read more about tradeoffs between the different authentication channels supported by the Verify API.
SMS offers less security than TOTP or push authentications, but in many cases you should still leave it available as an authentication option. SMS support is built into all mobile phones and—without a separate application—tokens delivered by SMS will make it to your users. The user experience benefits of SMS still make it a popular choice for many companies. Learn more about why SMS 2FA isn't going away.
If the choice is between password-only authentication or password plus SMS, adding SMS is a clear winner.
Push authentications are the most secure channel for 2FA because they are tied to a specific device and resistant to phishing. Push also offers the ability to deny an authentication request, which can be used to detect fraud.
Push authentications are also very convenient for your users. Instead of having to open a mobile application and navigate to your website's token, push authentications present an "Approve"/"Deny" dialog within easy reach. This can be embedded directly into your application with our SDKs so it doesn't require the user to download an additional app.
Time-based one-time passwords (TOTP) are also a strong choice that provide additional security compared to SMS.
For an example user registration flow with one time passcodes, smart retry logic, and voice channel fallback, check out this Code Exchange project.
Allow customers to set authentication preferences and store those preferences for subsequent logins. This is a great way to delight your users and reduce frustrations during the authentication process. For example, landline users will want a voice call instead of an SMS. You could store preferences in your user database or use a third-party service like Segment Personas.
These channels can also be used for backup and account recovery (more on this below).
For phone or email verification use cases (as opposed to ongoing login or two-factor authentication), display the complete identifier in the interface so the user can detect any typos during the registration process. You can also introduce an intermediate step that asks the user to confirm the phone number before you send the OTP in order to catch mistakes.
Building international support for telephone numbers includes separating country code and phone number input fields in your form fields and storing phone numbers in the standard E.164 format.
If you're sending OTPs to countries that require pre-registration of sender IDs, you'll need to complete this application. Learn more about international support for Alphanumeric Sender IDs.
This topic is covered in depth in our blog post on best practices for phone number validation during new user enrollment.
You can also use Twilio's Lookup API to build an allow list of country codes in order to filter sign ups to meet compliance requirements, reduce fraud, or otherwise control your onboarding pipeline.
Here are a few additional resources on building phone number inputs and validating numbers at this stage:
- Quick Deploy: international telephone input (seen above)
Look no further than the humble
<input> element as a place to optimize the user experience. Learn more about how to design your HTML attributes to support autocomplete and more in this blog post.
To prevent abuse (and impatient users!) we always recommend building retry buffers into verification workflows. This helps prevent:
- Accidentally spamming a user with repeated text messages
- Hitting API rate limits
- Toll fraud or unnecessary spend
We suggest limiting verifications to 1 request / 30 seconds per phone number with exponential backoff. Learn more in the blog post about best practices for managing retry logic with SMS 2FA or check out this Code Exchange project with an example retry logic flow seen below.
Think about what happens when a user no longer has access to an authentication channel like a forgotten password or lost phone. Register at least one additional way to authenticate a user at sign up so that you always have a backup. Common combinations include:
- Password + email
- Email + phone number
- Authenticator app (TOTP) + backup codes
- Push authentication + phone number
Then if you're supporting two-factor authentication (2FA), add a third channel. For more recommendations, watch this talk on designing customer account recovery in a 2FA world or check out the slides.
Send a one-time password to a phone number or email address the first time a user provides it. This ensures that the user has control of the device or identity. For email, verifying a user's email address the first time they provide it is a best practice to reduce fraud, ensure deliverability, and maintain a good sending reputation. If the user is using your mobile application, register the device as a factor to be used for Verify Push.
Wait until the information has been verified to store it in your database. Alternatively, add a "verified" flag. This helps prevent typos or other unverified information from being connected to a user account.
If you don't care about verifying a piece of contact information, ask if you need to collect it at all.
Once the phone number has been verified the first time, subsequent uses should mask the phone number in order to prevent leaking PII. Unlike during initial verification, there is no option to edit a phone number for ongoing authentication in the example below. We recommend exposing 3 or 4 numbers and masking the rest like +1 (5**) ***-**67 or ********567.
Offering 2FA doesn't help secure your customers if they don't opt in to the feature. Incentives can help users who feel burdened by the security investment.
The Verify API helps you quickly build trust with the users accessing your platform and focus on your business logic.
The API supports token lengths between 4 and 10 digits with a default of 6 digits. Longer verification codes have more combinations and are harder to guess or brute force. The API has robust rate limits that counter brute forcing attempts of any token length size. You can change the token length in the Verify Service section of the Twilio Console.
The Verify API supports a standard template. The English example is:
Your <App Name> verification code is: 123456
You can override the language by sending in a
locale parameter for any of our dozens of supported languages. You can also provide a template to support use cases like do not share warnings, origin bound SMS codes, and your own verbiage.
If you already have token validation and generation logic and would like to keep those systems in place, you can do so. We have a feature where you can use your own OTP and still use our pre-screened message templates and localizations for both text and voice. Contact Twilio Sales and we'll help you enable this option.
Once generated, tokens are valid for 10 minutes. We are unable to change the timeout for token validity for your application. If your users make another request within the 10 minutes, they will receive the same token.
Rate limits are in place to help prevent fraud and protect your application and Twilio's servers. For example, we limit send attempts to the same entity (phone number or email). Our built in rate limits are sufficient for most customers, but you can also define your own rate limits. In addition, this blog post covers how to test and develop with the Verify API without getting rate limited.
With the 10 minute timeout, the majority of the delay you'll see during verification will be user input and not API requests.
SMS messages sent with Programmable Messaging, Verify, and Authy are priced per message segment.
Character limits for message segments depend on the types of characters used:
|Character set||Character limit|
|Contains only GSM characters||160 characters|
|Contains Non-GSM characters (e.g. ó and ¡)||70 characters|
When a message doesn’t fit into one segment, it’s automatically broken into two or more segments and you'll be billed for all of those segments. Therefore we recommend constructing your OTP messages to fit into one segment or be aware when it's going to take more than one. Use the segment calculator to confirm how many segments a message will result in.
The default, standard messages that Verify and Authy provide currently all fit within one message segment, except in the following circumstances:
- Messages are sent in these language locales:
- do_not_share_warning_enabled is set to
true, if appending the privacy warning results in a message that takes more than one segment, then the privacy warning won't be appended.
- psd2_enabled is set to
- Template feature is used
- Custom message feature is used
In the case of these exceptions, your specific message may still fit within one message segment, depending on parameters that affect character length like friendly_name, code_length, locale, and other customization options that you select.
Monitor based on geography to detect spikes in unchecked verifications that could indicate abuse or delivery issues.
Finally, leverage the Verify and Lookup error dictionary to handle errors appropriately in the customer application.
Now that you have all of the best practices, you can send an SMS OTP in less than 5 minutes with the Verify API with Twilio's Code Exchange. Learn more about the parameters supported in the API documentation or check out one of our quickstarts in the language of your choice.If you have questions about your implementation, please reach out. We can't wait to see what you build and secure!