---
parent: /workflows/agents.md
back_out_url: /workflows/agents.md
---

# Workflow 17: Authenticate a NATS / DataHub Client

> You are at https://api.litmus.io/workflows/authenticate-nats-datahub-client.md
> Parent: https://api.litmus.io/workflows/agents.md
> If this is the wrong workflow, back out to the index above.

## 17. Authenticate a NATS / DataHub Client

**UI trigger**: System -> Access Control -> Tokens -> *Access Accounts* (create the credential, grant topics) and *NATS Proxy* (expose the bus). The LE UI also shows the same key under DataHub.

Opens the device's internal NATS message bus (DataHub) to an external client. Provisioning the credential is five REST calls. Connecting with it then needs four LE-specific client settings, none of them guessable, and every one of them fails as a bare connection timeout rather than an error.

### URL pattern

Provisioning calls are REST under `{{edgeUrl}}/access/...`. Auth is HTTP Basic: username is the API token (`{{apiToken}}`), password empty. See /le/agents.md#authentication.

The bus itself is NATS on port `4222`, not HTTP, so **the connection in step 6 cannot be issued from Postman** or any HTTP client. Use a NATS client library.

### Step table

| Step | Name in Collection | Method | Endpoint | Key input | Output / what to capture |
|------|-------------------|--------|----------|-----------|--------------------------|
| 1 | Enable NATS Proxy | `PUT` | `/access/proxy/enable` | -- | `204`. External clients can now reach the bus. Until this succeeds nothing off-device connects |
| 2 | Create Access Account | `POST` | `/access/accounts` | `{"name": "api_access_account", "enabled": true}` | `{id, apikey}`. The `apikey` is the NATS credential -- capture as `{{access_account_api_key}}` |
| 3 | Add Read Topic | `PUT` | `/access/accounts/access/{apikey}?accessType=read&topics=<pattern>` | Pattern, e.g. `devicehub.alias.>` | `204`. Repeat once per pattern |
| 4 | Add Write Topic | `PUT` | `/access/accounts/access/{apikey}?accessType=write&topics=<pattern>` | Pattern | `204`. Skip entirely for a read-only consumer |
| 5 *(verify)* | Account Current Access | `GET` | `/access/accounts/access/{apikey}` | -- | `{"read": [">"], "write": null}`. Confirms the grants landed |
| 6 | *(not an API call)* | -- | `nats://<device-ip>:4222` | See client settings below | A connected NATS client |

Steps 3 and 4 key off the **API key**, not the account UUID. `{{access_account_id}}` from step 2 is only needed for the account-level operations in /le/system/access-control.md (enable, disable, reset, delete).

### Client connection settings

What any NATS client library needs to be told, whichever language it is written in. All five are required together, and the last four are where LE differs from a stock NATS broker.

| Setting | What to send | Why |
|---|---|---|
| Broker address | `nats://<device-ip>:4222` | See the address table below for the on-device cases |
| Username | The `apikey` from step 2 | LE accepts the key only as a user/password pair |
| Password | The same `apikey` again, not empty | Both fields carry the same value. This is the part that is not guessable |
| TLS | Trust the device CA, or accept any certificate | The bus uses the same self-signed certificate as the REST API (`System > Network > Certificates`, see /le/system/network.md) |
| Missing `version` in INFO | Tolerate it | LE's INFO banner omits `version`. Strict clients that parse it as a semantic version throw mid-handshake |

| Calling from | Address | Note |
|---|---|---|
| Another host on the network | `nats://<device-ip>:4222` | Needs step 1 done and the port open in the device firewall |
| A container on the same device | `nats://172.17.0.1:4222` | The Docker bridge gateway. Inside a container `localhost` is the container, not the device |
| A process on the device | `nats://127.0.0.1:4222` | The internal bus directly. This is what the Node-RED `Datahub Connect` node uses |

### Topic patterns

Patterns use NATS wildcards: `>` matches any number of trailing tokens, `*` matches exactly one.

| Pattern | Covers |
|---|---|
| `devicehub.alias.>` | Device tag traffic |
| `analytics.publish.>` | Analytics output |
| `>` | The whole bus |

For the JSON shape of the messages that arrive on these subjects, see /reference/devicehub-message-format.md.

### Failure modes

> **Token auth is silently dropped**: sending the key as a NATS `auth_token` (the token field of the CONNECT protocol message) is valid NATS and is accepted by stock brokers, but LE neither honours nor rejects it. The login is discarded and the connection times out. Send the key as username *and* password instead.

> **Every failure looks like the same timeout**: a wrong key, token-style auth, and the `version` parse error all present as a connection timeout. The gateway never answers `-ERR 'Authorization Violation'`, so a timeout means "try the next hypothesis", not "the broker is down". The most common cause is a key from a different device: keys are per-device and are not portable.

> **Fail fast with an INFO preflight**: a NATS broker greets every TCP connection with `INFO ` and a JSON document before any TLS or authentication. Opening a raw socket and reading that one line tells you in under a second whether a broker is listening and whether `auth_required` is `true`, instead of spending one full timeout per credential guess.

> **No grants means no data**: a new account has no grants at all, so a client with a correct key connects successfully and then receives nothing. Grant at least one read pattern (step 3) before concluding the connection is broken.

> **Port check**: `4222` is the DataHub broker port and the NATS integration provider default. Field devices have also been seen with a firewall `ACCEPT` rule for TCP `4999` on `eth0` labelled `NATS` (visible under `System > Device Management > Templates > List Configuration Template Inventory` in `dm.firewall.rules`). If `4222` refuses from off-device while the proxy is enabled, confirm which port your deployment publishes and open it under `System > Network`.

### Related

| Task | Fetch |
|---|---|
| Rest of the access-account surface: `Reset Access Account` to rotate a leaked key, remove-topic calls, enable/disable pair | /le/system/access-control.md |
| Message payload shape on the bus | /reference/devicehub-message-format.md |
| Opposite direction of travel: point the device's own integration engine *at* an external NATS broker | /le/integration/provider-examples.md#create-instance---nats |
| Open the port in the device firewall | /le/system/network.md |
