Set Up Custom SMS Gateway for Passwordless Connections

Set Up Custom SMS Gateway for Passwordless Connections

This guide will show you how to use a custom SMS gateway to send out your one-time-use codes.

By default, Passwordless SMS connections use Twilio to send out one-time use codes. However, if you have a custom SMS gateway, you can modify your connection to use that instead.

  1. Set up a SMS passwordless connection. To learn how, read the Implement Passwordless section in Passwordless Connections.

  2. Get an Access Token for the Management API. You will need this to make calls to the Management API to update your Passwordless connection.

  3. Use the GET Connections endpoint to retrieve information about the connections associated with your tenant. More specifically, you need to get the ID for your Passwordless SMS connection so that you can use it in a later API call that updates the connection itself. Be sure to replace ACCESS_TOKEN with the token you obtained in step 1 before making the following call to the Management API:

    
    
    curl --request GET \
      --url https://your-auth0-tenant.com/api/v2/connections \
      --header 'authorization: Bearer {yourAccessToken}'

    Was this helpful?

    /
    var client = new RestClient("https://your-auth0-tenant.com/api/v2/connections");
    var request = new RestRequest(Method.GET);
    request.AddHeader("authorization", "Bearer {yourAccessToken}");
    IRestResponse response = client.Execute(request);

    Was this helpful?

    /
    package main
    
    import (
    	"fmt"
    	"net/http"
    	"io/ioutil"
    )
    
    func main() {
    
    	url := "https://your-auth0-tenant.com/api/v2/connections"
    
    	req, _ := http.NewRequest("GET", url, nil)
    
    	req.Header.Add("authorization", "Bearer {yourAccessToken}")
    
    	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.get("https://your-auth0-tenant.com/api/v2/connections")
      .header("authorization", "Bearer {yourAccessToken}")
      .asString();

    Was this helpful?

    /
    var axios = require("axios").default;
    
    var options = {
      method: 'GET',
      url: 'https://your-auth0-tenant.com/api/v2/connections',
      headers: {authorization: 'Bearer {yourAccessToken}'}
    };
    
    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 = @{ @"authorization": @"Bearer {yourAccessToken}" };
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://your-auth0-tenant.com/api/v2/connections"]
                                                           cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                       timeoutInterval:10.0];
    [request setHTTPMethod:@"GET"];
    [request setAllHTTPHeaderFields:headers];
    
    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://your-auth0-tenant.com/api/v2/connections",
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_ENCODING => "",
      CURLOPT_MAXREDIRS => 10,
      CURLOPT_TIMEOUT => 30,
      CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
      CURLOPT_CUSTOMREQUEST => "GET",
      CURLOPT_HTTPHEADER => [
        "authorization: Bearer {yourAccessToken}"
      ],
    ]);
    
    $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("your-auth0-tenant.com")
    
    headers = { 'authorization': "Bearer {yourAccessToken}" }
    
    conn.request("GET", "/api/v2/connections", headers=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://your-auth0-tenant.com/api/v2/connections")
    
    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    
    request = Net::HTTP::Get.new(url)
    request["authorization"] = 'Bearer {yourAccessToken}'
    
    response = http.request(request)
    puts response.read_body

    Was this helpful?

    /
    import Foundation
    
    let headers = ["authorization": "Bearer {yourAccessToken}"]
    
    let request = NSMutableURLRequest(url: NSURL(string: "https://your-auth0-tenant.com/api/v2/connections")! as URL,
                                            cachePolicy: .useProtocolCachePolicy,
                                        timeoutInterval: 10.0)
    request.httpMethod = "GET"
    request.allHTTPHeaderFields = headers
    
    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?

    /
    The response from the endpoint will be an array of objects. Each object represents one connection affiliated with your tenant.

  4. Identify your connection ID. You can find the ID associated with your Passwordless connection by reviewing the array of objects you returned from the GET Connections endpoint in step 2. To find the specific object for your Passwordless connection, you can search for the "name": "sms" property. Notice that the connection currently displays the Twilio information you provided during the setup process.

    [
        {
            "id": "con_UX85K7K0N86INi9U",
            "options": {
                "disable_signup": false,
                "name": "sms",
                "twilio_sid": "TWILIO_SID",
                "twilio_token": "TWILIO_AUTH_TOKEN",
                "from": "+15555555555",
                "syntax": "md_with_macros",
                "template": "Your SMS verification code is: @@password@@",
                "totp": {
                    "time_step": 300,
                    "length": 6
                },
                "messaging_service_sid": null,
                "brute_force_protection": true
            },
            "strategy": "sms",
            "name": "sms",
            "is_domain_connection": false,
            "realms": [
                "sms"
            ],
            "enabled_clients": []
        }
    ]

    Was this helpful?

    /

  5. Update the connection. You can do this by making a PATCH call to the Update a Connection endpoint. More specifically, you'll be updating the connections options object to provide information about the SMS Gateway.

    Make the following changes:

    • Remove both the twilio_sid and twilio_token parameters

    • Add the provider parameter, and set it to sms_gateway)

    • Add the gateway_url parameter, and set it to the URL of your SMS gateway. Auth0 must be able to reach this URL for it to use your gateway to send messages on your behalf.

    Your payload will look something like this:

    {
        "options": {
          "strategy": "sms",
          "provider": "sms_gateway",
          "gateway_url": "{urlOfYourGateway}",
          "from": "+1 234 567",
          "template": "Your verification code is: @@password@@",
          "brute_force_protection": true,
          "forward_req_info": "true",
          "disable_signup": false,
          "name": "sms",
          "syntax": "md_with_macros",
          "totp": {
            "time_step": 300,
            "length": 6
          }
        },
        "is_domain_connection": false,
        "enabled_clients": []
    }

    Was this helpful?

    /

