> ## Documentation Index
> Fetch the complete documentation index at: https://docs-dev-docs-event-stream-action-templates.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Learn how to set up a custom SMS gateway for Passwordless connections.

# Set Up Custom SMS Gateway for Passwordless Connections

export const AuthCodeGroup = ({children, dropdown}) => {
  const [processedChildren, setProcessedChildren] = useState(children);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      unsubscribe = window.autorun(() => {
        const processChildren = node => {
          if (typeof node === "string") {
            let processedNode = node;
            for (const [key, value] of window.rootStore.variableStore.values.entries()) {
              const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
              processedNode = processedNode.replaceAll(new RegExp(escapedKey, "g"), value);
            }
            return processedNode;
          } else if (Array.isArray(node)) {
            return node.map(processChildren);
          } else if (node && node.props && node.props.children) {
            return {
              ...node,
              props: {
                ...node.props,
                children: processChildren(node.props.children)
              }
            };
          }
          return node;
        };
        setProcessedChildren(processChildren(children));
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  return <CodeGroup dropdown={dropdown}>{processedChildren}</CodeGroup>;
};

<Warning>
  This guide is the legacy custom SMS implementation for Passwordless connections and only applies to Auth0 tenants created prior to March 2025.

  New tenants should follow the [Passwordless Authentication with SMS phone provider instructions](/docs/authenticate/passwordless/authentication-methods/sms-otp#configure-the-phone-provider).
</Warning>

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](/docs/authenticate/passwordless/authentication-methods/sms-otp) use [Twilio](https://www.twilio.com) to send out one-time use codes. However, if you have a custom SMS gateway, you can modify your connection to use that instead.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Auth0 does not support basic SMS authentication.
</Callout>

1. Set up a SMS passwordless connection. To learn how, read the Implement Passwordless section in [Passwordless Connections](/docs/authenticate/passwordless).
2. [Get an Access Token for the Management API](/docs/secure/tokens/access-tokens/management-api-access-tokens). You will need this to make calls to the Management API to update your Passwordless connection.
3. Use the [GET Connections](https://auth0.com/docs/api/management/v2#!/Connections/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:

<AuthCodeGroup>
  ```bash cURL lines theme={null}
  curl --request GET \
    --url https://your-auth0-tenant.com/api/v2/connections \
    --header 'authorization: Bearer {yourAccessToken}'
  ```

  ```csharp C# lines theme={null}
  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);
  ```

  ```go Go lines theme={null}
  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))

  }
  ```

  ```java Java lines theme={null}
  HttpResponse response = Unirest.get("https://your-auth0-tenant.com/api/v2/connections")
    .header("authorization", "Bearer {yourAccessToken}")
    .asString();
  ```

  ```javascript Node.JS lines theme={null}
  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);
  });
  ```

  ```php PHP lines theme={null}
  $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;
  }
  ```

  ```python Python lines theme={null}
  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"))
  ```

  ```ruby Ruby lines theme={null}
  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
  ```
</AuthCodeGroup>

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](https://auth0.com/docs/api/management/v2#!/Connections/get_connections) 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.

```json lines expandable theme={null}
[
    {
        "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"
        ],
    }
]
```

5. Update the connection. You can do this by making a PATCH call to the [Update a Connection endpoint](https://auth0.com/docs/api/management/v2#!/Connections/patch_connections_by_id). More specifically, you'll be updating the connections `options` object to provide information about the SMS Gateway.

   <Warning>
     You must send the entire `options` object with each call; otherwise, you will overwrite the existing data that is not included in subsequent calls.
   </Warning>

   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:

   ```json lines theme={null}
   {
       "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,
   }
   ```

## Authenticated requests

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

```json lines theme={null}
"gateway_authentication": {
    "method": "bearer",
    "subject": "urn:Auth0",
    "audience": "urn:MySmsGateway",
    "secret": "MySecretToSignTheToken",
    "secret_base64_encoded": false
}
```

When you include `gateway_authentication` in your `options` object, Auth0 adds a [JSON Web Token](/docs/secure/tokens/json-web-tokens) 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 <Tooltip tip="Passwordless: Form of authentication that does not rely on a password as the first factor." cta="View Glossary" href="/docs/glossary?term=Passwordless">Passwordless</Tooltip> connection.

```json lines theme={null}
{
  "recipient": "+1 399 999",
  "body": "Your verification code is: 12345",
  "sender": "+1 234 567"
}
```

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.

```json lines theme={null}
{
  "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"
       }
}
```

## 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:

```json lines theme={null}
{
 "error":"sms_provider_error",
 "error_description":"Unexpected response while calling the SMS gateway: <HTTP Code Returned by the SMS Gateway>"}
}
```

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.)
