Skip to content

Security modes

Every firmware artifact has a security_mode field that describes the level of trust assurance applied during OTA delivery. Set it in the manifest sidecar at upload time.

Modes

basic (default)

Transport security via HTTPS plus a SHA-256 checksum on the artifact.

The OTA check response includes "checksum": "<sha256>" and "size": <bytes>. The device should verify both after download and abort the update if either mismatches; do not flash an artifact whose checksum does not match.

Suitable for: prototyping, hobby projects, and internal fleets where code-signing infrastructure is not yet in place.


token

Per-device token authentication at check-in time.

When security_mode: "token" is set on an artifact, the OTA engine enforces that the device must authenticate with a per-device token. A device presenting only a project token receives {"update_available": false, "status": "token_required"} and no firmware URL.

No change to the firmware binary is required; the security upgrade is entirely at the protocol level (the Authorization header).

Suitable for: production fleets that require per-device authentication and auditability.


signed

Firmware signed with a project-scoped Ed25519 private key that only you hold. Two independent verifications protect the fleet:

  1. At upload: the server verifies the signature in signing_metadata against one of the project's registered public keys before the artifact is accepted. Uploads with a missing, invalid, or revoked-key signature are rejected outright; no build number is consumed.
  2. On device (essential): the OTA check response includes signing_key_id, signature_algorithm, and signature (base64). The device must verify the signature over the exact downloaded bytes against its pinned public key before writing to flash. A tampered image is rejected before any flash operation begins.

The signature covers the raw binary bytes exactly as delivered from the pre-signed URL. Register keys in project settings (Advanced mode) or via the developer API; SimpleOTA stores only the public key.

On Arduino, SimpleOTAClient v0.4.0+ performs the device-side verification automatically once you pin the public key with setSigningPublicKey(). ESP-IDF and custom integrations verify manually; see the guide below.

See the full signed firmware guide for key generation, CI signing commands, and device-side verification code.

Suitable for: commercial fleets where devices must never flash a binary that was not approved by the key holder, even if an account or upload credential is compromised.


How modes are matched

security_mode is a compatibility dimension in the OTA decision engine: an artifact is only offered to a device when the two values are exactly equal, or either side is blank. A device that never reports a mode matches every artifact. The rule is symmetric, which has consequences in both directions:

Device reports basic artifact token artifact signed artifact
(nothing) offered offered offered
basic offered not offered not offered
token not offered offered not offered
signed not offered not offered offered

What this means in practice:

  • A basic device can never receive a signed artifact. Upgrading a fleet to signed therefore goes through one last basic upload whose firmware pins the key and switches the reported mode; see the migration recipe.
  • A signed device can never receive a basic artifact. Once your fleet reports signed, every subsequent upload must be signed; there is no quiet fallback to unsigned releases (that is the point).
  • A blocked device does not error. It receives a normal no_compatible_build response and simply stays on its current build. After changing modes, watch the project device list for devices stuck on old builds; they are the ones still reporting the previous mode.

Choosing a mode

Deployment Recommended mode
Prototyping / hobby project basic
Production fleet, no code-signing infrastructure token
Production fleet with key management signed

Setting the mode

In your manifest sidecar:

{
  "framework": "arduino",
  "version_label": "1.4.2",
  "chip_family": "esp32",
  "security_mode": "token"
}

Valid values are basic, token, and signed. Omitting the field defaults to basic.