Bring Your Own Messaging Provider: WhatsApp OTP with Inline Hooks & Workflows

Okta’s Identity Engine introduced an Inline Hook for Telephony effectively allow you to replace Okta’s inbuilt SMS solution with your own provider. This empowers customers to manage their own numbers and providers around the world allowing for cost and delivery optimisation. It also paves the way for adding additional channel options for OTP messages. Messaging applications like WhatsApp & Line are incredibly popular around the world and often will work where SMSs do not. This feature was powerful however the information provided in the hook is limited. Now with Low Latency Workflows it is possible to augment the information at hand and deliver a more customised telephony messaging experience.

In this blog post we will do the following.

  1. Add a profile attribute via the profile editor that indicates whether a user has opted in to use WhatsApp to receive OTP.
  2. Setup a Twilio Account and connect to the WhatsApp Sandbox.
  3. Create a Workflow that receives the inline hook grabs the user profile associated with the target user and uses WhatsApp if they have opted in.
  4. Create an Inline Telephony Hook and connect it up.
  5. Test the flow with the Inline Hook Tester

Please note that in this blog post I am not going through the process of enrolling a user via WhatsApp into OTP nor are we capturing the preference data. This is something that you should plan out within your business to determine the best method.

Add Profile Attribute

Our first step is to add an attribute to the user profile to indicate whether a user wants to receive their OTP via WhatsApp. To add the profile attribute first navigate to Directory -> Profile Editor and select the Okta User Default profile as highlighted below.

Once viewing the profile click add-attribute and fill out the fields similar to the below. Here we are simply creating a boolean value and setting it to Read-Write so that a user could change it in their profile settings on the dashboard if they desired.

Set Up Twilio Account

There are a couple of steps required within your Twilio account to setup this demonstration. Firstly, if you do not yet have a Twilio Account you can head over here and create one. You’ll get a small amount of credit, enough to try this out. I recommend reading through this guide to understand how to work with the trial account.

Secondly you’ll need to sign up your test user to the WhatsApp Sandbox. WhatsApp has strict controls around Opt in and message flows Twilio has created Sandbox numbers to allow testing without going through all the hoops of signing up and complying to WhatsApp policies. To connect to the sandbox number navigate to Messaging -> Try It Out -> Send a WhatsApp message within the Twilio Console. Here I recommend scanning the QR code from a phone that has WhatsApp setup on it as it is the quickest and easiest way to opt in. While you’re here copy the sandbox phone number as we will need it later.

In my workflow I am also supporting standard SMS messaging for users who haven’t opted in to WhatsApp. To do this from your Twilio account you’ll need to Obtain a Phone number and add it to your account. Please refer to Twilio’s documentation for more details on how to do this, You’ll want to note down the number that you have purchased and also copy the Account SID and Auth Token for use in the workflow. Please note for a production environment it is strongly recommended that you use API Keys rather than the Account SID and Auth Token.

Create Workflow

To leverage Inline hooks in a workflow we create a new flow and specify API Endpoint

Then on the API Endpoint settings, select Expose as Webhook under Security Level. You can also select Expose as Public Service, but in this instance you will need to implement the security yourself. Expose as Webhook is much easier as it looks after the security for you.

Within the API Endpoint card we want to expose some additional information that we’re going to receive from the inline hook. Specifically in the body section of the card add a data object which contains a userProfile object with a userID inside and a messageProfile object with messageTemplate, phoneNumber and otpCode exposed. You’ll also want to capture the requestType so that we can respond properly to the webhook. We’re going to add an Okta Read User card and use the user ID from the webhook to get teh details of the user. We are going to include the WhatsApp attribute we created above as well as the Mobile Phone number profile properties.

Next, we add an If/Else block which we will use to build the appropriate body for our request to Twilio. We check the WhatsApp boolean we have retrieved from the user profile. If true we then compose a message body for WhatsApp or if false for SMS.

For WhatsApp this will be of the format shown below. Noting that there should be no + on the numbers otherwise an error will occur. Noting that for SMS the format is very similar just without the whatsapp: prefix. Also, within the block create a URL Body output for use later.

To=whatsapp:<users phone number from Read User>&From=whatsapp:<twilio sandbox number>&Body=<message template from API Endpoint card>

Next we need to create the appropriate headers for our Post Request to Twilio. To do this use a Construct Object card as shown below.

Next add an If Error block and inside it as an API Connector POST block. When you add this block you’ll be asked to create a new connection. In this section add a Connection Nickname set the Auth Type to Basic. Use the previously copied Twilio Account SID for the Username and the Twilio Auth Token for the Password. The URL for the Request should be set to https://api.twilio.com/2010-04-01/Accounts/<Twilio Account SID>/Messages.json

Next, you’ll want to connect the headers and URL body that we just created into the POST connector as shown below.

When making an Inline Hook request Okta expects a certain format of JSON response as specified in the developer documentation and copied below. We will use a Compose Card to construct the response. You can copy the block from the documentation and modify it as shown above to include the SID returned from Twilio and the requestType which was included in the initial API request to the flow.

{
  "commands":[
    {
      "type":"com.okta.telephony.action",
      "value":[
        {
          "status":"SUCCESSFUL",
          "provider":"VONAGE",
          "transactionId":"SM49a8ece2822d44e4adaccd7ed268f954",
          "transactionMetadata":"Duration=300ms"
        }
      ]
    }
  ]
}

In the If Error section we are going to capture the error message from Twilio and fill in the error to report back to Okta. As with the above response I recommend copying from the developer documentation and modifying it as shown below to include the message and destination phone number or user ID.

Finally, we are going to use a Return Raw card to respond to Okta and include the output from the above compose cards.

Configure the Inline Hook

Next we need to configure the inline hooks to do so navigate to Workflow -> Inline Hooks in your Okta console and select Add Inline Hook and select the Telephony option.

Here you’ll need to copy across some details from the API Connector card in the workflow. Specifically click on the </> button at the bottom of the card and you’ll see something like the below. Use the Invoke URL for the Hooks URL, use the Alias for the Authentication field and the Client Token for the Authentication secret.

Testing the flow

To test the flow navigate to the Preview Tab. In the data.userProfile box search for a user in your directory that has the WhatsApp flag set to true, has their WhatsApp number saved in the mobile phone field and has followed the steps above to connect to the Twilio Sandbox in the last 24 hours. Select a requestType of MFA Verification and then click Generate Request. This will create a JSON request as shown below. This can be edited if desired by clicking the Edit button.

Once you’re happy with the sample request you can hit View Response and this will send the sample request to our workflow that we created. Ideally you should get a response back like the one shown below.

If it doesn’t work as expected you can view the Workflow execution history to troubleshoot. The workflow template used for this blog can be found on the iamse.blog Github repository here

Extending to Other Channels and Further Info

There is no reason that the extra options be limited to WhatsApp this use case could easily be extended to allow a user to chose any other messaging channel that has a usable API. This methodology could also be used to extend the range of templates or message choices for SMS by allowing access to a user profile or external systems more customised messages become possible.
For more background and information on Low Latency Flows and using Inline Hooks with Workflows I recommend the following other posts on the iamse.blog Low Latency Flows & Learn How to use Workflows for Inline Hooks.

For more information on sending WhatsApp Messages with Twilio including how to get approved to send messages as a business please refer to Twilio.

For another tutorial on sending Twilio messages from workflows refer to Workflows Tutorial: Send SMS via Twilio.

One thought on “Bring Your Own Messaging Provider: WhatsApp OTP with Inline Hooks & Workflows

Leave a Reply