How to capture and verify user’s phone number using Auth0 Actions
For various scenarios, a business might need to record & verify a user’s phone number before they can provide a service.
This example demonstrates how you can capture and verify the user’s phone number as part of Sign up (First login) using Auth0 Actions.
Auth0 Actions are secure, tenant-specific, versioned functions written in Node.js that execute at certain points during the Auth0 runtime. Actions are used to customize and extend Auth0’s capabilities with custom logic. auth0.com/docs/customize/actions
Here is a diagram showing how the solution works.
If you are looking for Multi-Factor Authentication using SMS , it’s supported out of the box with Auth0. This solution is just a suggestion to get around the mobile verification issue. I found some users on the Auth0 forum asking for this feature so I decided to see if I can use Auth0 Actions to provide a solution.
The solution brekdown
We need the following pieces to make this flow work:
A Twilio account. Twillio provides the APIs that we need to send the verification SMS and also to verify the code after the user submits it.
Custom signup form with an extra field to record the user’s phone number.
Auth0 Action that will execute on login and make use of the recorded phone number to send a verification code to the user’s device using SMS. This Action is also responsible for the redirect to the code verification form.
A simple web application that will host the form to get the verification code from the user and redirect the user along with the code to Auth0 to finish the login.
1- Create a Twilio account and the verification service
To create an account go to https://www.twilio.com/try-twilio and create a free account.
After login, click on the verify from the side menu. This is where we can add a verification service. This service will help us to send an SMS to the user phone number and use the code in that SMS for verifying the number.
Click Verify -> Try it out and create a new service.
In the second and third steps, you get a chance to test your newly created service in the console. This helps you to verify the URL you need to call and the parameters you need to pass for the payload. After you have tested your new service and you are happy that it all works, we are done with the Twillio setup.
If you need to see your service id at any later stage you can come back to verify and it will be listed under services.
2- Create a signup form with an extra field to record phone number
There are multiple ways you can customise your login/signup form. In this example, I am using the Auth0 lock and passing the configuration for extra fields.
To learn more about other ways you can customise the signup experience check this page.
This is the configuration you can pass to the Auth0 lock to add an extra field.
And You will get a signup form like this:
Now after the user signs up, the phone number will be added to the user profile under the
At this stage, we have not verified the phone number yet.
3- Create a Login Action to verify the phone number
Next step we need a login Action to read the phone number from the user profile and send a verification SMS to the user’s phone number.
Among the Auth0 Action triggers Login is the only one that supports redirect which is what we need for this flow. Since the phone number verification happens only once users will only go through it the first time they log in.
For the subsequent logins, the Action will check if the phone number exists and is verified for a particular user and if so it will just ignore the rest.
To start you need an Auth0 account. If you don’t already have one, follow these instructions for setting up one.
To create the login Action Click on the Actions > Flows > Login
This creates a
post-login trigger that runs as part of the Login flow.
It is executed after a user logs in and when a Refresh Token is requested.
Click on the
+ button in Add Action and select Build Custom. Call it Verify phone number and leave the rest as is.
After Creation, you come to the edit screen. Here you can edit the code and write the logic to call Twilio APIs to send a verification code and verify it.
To do this we need to write two separate functions.
onExecutePostLogin — Handler that will be called during the execution of a PostLogin flow.
onContinuePostLogin — Handler that will be invoked when this Action is resuming after an external redirect.
onExecutePostLogin function Code is simply reading the phone number from the user
user_metadata and sending an SMS to the phone number using Twilio REST API.
After sending the SMS successfully, this function will redirect the user to the webform to enter the verification code we just sent them. This webform is simply a web application that you need to create and host yourself.
It doesn't need to be anything fancy, as long as it can get the verification code and redirect the user back to Auth0.
onContinuePostLogin comes into play after the user is redirected back to Auth0. At this point, you will have the verification code sent to the function from the webform using a redirect.
So we can use the code and call another REST API from Twilio to verify it.
If all goes well and you get a successful response from Twillio the phone number is verified and we will add this information to the user profile but this time under the
user_metadata can be edited by the logged-in user but the user cannot edit app_metadata.
Here is the code for the Action.
4- Webform to get verification code & perform redirect
While you’re in the same directory as the
index.html, simply run the following command to spin it up in Vercel:
Press enter for each prompt the
vercel command gives you to select the defaults. The output of this command will contain the URL of your newly hosted code verification form.
- In your Action’s code be sure to delete the existing VERIFY_FORM_URL and replace it with the value that is the URL that was output in the previous step.
- If you want to make changes to the code verification form, you can upload a new version simply by running the same vercel command you did before.
Here is the code for this web application.
There you have an end-to-end solution to verify phone numbers as part of your Auth0 login and account creation.
There are more things to consider to make this a production-ready solution.
Error handling You need to consider and handle different errors that can happen. The example Action code makes use of
api.access.deny()to reject the login in case an error happens.
Setting up different environments(tenants) for different stages When you set up Auth0 tenant or Twilio service you need to separate your dev and prod environments.
Keeping your Secret(API) keys safe All the secrets used in this solution only exist on the server-side of the code (action.js and verify.js) which makes it easier to keep them safe. Make sure you do not expose the sensitive keys in your client-side code or commit them to your repo.
Actions have secret management built-in to keep your secrets safe and provide a convenient way to access them in your action code.
and you can access them like this
Trusted Callback URL (quoting from Dylan Swartz example ) Our sample Action and consent form makes one security compromise for the sake of convenience: the rule passes the Auth0 domain (i.e.
your-tenant.auth0.com) to the form website and the form uses that to construct a callback URL (i.e.
https://your-tenant.auth0.com/continue) for returning to the rule. This is essentially an open redirect and should not be used in production scenarios. You can lock this down by configuring your form website implementation to only return to a specific URL (i.e. just your Auth0 tenant) instead of one that’s generated from a query param. You can then simplify the rule too so it no longer passes the Auth0 domain.
Data Integrity (quoting from Dylan Swartz example ) As stated, this is a very basic example of using an Action Redirect to invoke a consent form. That said, at Auth0 we take security very seriously. The
confirmfield (which has the value of
yes) that is being passed back to auth0 as a signed token using a shared
SESSION_TOKEN_SECRET. In production scenarios where you need assurances of the integrity of the data being returned by the external website (in this case in our hosted code verification form). For example, if you want to be sure that the data truly came from a trusted source, then it should be signed. If the data is sensitive, then it should be encrypted. A good mechanism for doing this is to use a JWT (JSON Web Token). You can build a JWT with claims (that you can optionally encrypt) and then sign it with either a secret shared with your Auth0 Action or with a private key, whose public key is known by the action. The Action can then verify that the claims are legit and decrypt them, if necessary.
Social logins This solution needs some adjusting if you want to offer social logins/signup. In the case of social login, users will not use our signup form, so we need to capture the phone number through a separate form in our application.
Thanks for reading this article. Please reach out here or on Twitter if you have any feedback or questions.
Here is the link to my example code repository: https://github.com/pazel-io/auth0-twilio-phone-verification
Did you find this article valuable?
Support Parham by becoming a sponsor. Any amount is appreciated!