Configure SMS and Voice Notifications for MFA

If you use SMS or voice as authentication factors, when an end user attempts to authenticate with your application, they are sent a code via SMS or voice, which they will have to enter to complete the transaction. This implies that they both know their login credentials and are in possession of the device that they have registered for MFA use.

You can configure the SMS and Voice factor using the Dashboard or the Management API to send messages through SMS, voice, or to let the end users choose how they want the code to be delivered. You can configure your delivery provider using Actions, configure your Twilio account, or if you want to send customers SMS only, configure Auth0's default message delivery service. You must use the New Universal Login Experience to enable voice notifications for MFA.

Availability varies by Auth0 plan and login method

Both the login implementation you use and your Auth0 plan or custom agreement affect whether this feature is available. To learn more, read New Universal Login vs. Classic Universal Login and Pricing.

How it works

When SMS and Voice are enabled, users are given the option to enroll by getting the code sent by SMS or voice:

Configure SMS and Voice for MFA User Experience Voice

When you only enable SMS, the flow is simpler:

Configure SMS and Voice for MFA User Experience SMS

After users are enrolled, the next time they authenticate they will get the voice or SMS message at their registered phone.

Use the Dashboard

  1. Go to Dashboard > Security > Multi-factor Auth.

  2. Click Phone Message and enable the toggle switch at the top.

    Dashboard Security Multi-factor Auth Phone Message
  3. Select your preferred message delivery provider.

  4. To allow users to authenticate with SMS and voice, you must enable the SMS and voice factors and select your preferred delivery method:

    1. Auth0: You can't use this provider to send voice messages. Sends SMS messages using Auth0's internally-configured SMS delivery provider. It can be used for evaluation and testing purposes only, and there is a maximum of 100 messages per tenant during the entire tenant lifetime. New codes are not received after reaching the 100 message limit.

    2. Twilio: Sends the messages using the Twilio Programmable SMS API for SMS or Twilio Programmable Voice API for voice. Use Twilio Life Credentials, not Test Credentials, which are only meant to send messages in a production environment.

    3. Custom: Sends the messages by invoking an Action in the Send Phone Message Flow.

    You can also choose to give users the option of getting SMS text messages, voice calls, or both.

Twilio configuration

If you choose to deliver SMS via Twilio, follow these steps to configure your SMS factor.

  1. Open an account with Twilio. You will need a Twilio Account SID and a Twilio Auth Token. These are the Twilio API credentials that Auth0 will use to send an SMS to the user.

  2. You may also need to enable permissions for your geographic region for SMS or voice. If you use voice, your account needs to have a Twilio phone number enabled to make voice calls. This can be an external phone number verified with Twilio or you can purchase and set up a Twilio phone number from within your account.

  3. Configure the connection. Go to Dashboard > Security - Multi-factor Auth and choose Phone Message.

  4. Under Choose your delivery provider, choose Twilio and choose a delivery method.

  5. Enter your Twilio Account SID and Twilio Auth Token in the appropriate fields.

    Dashboard Security Multi-Factor Auth Twilio
  6. Choose your SMS Source.

    1. If you choose Use From, you will need to enter the From phone number that users will see as the sender of the SMS. You may also configure this in Twilio.

    2. If you choose Use Messaging Services, you will need to enter a Messaging Service SID.

    3. If you are using voice, you always need to configure From even if you are using Message Services for SMS. Make sure the phone number is configured to send both SMS and voice messages.

  7. Click Save.

Customize SMS or voice message templates

You can customize your SMS and voice message templates. To learn more, read Customize SMS and Voice Messages.

Use the Management API

You can use the Management API to configure which message delivery methods are enabled by using the /api/v2/guardian/factors/phone/message-types endpoint. The message_types parameter is an array that can have ["sms"], ["voice"], or ["sms", "voice"]. You need a Management API access token with the update:guardian_factors scope as a bearer token to call the API:


curl --request PUT \
  --url 'https://{yourDomain}/api/v2/guardian/factors/phone/message-types' \
  --header 'authorization: Bearer MGMT_API_ACCESS_TOKEN' \
  --header 'content-type: application/json' \
  --data '{ "message_types": ["sms", "voice"] }'

Was this helpful?

/
var client = new RestClient("https://{yourDomain}/api/v2/guardian/factors/phone/message-types");
var request = new RestRequest(Method.PUT);
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "Bearer MGMT_API_ACCESS_TOKEN");
request.AddParameter("application/json", "{ \"message_types\": [\"sms\", \"voice\"] }", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);

Was this helpful?

/
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io/ioutil"
)

