Newer Version Available

This content describes an older version of this product. View Latest

Deploy Third-Party SMS-Based Two-Factor Authentication

Two-factor authentication (2FA) enhances security when validating a user’s identity and protects access to your Salesforce org. In addition to a password, SMS-based 2FA requires the user to provide a one-time password (OTP) code received on a mobile device.

To implement 2FA, you can take advantage of a third-party SMS or voice delivery service, like Twilio or TeleSign, together with a Salesforce login flow.

Let’s break down an SMS-based 2FA process.

  1. As the user logs in, the login flow generates a random OTP and sends it via voice or text message to the user’s phone.
  2. The user provides the OTP to the Salesforce application.
  3. Salesforce verifies the code.
  4. If the code is valid, Salesforce permits user access.

The login flow has four steps.

SMS 2FA process
  1. Record lookup—Queries the user record to get the mobile phone number.
  2. SMS plug-in—An Apex class that generates the OTP and uses a third-party SMS delivery service to send it to the user’s mobile device.
  3. Screen—Prompts the user to provide the received OTP.
  4. Decision—Compares the OTP generated by the flow with the one that the user provides. If equal, the flow is completed, and the user is redirected to the application. Otherwise, the flow generates another code and asks the user to reverify.

Configure the Flow

This example uses the Twilio Apex SDK to perform SMS delivery operations. However, you can use any cloud-based SMS or voice vendor that has a public API to access its services.

  1. Go to the Cloud Flow Designer in Salesforce and create a flow.
  2. Create a LoginFlow_UserId input text variable. This variable is populated with the user ID during the login event.

    Creating a LoginFlow_UserId variable

  3. Create text variables.
    • Mobile—The user’s mobile number
    • VerificationCode—The OTP generated by the Apex plug-in
    • Code—The OTP collected from the user
    • Status—The status returned when the plug-in executes
  4. Create a record lookup that queries the UserObject based on the user ID and stores the mobile number in the Mobile input variable.

    Creating a record lookup

  5. Install the Twilio Apex SDK from https://github.com/twilio/twilio-salesforce.
  6. To allow the SMS plug-in to perform outbound API calls to Twilio web services, set up https://api.twilio.com as a remote site in Salesforce. In Setup, enter Remote Site Settings in the Quick Find box, select Remote Site Settings, and add the Twilio web services URL.

    Add the third-party web services URL as a remote site

  7. Create an Apex class.
    101    global class SMSPlugin implements Process.Plugin {
    202     
    303    global Process.PluginDescribeResult describe() {
    404     
    505        Process.PluginDescribeResult result = new Process.PluginDescribeResult();
    606        result.tag='Identity';
    707        result.name='SMS Plugin';
    808        result.description='Two factor authentication with SMS';
    909         
    1010        result.inputParameters = new List<Process.PluginDescribeResult.InputParameter> {
    1111            new Process.PluginDescribeResult.InputParameter('AccountSid', Process.PluginDescribeResult.ParameterType.STRING, true),
    12  
    1312            new Process.PluginDescribeResult.InputParameter('Token', Process.PluginDescribeResult.ParameterType.STRING, true),
    1413            new Process.PluginDescribeResult.InputParameter('To', Process.PluginDescribeResult.ParameterType.STRING, true),
    1514            new Process.PluginDescribeResult.InputParameter('From', Process.PluginDescribeResult.ParameterType.STRING, true),
    1615            new Process.PluginDescribeResult.InputParameter('Message', Process.PluginDescribeResult.ParameterType.STRING, true)
    1716        };
    1817       
    1918        result.outputParameters = new List<Process.PluginDescribeResult.OutputParameter> {
    2019            new Process.PluginDescribeResult.OutputParameter('Status', Process.PluginDescribeResult.ParameterType.STRING),
    2120            new Process.PluginDescribeResult.OutputParameter('VerificationCode', Process.PluginDescribeResult.ParameterType.STRING)
    2221        };
    2322         
    2423        return result;
    2524     
    2625    }
    2726     
    2827     
    2928    global Process.PluginResult invoke(Process.PluginRequest request) {  
    3029     
    3130        Map<String, Object> result = new Map<String, Object>(); 
    3231        String AccountSid = (String)request.inputParameters.get('AccountSid');
    3332        String token = (String)request.inputParameters.get('Token');
    3433        String To = (String)request.inputParameters.get('To');
    3534        String From_a = (String)request.inputParameters.get('From');
    3635        String Message = (String)request.inputParameters.get('Message');
    3736        if (Message == null) Message = 'Your verification code is: ';
    3837         
    3938        TwilioRestClient client = new TwilioRestClient(AccountSid, Token);
    4039        TwilioSMS sms;
    4140         
    4241        Integer rand = Math.round(Math.random()*100000);
    4342        String VerificationCode = string.valueOf(rand);
    4443        String Body = Message + VerificationCode;
    4544         
    4645        Map<String,String> params = new Map<String,String> {
    4746            'To'  => To,
    4847            'From' => From_a,
    4948            'Body' => Body
    5049        };
    5150      
    5251        try {
    5352            sms = client.getAccount().getSMSMessages().create(params);
    5453            result.put('Status', sms.getStatus());
    5554        } catch(Exception ex) {
    5655            result.put('Status', 'Failure');
    5756        }
    5857            result.put('VerificationCode', VerificationCode);
    5958           return new Process.PluginResult(result);
    6059      }
    6160    }
  8. Create an SMS plug-in that generates an OTP code and sends it via SMS to the user’s mobile number. The plug-in takes these inputs.
    • AccountSid—Twilio Account SID (username from your Twilio account)
    • Token—Twilio Auth Token (password from your Twilio account)
    • From—The SMS From number
    • Message—The message sent to the user with the verification code
    • To—The user’s mobile phone number

    Create the SMS plugin

    The plug-in returns two values.
    • Status—The status of the SMS delivery operation
    • VerificationCode—The verification code generated and sent to the user

      The plugin returns two outputs

  9. Create a screen element that prompts for the verification code received.

    Create a screen element

  10. Create a decision element with two outcomes.
    • Valid—The verification code is the same as the code the user provided.
    • Invalid—The valid condition is not met, so the outcome is invalid.

    Create a decision element

  11. Save and activate the flow.
  12. Connect the login flow to a user profile.

    Connect flow to a profile

  13. Log out, and then log in as a test user that’s connected with a test profile.

    sample welcome screen

Extending the Flow

In a production deployment, it’s common to extend this basic flow. For example, you can add customization, validation, or policies, such as:
  • Branding—Add a corporate logo and message to the verification screen.
  • Validation—Verify whether the user record included a phone number. If not, prompt the user to enter one.
  • Retries—If the OTP code that the user provides is wrong, the login flow generates a new OTP code and sends it to the user. It’s typical to limit the number of retries or to temporarily block a user login after several unsuccessful verification attempts.
  • Policies—If the user has registered a landline phone but not a mobile phone number, send the OTP over voice rather than SMS. Alternatively, if Salesforce doesn’t have a registered phone number for the user, send the OTP code by email. Another approach is to challenge the user with a second authentication factor, such as a Salesforce time-based OTP or a hardware-based OTP, like a YubiKey.