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, e.g. devicehub.write.> |
204. Needed to write tags (see Writing a tag below); 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 |
devicehub.write.> |
Tag writes (grant as write) |
devicehub.write_response.> |
Replies to tag writes (grant as read; > covers it) |
analytics.publish.> |
Analytics output |
> |
The whole bus |
Every tag lists its own subjects in the Topics array of its register (DeviceHub tag
list): Output/Raw is the value stream, Input/Value is the write subject,
Output/WriteResponse is the reply, and Input/Command (devicehub.pollonce.<device>.<tag>)
asks for an immediate read.
Writing a tag
Tag values are written over the bus, not the REST API: there is no REST endpoint for it.
- Subscribe to
devicehub.write_response.<device>.<tag>. - Publish
{"value": <value>, "writeID": "<uuid>"}todevicehub.write.<device>.<tag>.valueis JSON of the tag's type (1.6,true,"AUTO");writeIDis optional. - Read the reply:
{"success":true,"timestamp":1790192833628,"statusCode":0,"status":"Good","writeID":"BE26B124-186E-2060-A3F2-74DDFAEB9D10"}
writeID is echoed back, so a client with several writes in flight can match each
reply to its request. success: false (with a non-Good status) means the device
rejected the write.
Subscribe before you publish: the reply arrives within tens of milliseconds (17 ms measured on 4.0.15). Make sure the reply subscription is live first (send a NATS
PINGafter theSUBand wait for thePONG), or the reply is published before anyone is listening and is lost.
litmus-cli le data write <device> <tag> <value> does all of this (cli-v0.11.0 or later; litmus-cli update to upgrade; see /cli.md).
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
versionparse 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
INFOand 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 whetherauth_requiredistrue, 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.
Permission errors do arrive: unlike a bad login, subscribing to or publishing on a subject outside the account's grants gets an explicit
-ERR, in LE's own wording:permission denied for subscription to topic <subject>: no access ReadAccess for topic <subject>. Stock NATS saysPermissions Violationinstead, so clients that retry on errors should match onpermissionand treat it as permanent.Detecting a dead connection: the broker answers
PINGwithPONG, and the firstPONGafterCONNECTalso proves the login was accepted. Long-running clients should send periodicPINGs and reconnect whenPONGs stop; a half-open TCP connection otherwise waits forever.Port check:
4222is the DataHub broker port and the NATS integration provider default. Field devices have also been seen with a firewallACCEPTrule for TCP4999oneth0labelledNATS(visible underSystem > Device Management > Templates > List Configuration Template Inventoryindm.firewall.rules). If4222refuses from off-device while the proxy is enabled, confirm which port your deployment publishes and open it underSystem > 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 |