func main() {

	url := "https://{yourDomain}/api/v2/guardian/factors/phone/message-types"

	payload := strings.NewReader("{ \"message_types\": [\"sms\", \"voice\"] }")

	req, _ := http.NewRequest("PUT", url, payload)

	req.Header.Add("content-type", "application/json")
	req.Header.Add("authorization", "Bearer MGMT_API_ACCESS_TOKEN")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}

Was this helpful?

/
HttpResponse<String> response = Unirest.put("https://{yourDomain}/api/v2/guardian/factors/phone/message-types")
  .header("content-type", "application/json")
  .header("authorization", "Bearer MGMT_API_ACCESS_TOKEN")
  .body("{ \"message_types\": [\"sms\", \"voice\"] }")
  .asString();

Was this helpful?

/
var axios = require("axios").default;

var options = {
  method: 'PUT',
  url: 'https://{yourDomain}/api/v2/guardian/factors/phone/message-types',
  headers: {
    'content-type': 'application/json',
    authorization: 'Bearer MGMT_API_ACCESS_TOKEN'
  },
  data: {message_types: ['sms', 'voice']}
};

axios.request(options).then(function (response) {
  console.log(response.data);
}).catch(function (error) {
  console.error(error);
});

Was this helpful?

/
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"content-type": @"application/json",
                           @"authorization": @"Bearer MGMT_API_ACCESS_TOKEN" };
NSDictionary *parameters = @{ @"message_types": @[ @"sms", @"voice" ] };

NSData *postData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:nil];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://{yourDomain}/api/v2/guardian/factors/phone/message-types"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"PUT"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

Was this helpful?

/
$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://{yourDomain}/api/v2/guardian/factors/phone/message-types",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "PUT",
  CURLOPT_POSTFIELDS => "{ \"message_types\": [\"sms\", \"voice\"] }",
  CURLOPT_HTTPHEADER => [
    "authorization: Bearer MGMT_API_ACCESS_TOKEN",
    "content-type: application/json"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}

Was this helpful?

/
import http.client

conn = http.client.HTTPSConnection("")

payload = "{ \"message_types\": [\"sms\", \"voice\"] }"

headers = {
    'content-type': "application/json",
    'authorization': "Bearer MGMT_API_ACCESS_TOKEN"
    }

conn.request("PUT", "/{yourDomain}/api/v2/guardian/factors/phone/message-types", payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))

Was this helpful?

/
require 'uri'
require 'net/http'
require 'openssl'

url = URI("https://{yourDomain}/api/v2/guardian/factors/phone/message-types")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Put.new(url)
request["content-type"] = 'application/json'
request["authorization"] = 'Bearer MGMT_API_ACCESS_TOKEN'
request.body = "{ \"message_types\": [\"sms\", \"voice\"] }"

response = http.request(request)
puts response.read_body

Was this helpful?

/
import Foundation

let headers = [
  "content-type": "application/json",
  "authorization": "Bearer MGMT_API_ACCESS_TOKEN"
]
let parameters = ["message_types": ["sms", "voice"]] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://{yourDomain}/api/v2/guardian/factors/phone/message-types")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "PUT"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()

Was this helpful?

/

Integrated SMS messaging providers

Auth0 defaults to support for sending messages through Twilio. However, you can use a different SMS provider, and add specific logic before sending a message or send a different message depending on the user or the application. To do this, you configure SMS MFA to use one of our integrated Actions in the Send Phone Message Flow.

Integrated SMS messaging providers include:

Custom phone providers

You can also configure custom phone providers using Actions. To see example code for a custom phone provider Action, read the "Common use cases" section of Send Phone Message Flow.

Security considerations

When using any phone messaging provider, be aware that attackers abusing the signup flow could cause you financial damage.

Auth0 limits a single user to send up to 10 SMS or voice messages per hour, and OTP flows via email or authenticators are limited to five requests every five minutes. (The burst rate is 10 but only 1 voice message per hour will be sent for new requests.) To further protect your account, consider:

  • Enabling Brute Force Protection. Auth0 will block an IP if it attempts to do more than 50 signup requests per minute.

  • Enabling Log Streaming and creating alerts using your favorite monitoring tool when you see spikes in the number of gd_send_voice or gd_send_voice_failure log events.

Phone Messaging providers have additional protections. If you are using Twilio, read the Twilio's Anti-Fraud Developer Guide. Consider the following options:

  • Limit the countries that you will send messages for SMS and Voice. This is particularly useful if there are countries with a higher risk of toll fraud or more expensive calling rates in which you do not typically do business.

  • Enable Twilio usage triggers to protect your account against fraud and coding mistakes.

Learn more