Node API Auth: open, admin, and strict

How a node is locked down: the three apiMode tiers, the X-PN-Api-Key header, the separate update key, and the 15-second button hold that clears both.

Published 2026-09-09 · All documentation

A node serves its API on your LAN over plain HTTP, and the first question any integrator asks is what stops the rest of the shop’s Wi-Fi from driving it. The answer is three tiers, one header, and a separate credential for firmware — plus a button on the box that undoes all of it when somebody loses the key.

The shipped default is open, and that is deliberate

Every node in the field has no API key set, and until somebody sets one, nothing on this page changes what a node does.

That is not an oversight to be tidied up later. If "no key set" had meant closed, the first image carrying this feature would have turned an entire fleet cable-only the moment it landed, with the remedy behind the door it had just locked. So the read side stays open, the write side stays open until an operator opts in, and the one operation that is closed by default is firmware replacement — where the remedy is a USB cable already in the room.

The three tiers

A node’s apiMode is open, admin, or strict, reported on its config and set through a config write. Read a tier as the weakest mode at which a route starts asking for a credential.

tierwhat it gateswhy the line is there
nothing. Every read is hereA node that cannot be looked at while locked is a node an operator cannot diagnose, and there is nothing on a read worth protecting: every credential field is write-only, so a read reports only whether one is set
adminthe config and lifecycle class — what this node is, which network it is on, where it sends events, what firmware it runs, whether it is running at allThis is the class an operator locks to stop a well-meaning tablet re-pointing a node
strictthe operational class — printing, the drawer, raw bytes, composed jobs, the diagnostic ring, the scan logLeft open in admin on purpose. Gating printing at admin would mean the setting somebody turns on to protect their configuration also stops their receipts, and a control with that failure mode is switched off again within a shift

A refusal is 401 api_locked. See the error vocabulary for how it sits beside the rest.

One header, and it is not Authorization

The credential is X-PN-Api-Key: <key>.

curl -X PUT http://proxynodes-7f3a.local/config \
  -H 'X-PN-Api-Key: <key>' \
  -H 'Content-Type: application/json' \
  -d '{"printWidthCols": 48}'

It is deliberately not a bearer token, and that is worth understanding rather than working around. Authorization: Bearer already carries the update key on this API, and a node in admin needs both credentials on a single firmware-settings request: the API key to reach the route at all, and the update key to replace the update key. Two secrets cannot share one header without each quietly becoming a valid substitute for the other.

Setting a key, and replacing one

The key is written through the same config route that carries every other setting, as a write-only field beside a read-only "is one set" flag.

  • A key is at least 16 characters, and an over-length one is refused rather than truncated. A truncated credential is byte-for-byte indistinguishable from a working one until the far end starts rejecting things.
  • Setting the FIRST key is ungated bootstrap. Replacing a stored one takes the current key, in every mode including open. That closes the window between "the operator set a key" and "the operator turned the mode up", during which a stranger could otherwise overwrite it.
  • A mode above open requires a key, counting one arriving in the same request. Asking for admin on a keyless node is refused rather than accepted as a lock nothing can satisfy.
  • An empty key clears it, and clearing while the mode is above open is refused unless the same request reopens the node. Presence, not truthiness, decides whether a field applies.

The honest consequence: the node’s own page stops being able to save

A node serves its own operator page over plain HTTP on a LAN address, and that page has nowhere to hold a credential that would not simply be readable by whoever loaded it. So on a node above open, every save from that page is refused.

It still reads everything — status, config, network, firmware state and the diagnostic ring are all ungated — so the page remains the diagnostic it mostly is. Configuration on a locked node is a curl with the header, tooling with the key in its environment, or your own software. If that trade is wrong for a site, the answer is open, which is where every node starts.

Firmware is a separate credential

Uploading a firmware image is gated by a bearer key in every mode, including open, and a node with no update key set refuses firmware from everyone. Closed by default, not open — the opposite default would ship every node wide open until somebody remembered to lock it.

Flowchart of a firmware upload: the key check, the declared byte count, digest verification, erase, the boot-slot switch, and the two escape hatches — bootloader rollback for an image that will not come up, and revert-to-factory for one that comes up wrong.
Where the update key sits in the upload path, and the two ways back out of a bad image. A wrong or truncated image is refused before it can hurt anything: the boot slot is only switched once the exact declared byte count has arrived and hashed to the digest the caller promised.This diagram covers the LAN upload half only. A node also pulls its own images unattended from the release store, and none of that — the schedule, the staged rollout, pins, the bus-settle and quiet-reboot gates — is drawn here.

Reverting to the factory image is not gated the same way, and that asymmetry is a decision:

  • The key exists to stop somebody putting their firmware on your node. Uploading an image can do that. Reverting to the partition its owner last flashed over a cable cannot.
  • Requiring the key there would mean the one command that rescues a bad update is unavailable to anyone who has lost it — the same trap as a fire door that locks.

At admin, a request whose only instruction is "boot the factory image" stays open; anything carrying another field alongside it takes the admin credential like every other write. At strict it closes too, and what makes that defensible is the paragraph below.

Lost the key

Hold the B button for 15 seconds while the firmware is running. The node erases the API key and the update key, returns the mode to open, and reboots.

That gesture is separate from, and longer than, the ~5-second hold that forgets the Wi-Fi credentials, and the two are separated by dead space so a mistimed press cannot land on the other one. It needs physical possession of the node, which is the only credential left when both of the others are gone.

What this model does not give you

There is no per-caller identity, no scopes, no audit trail of who called what, and no rotation schedule — one key per node, held by whoever is configuring it. Raw ESC/POS on port 9100 is outside all of it and cannot be inside it: that socket carries printer bytes and has no header, handshake or envelope anywhere in the protocol to put a credential in, so it is protected by network segregation or it is not protected. Plan the segment, not the header.

What to tell your evaluators

If you are an ISV putting this in front of a security review, the shape is: a LAN device with an optional shared secret, closed-by-default firmware replacement, a physical reset that needs possession, no inbound path from the internet at all, and no remote access — there is none, and none is planned. The API overview covers what the surface actually is, and webhooks covers the one direction a node initiates traffic on your network.

Frequently asked questions

Does a locked node still print?
At `admin`, yes — printing, the drawer and raw bytes stay open there on purpose. At `strict` they need the header too. That is the whole reason `admin` exists as a middle tier rather than a boolean.
Can the website configure my node for me?
No, and it could not be built. This site is served over https and a node is plain http on a private address; browsers block an https page from reading one. The site can hand you a link you click, which navigates your browser to the node — that works and is what the account page does — but it never reads or writes a node itself.
Is the API key sent in the clear?
On a plain-http LAN connection, yes. A till on a shop network has no certificate and refusing plain http would mean the feature only worked in deployments this product exists not to require. Treat the key as protection against casual misuse on a segment you control, not as transport security.
What happens to the key when I update the firmware?
It survives. Credentials live in non-volatile storage rather than in the image, so an update — pushed over the LAN or pulled unattended — leaves the mode and both keys where they were. The 15-second button hold is the only thing that clears them.
Can I set different keys for different parts of the API?
No. There is one key per node and the tiers decide which routes ask for it. If you need per-caller identity, put the node behind your own service and let that service hold the key.

Related reading