Authenticated requests

If your SMS Gateway accepts authenticated requests that are token-based, you can add the following to your options object:

"gateway_authentication": {
    "method": "bearer",
    "subject": "urn:Auth0",
    "audience": "urn:MySmsGateway",
    "secret": "MySecretToSignTheToken",
    "secret_base64_encoded": false
}

Was this helpful?

/

When you include gateway_authentication in your options object, Auth0 adds a JSON Web Token to the Authorization header whenever it sends requests to your SMS gateway. The token contains the gateway_authentication.subject and gateway_authentication.audience values, and is signed with gateway_authentication.secret.

If your secret is base64-url-encoded, set secret_base64_encoded to true.

Once you have updated your connection, Auth0 will send the following to your SMS Gateway every time a user signs up or logs in with your Passwordless connection.

{
  "recipient": "+1 399 999",
  "body": "Your verification code is: 12345",
  "sender": "+1 234 567"
}

Was this helpful?

/

If you set the forward_req_info property in the options object to true, the gateway will also receive information from the HTTP request that initiated the Passwordless process. This includes the IP address of the client calling /passwordless/start and its User Agent.

{
  "recipient": "+1 399 999",
  "body": "Your verification code is: 12345",
  "sender": "+1 234 567",
  "req" : { 
      "ip" : "167.56.227.117",
      "user-agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36"
       }
}

Was this helpful?

/

Error handling

Auth0 will only consider the HTTP code returned from the SMS Gateway; it ignores the rest of the response (e.g., response body and response type).

If the SMS Gateway returns an HTTP code other than 200, the /passwordless/start endpoint will return an HTTP 400 code and a response that looks like the following:

{
 "error":"sms_provider_error",
 "error_description":"Unexpected response while calling the SMS gateway: <HTTP Code Returned by the SMS Gateway>"}
}

Was this helpful?

/

If the SMS Gateway returns HTTP 401, the error_description will be Authentication failed while calling the SMS gateway: 401. (Please note that the error description verbiage is subject to change at any time.)

Auth0 enforces a timeout of 30 seconds for HTTP calls to custom SMS Gateways. If the SMS Gateway fails to reply within this time frame, the /passwordless/start endpoint will also return an HTTP 400 code. The response will have the format shown above and the error_description field will be Timeout while calling the SMS gateway: <Timeout Code>. (Again, the error description verbiage is subject to change at any time.)