Skip to main content
After this guide, a device holds a secret that lets it connect as one named device on one agent and do nothing else. Use a device credential for every new device; a legacy API key (api_ plus 32 hex characters) still connects existing devices. The scoped personal API keys the admin dashboard creates don’t work on a device: the device gateway refuses them with AUTH_FAILED and Typed API keys require an explicitly scoped gateway policy over Socket.IO, and with Not authorized over MQTT. A device credential and a scoped API key look alike, api_<uuid>.<43 characters>, so issue the credential with lua devices credential or the REST route below rather than copying a key from the dashboard. Verified against lua-cli 3.45.0. Before you begin
  • An agent project created with lua init, signed in by email. Run lua auth configure and choose Email; an API-key sign-in can’t issue a device credential, and neither can a run with LUA_API_KEY set in the environment or in the project’s .env, because that key takes precedence over the stored session.
  • The device name the client will connect with: 1 to 200 characters with no whitespace, /, +, or #. A name that also has a defineDevice declaration must match ^[a-z][a-z0-9-]*$.
1

Choose the operations

Grant only what the device does. The platform enforces the list on every message.
2

Issue the credential

From the agent project, issue one credential per device. It is bound to the project’s agent and the device name you pass. --operations defaults to commands,triggers.
--out writes three lines to the file, with mode 600, and refuses to overwrite an existing file unless you add --force:
.env.device
Without --out the command prints the secret once instead. The secret is never shown again, so issue a new credential if you lose it. Write the file outside the agent project, as above, or add it to .gitignore, so it is never committed. The command also prints the credential’s ID; keep it in your provisioning records. The aliases lua devices credentials and lua devices key run the same command.
3

Store the secret on the device

The clients read no environment variables themselves; the examples in this section read LUA_AGENT_ID and LUA_DEVICE_CREDENTIAL. Load the file into the shell that starts the device:
On a microcontroller, copy the three values into the board’s config file instead, as in the Pico W guide.
4

Configure the client

Pass the secret as the credential and the exact agentId and deviceName from the binding; a different pair is refused with AGENT_FORBIDDEN even though the secret is valid, and the Node client keeps reconnecting every second until you stop it.
device.ts
5

Verify

Connect the device, then check its state from the agent project.
It prints 🟢 Device 'bench-sensor' is online. A wrong secret stops the Node client with AUTH_FAILED and it doesn’t retry. has never connected to this agent means the device used a different name or agent.

Issue a credential with the REST API

For provisioning scripts and other automation, the same credential comes from one REST call. It needs a first-party user session token for the account that owns the agent; the route refuses API keys with Credential management requires a first-party user session. name (up to 120 characters) and expiresAt (epoch milliseconds) are optional.
The response is the only place the secret appears; list calls never return it.

Options you may need

Rotation, suspension, and revocation are REST calls; lua devices doesn’t cover them. Each takes a first-party user session token and the credential.id, which lua devices credential prints when it issues the credential.

Rotate

POST /admin/users/me/credentials/<id>/rotate returns a new secret and increments secretVersion; the binding and operations stay. Open connections that presented the old secret are closed at once, so update the device first and restart it.

Suspend and reactivate

POST /admin/users/me/credentials/<id>/suspend refuses new connections and closes open ones at once; POST /admin/users/me/credentials/<id>/reactivate restores an unexpired suspended credential.

Revoke

DELETE /admin/users/me/credentials/<id> is permanent. Open Socket.IO connections are closed at once and an MQTT device is denied at its next publish or subscribe; the periodic re-check, about every minute, is the fallback. Issue a new credential to bring the device back.

If it isn’t working

The secret was rejected: revoked, suspended, expired, rotated, or a scoped personal API key (Typed API keys require an explicitly scoped gateway policy). The Node client stops reconnecting; fix the secret and restart the process.
The agentId or deviceName in the client differs from the binding. Both must match the credential, character for character; with --out, use the LUA_AGENT_ID and LUA_DEVICE_NAME from the file. The Node client reconnects every second until you stop it, so handle its error event.
The credential lacks commands or triggers. Issue a new credential with the operation; operations can’t be added to an existing one.
The CLI is signed in with an API key, or LUA_API_KEY is set in the shell or the project’s .env. Remove it, run lua auth configure, choose Email, and run the command again.

Next steps

Build your first device

Use the credential from a Node script and go live.

Credentials

User sessions, API key classes, and scopes.

Reliability and limits

Revalidation intervals and auth rate limits.