Project

Security

The owner key, sign-in, tokens, the broker's users, and how to report a vulnerability.

Roastwarden drives a real heater. Treat anything that can reach its API as able to start a fire, and keep it on a trusted network or behind an authenticating proxy.

There is one owner and no user accounts. What protects the server is one secret, the owner key, and the tokens you make from it.

The owner key

The owner key signs browsers in and makes tokens; everything that changes state needs it or a token. Either set it yourself (ROASTWARDEN_API_KEY, at least 16 characters; a shorter one stops the server at start), or leave it unset: at its first start on a network address the server makes a 48-digit key, saves it as owner.key beside the database (mode 600) and logs it once. Keep it in a password manager. owner.key is not in the database backups, so back up the data directory.

The server runs without a key only on a loopback address, or with ROASTWARDEN_AUTH=off on purpose for a trusted network. It then logs a warning: anyone who can reach it can drive the heater.

Browsers

A browser signs in once with the owner key or a token and gets a login cookie (HttpOnly, SameSite=Strict, Secure behind HTTPS), good for 30 days from its last use. The browser never keeps the key. A write carried by the cookie must come from the dashboard's own page. Settings → This browser lists the signed-in browsers and signs one or all out. A new owner key signs every owner browser out.

What anyone can reach

With a key, reads need a credential too: the API, the live telemetry and /metrics. Open to anyone who reaches the server:

  • the app shell (the page, its scripts, icons and service worker; no data);
  • /healthz, /readyz, /version and the API's description;
  • share pages: a roast's page behind a bag's QR code and a shared profile's page. Each code is random; revoking it makes the page a 404 at once.

ROASTWARDEN_READS=open lets anyone who reaches the server read, for a trusted LAN or a proxy that signs people in. Writes, the audit log and supplier receipts still need a credential; secret settings stay write-only.

Tokens

Give scripts and agents a token, never the key. Make one under Settings → Tokens with a name, an expiry and a preset (Read-only, Roast, Inventory, Admin). The server keeps only a hash and shows the secret once; revoking a token stops it at once. No token can manage tokens, restore a backup, or switch "Tokens may control this roaster", which a roaster needs before any token can control it (Roasters → the roaster → Control). A token that asks first waits for your approval before it starts a roast on a physical roaster or deletes; printing labels and switching a roaster's control on always wait. Details in Agents.

Ten refused keys or tokens from one address within a minute block it for the rest of the minute (429).

The audit log

Every request that changes something is in Settings → Audit, refused ones included: the credential (and a token's name), the user your proxy signed in, the client's address, what was asked and the result. Fields named like a secret are masked. Rows are kept a year.

The roasters' side

  • MQTT. Both the built-in broker and the Mosquitto stack refuse anonymous clients. Each roaster signs in as its device id with its own password (MQTT_DEVICES in .env) and may use only its own topics, so one roaster cannot command another or fake the server going offline. Neither broker has TLS: keep port 1883 on your LAN, never on the internet.
  • Home Assistant, when you turn it on, gets its own broker user that reads Roastwarden's summaries and never a roaster's topics: it cannot command a roaster.
  • The Modbus slave (Artisan as a screen) is off unless ROASTWARDEN_MODBUS_ADDR is set. Modbus has no authentication: whoever reaches the port reads its roaster. It is read-only unless ROASTWARDEN_MODBUS_WRITES=on; then writes pass the same control checks as the API, and each is in the audit log. Never forward the port.
  • Keep the roaster's own safety in the roaster. Its firmware should cut the heater on over-temperature, a failed thermocouple and a lost connection, without waiting for the server. During a profile drive the server renews a short control lease; a roaster that supports it falls back to its safe state when the lease runs out.

What it does not do

  • There are no user accounts and no custom token scopes: the four presets are fixed.
  • A share link shows its roast (coffee, dates, notes, curve, brand) to anyone who has it, past your proxy's login. A QR code on a bag can be photographed. Never the roast's cost or stock.
  • With ROASTWARDEN_READS=open, roasts, costs, settings and the notification channels' addresses are readable by anyone who reaches the server.
  • The ntfy topic and the Gotify and Matrix addresses read like any setting: on a public ntfy server use a long random topic or an access token.

Reporting

Roastwarden is a one-person project. Report a vulnerability privately to the maintainer by email (the address on the commits), not in a public issue. Expect an answer within a week.

Supported versions

Only the latest release and main get fixes.