Signed: integrity without TLS
Signed (formerly L2 Signed) is the clever middle that enterprise clouds skip: every message carries an HMAC-SHA256 signature of the payload, computed with a device key you ask for on the device page — Get signing key. Claiming a device mints no key: the key is a separate, deliberate step, and it is shown exactly once.
Getting the key changes nothing at the door. The device carries on reporting as it is, and enforcement follows the firmware — the first message that arrives with a valid signature is what moves it to Signed. Moving up without going dark is the whole sequence.
X-Chirp-Signature: hex( hmac_sha256(device_key, signed_input) )
signed_input = nonce + "\n" + "tag=" + tag + "\n" + bodyBoth lines are always there, empty fields included: a message with no nonce and no tag signs "\ntag=\n" + body, and one carrying both signs "<nonce>\ntag=<tag>\n" + body. The label and the freshness stamp are part of what the device attests.
key 0123456789abcdef0123456789abcdef (32 ASCII bytes)
what the device sends body temp=21.4, no nonce header, no tag header
signed input "\ntag=\ntemp=21.4" (15 bytes)
signed input, hex 0a7461673d0a74656d703d32312e34
hmac-sha256 fd071ea6328d4ca04bf766d76c4298359a07db6b161fbc8446b336511954bda2Why this level exists
TLS is heavy for the smallest MCUs — RAM for the handshake, flash for the cert store, a correct clock for validation. Signed delivers the property most projects actually need — nobody can forge or alter a message from your device — using one hash function that runs on anything, over plain HTTP or UDP. An attacker can still read your traffic (it’s not encryption), and without the key they cannot forge a new payload or tamper undetected. What they can do is re-send one they captured, verbatim: the signature binds the bytes, not the occasion. Closing that is opt-in, and it is the first thing below.
How to protect yourself at Signed
- Send a nonce, and the platform rejects the replays. Stamp
X-Chirp-Nonceon the message and put it in the nonce field of the signed input above; a captured message re-sent verbatim is then refused, and one re-sent with the stamp stripped fails its signature. It is opt-in and it rides in a header, so a transport with nowhere to put one stays replayable — the API contract carries the current header format and freshness rules. - The device key is shown once and never travels again. Same hygiene as the Token level’s token: config file, not public source. Lost it? Rotating the token issues a fresh token and a fresh key together — and takes the board dark until both are on it, so prefer re-provisioning, which rotates and pushes in one pass.
- Signed means the same thing on every transport: HTTP and UDP carry the signature in a header/field; MQTT and raw TCP prefix each payload with the 32 raw HMAC bytes. Your device computes one HMAC either way — only where it rides differs, and the docs snippets show both forms.
Choose Signed when
The device acts on commands (relay, fan, valve, lock — within the acceptable-use limits), or decisions get made from its data, but the payload itself isn’t secret. Greenhouse controller: yes. Anything whose readings are sensitive: keep Signed and switch on Encrypted as well — the signature stops forgery, the switch stops reading, and they are separate switches.