Guides & tutorials

Custom multi-factor authentication with Auth0

Table of contents

In this article we will cover the main concepts on how to build a custom multi-factor authentication flow on top of your identity provider or custom API, so you can add an extra layer of security whatever email or SMS service you want to use for the 2nd factor or the custom logic you want to add to the process.

Create custom UI components in minutes

Build the UI of your forms with our drag-and-drop editor, and completely personalize its look and feel to make them fit consistently anywhere.

Click on 'Create a form', and select 'Login Form' template. All the templates are fully editable. Simply include a new step for the second authentication factor. Ask for email and password on the first one, and for the temporary code on the second one.

You can also edit styles and colors in the 'Design' tab, in no time. This editor allows you to change the most basic styles, but if you want to make a more advanced customization, you can use all these CSS variables to make it fit perfectly with your brand image.

Add logic to each form step

Our editor allows you to add flows that will execute custom server-side logic between form steps or before submitting the form, so for this case we will add two flows just after each step as you see in the image below:

Flow 1: Verify credentials and send a OTP

The first flow will do the following actions:

  • Check if user provided a valid email and password.
  • If the user provided invalid credentials, show a custom error message.
  • If the credentials are valid, we will store the access_token in a private state, to use it later, and generate an OTP to send by email.

1. Check if the user provided valid credentials

We will add an ¡HTTP Request' action using Auth0's Resource Owner Password  API which allows you to check if the user provided credentials are valid or not, if they are, the API will return an access_token which we can use to authorize the user.

We will set this action using the endpoint and body field:

  "username": "{{}}",
  "password": "{{input.body.password}}",
  "client_id": "YOUR_CLIENT_ID",
  "grant_type": "password",
  "scope": "openid"

You can get the variables from drill down on previous fields or from the 'Executions' tab, checking the data structure. If you need more information about this, you can take a look at how to reference variables in Arengu, and at Auth0's authentication API documentation.

2. Add a conditional that checks the API response

This action will only check if Auth0 returned a success response. It's as simple as adding an 'If/then condition' action and referencing the Auth0 response variable. Get the response variable from the drill down.

3. If credentials are valid, store a state variable

State allows you to create private variables that will be available across your current flows executions and as Auth0 returns an access_token but we don't want to give it to the user yet, we will store it in a private state and only use it once the user provides a second authentication factor.

Just click on the dropdown to get the access_token variable from the first action and give it a simple name to reference in the second flow.

4. Generate an OTP and send it via email

To configure the generation of the temporary codes you just need to include this action, and reference the email variable. You will find it on the drill down. This action also allows you to set up the length of the temporary code that is going to be sent.

Choose between Mailjet or SendGrid native actions to send the code by email. In both cases, you will need to have an account created in one of these services, and to copy paste its API key and Secret key.

Both actions will allow you to customize the email template and different settings, all you have to do is remember to include the generated OTP in your email template. You will find it, for example, on the 'Subject' field's drill down after an execution of the flow with 'Generate one-time password' action working properly.

Now, we will just close the first flow adding a 'Go to the next form step' action.

Flow 2: Check the OTP and authorize the user

The last step is to set up a flow with a simple structure:

  • Verify if the provided OTP is valid or not.
  • If the OTP is not valid, show a custom error message.
  • If the OTP is correct, submit the form including the access_token.

1. Verify the OTP code

Include this action and reference user email and temporary code variables. You can find them on each field drill down after a form execution, as usual. Remember also to link this flow with the form step 2 to make them work properly together.

2. Manage the OTP verification result

Add an 'If/then condition' action to manage the different responses. Reference the OTP validation output variable, and choose 'is true' from drill down. That easy.

3. Show an error message if the OTP is not valid

If the temporary code is not correct, we need to show the proper error message on the form. So, let's include a 'Show error message' action, and write a custom message.

4. Submit the form and redirect the user

If the OTP code is valid, we will submit the form displaying a custom success and redirecting the user to the private area. Here you can include the access_token variable to authorize the user on your callback URL.

Embed it anywhere!

Go to the 'Embed' tab and test your own form with the Preview option, and get the code to embed it anywhere you need it. Our forms are compatible with any tech stack.

Alternative 2nd factor: OTP via SMS

You can also easily integrate Twilio to send one-time passwords by SMS. Create an account, and include this action in the flow after the OTP generation one.

Just copy and paste 3 data (the Account ID, the Auth token and its phone number) and get 2 variables from the drill-down (user's phone number and OTP code in the message) to set up this action. That's all you need to start sending temporary codes!

Do you want to try it by yourself? Sign up free or schedule a demo with our team, and maybe you are interested in taking a look at all the use cases.

You might like to read

Getting started with Arengu

Arengu allows you to build all your user flows connected to your current stack, and avoids coding all the UI, complex integrations, validations or logic from scratch. Try it for free and start building faster and scaling your application needs as they grow.