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. Runlua auth configureand choose Email; an API-key sign-in can’t issue a device credential, and neither can a run withLUA_API_KEYset 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 adefineDevicedeclaration 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. Without
--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
--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 On a microcontroller, copy the three values into the board’s config file instead, as in the Pico W guide.
LUA_AGENT_ID and LUA_DEVICE_CREDENTIAL. Load the file into the shell that starts the device: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.- Node
- Python
- MQTT
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 withCredential management requires a first-party user session. name (up to 120 characters) and expiresAt (epoch milliseconds) are optional.
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
AUTH_FAILED on connect
AUTH_FAILED on connect
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.AGENT_FORBIDDEN on connect
AGENT_FORBIDDEN on connect
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.OPERATION_FORBIDDEN on a response or trigger
OPERATION_FORBIDDEN on a response or trigger
The credential lacks
commands or triggers. Issue a new credential with the operation; operations can’t be added to an existing one.lua devices credential says it needs an email sign-in
lua devices credential says it needs an email sign-in
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.

