Skip to main content

Consumer Tier 2 — OTP

App-assisted onboarding with a manufacturer-issued one-time password and server-generated certificates via EST.

The manufacturer registers devices with the Beacon Tower registry and receives a unique OTP per device. The OTP is flashed onto the device or printed on a label. At setup time, a customer app provisions the device, and the device uses the OTP to authenticate with the onboarding service and EST server. The OTP is permanent — it is never invalidated, allowing the device to re-enroll if its certificate expires.

When to use this flow

Use Tier 2 when the manufacturer can register devices and distribute OTPs but does not operate a full PKI. The device must be able to store keys securely after enrollment. More secure than Tier 1 because the attestation credential (OTP) is generated per-device during manufacturing, not distributed by Beacon Tower.

Prerequisites

Manufacturer:

  • Register devices with the Beacon Tower registry via POST /api/devices/register
  • Receive a unique OTP per device
  • Flash each device with: device_id, otp_token, onboarding service base URL, Beacon Tower Root CA certificate

Platform:

  • Beacon Tower onboarding service deployed
  • Beacon Tower EST server deployed and configured
  • Beacon Tower CA operational
  • Device Registry accessible from EST server

Device hardware:

  • Network connectivity (WiFi via BLE/SoftAP provisioning)
  • TLS client capable of HTTP Basic Auth
  • Secure persistent storage for certificates and private keys

Sequence Diagram

Flow Walkthrough

Manufacturing

The manufacturer registers each device with the Beacon Tower registry:

curl -X POST https://<onboarding-host>/api/devices/register \
-H "Authorization: Bearer $MFG_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"device_id": "charger-x100-001",
"attestation_type": "otp",
"enrollment_group_id": "<enrollment-group-uuid>"
}'

Response:

{
"device_id": "charger-x100-001",
"otp_token": "otp_7f3a9c2e1d..."
}

The manufacturer flashes the device with the device_id, otp_token, onboarding service base URL, and Beacon Tower Root CA certificate.

Step 1: Provision via App

The customer app scans the device and calls the Provision API:

curl -X POST https://<onboarding-host>/api/provisioning \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"device_id": "charger-x100-001",
"enrollment_group_id": "<enrollment-group-uuid>"
}'

The enrollment group defines the tenant, attestation type (OTP), provider template, and routing target. The onboarding service resolves the provider template and provisions the device with the provider.

The app provides WiFi credentials to the device over BLE or SoftAP.

Step 2: Bootstrap Discovery

The device calls the onboarding service to learn where everything is:

curl -X GET https://<onboarding-host>/get_settings \
-H "Authorization: Basic <base64(device_id:otp_token)>"

Response contains the broker URL, EST enrollment URL, and EST renewal URL. The device now knows where to enroll and where to connect.

Step 3: EST Enrollment

  1. Fetch CA chainGET /.well-known/est/cacerts returns the Beacon Tower CA chain.

  2. EnrollPOST /.well-known/est/serverkeygen with HTTP Basic Auth (device_id:otp_token). EST generates the keypair server-side and returns the signed certificate (PKCS#7) and private key (PKCS#8).

  3. OTP preserved — The OTP is validated but NOT invalidated. It remains as the device's permanent credential for future get_settings calls and re-enrollment.

The device stores the certificate and private key in secure persistent storage.

Step 4: Connect to Broker

The device connects to the MQTT broker (URL from Step 2) using mTLS with the operational certificate.

Step 5: Certificate Renewal

Before the certificate expires, the device calls POST /.well-known/est/serverkeygen using its current operational certificate for mTLS authentication. No OTP is needed — the valid certificate proves identity.

Step 6: Re-enrollment (Certificate Expired)

If the certificate expires before renewal (e.g., device was offline too long), the device falls back to OTP authentication: calls get_settings to refresh URLs, then re-enrolls via serverkeygen with Basic Auth. The OTP is permanent, so this always works.

Lifecycle Operations

The six steps above cover the device-driven happy path. The operations below cover the rest of the lifecycle — admin-driven (revoke, disable, approval gating) and device-driven recovery from states the happy path cannot fix on its own (session loss, shard rotation).

Session-loss recovery / shard rotation — POST /reenroll

Used when the device still holds a valid operational certificate but its MQTT session is broken — broker refused CONNECT, MQTT 5 reason 0x82 (session-taken-over) / 0x9C (use-another-server), or the device woke up after a fleet rebalance and its provider shard moved.

Distinct from Step 6 above: Step 6 is "my cert is gone, give me a new one." /reenroll is "my cert is fine, tell me where to connect."

POST /reenroll
Authorization: Basic <base64(device_id:otp_token)> # OTP path
OR
(mTLS with current operational cert) # cert path
StatusMeaning
200Existing routing is healthy — idempotent fast path. Device reconnects with current credentials.
201Routing was refreshed (shard rotation). For cert-based devices the X.509 credentials are unchanged; rotate via Step 5 if needed.
202Admin approval required — retry after the indicated interval (see below).
403The enrollment group's re-enrollment policy denied the request.
409Re-enroll not supported for the routing target type.
503Provider unavailable — retry with backoff.

Rate-limited per device.

Admin-gated approval

An enrollment group can be configured to require an admin decision on every re-enrollment. When that gate is active, the device's /reenroll or /.well-known/est/serverkeygen call returns 202 Accepted with a Retry-After header instead of issuing credentials. The device keeps retrying on that cadence until an admin makes a decision:

  1. Admin reads the parked request: GET /api/devices/{deviceRecordId}/pending-reenrollment.
  2. Admin approves or rejects:
    • POST /api/devices/{deviceRecordId}/pending-reenrollment/approve — next device retry mints the cert.
    • POST /api/devices/{deviceRecordId}/pending-reenrollment/reject — next device retry returns 403 until the parked request expires (group-configured TTL).

Use this for fleets where every re-enrollment must trace back to a human decision.

Revoke a device

Two operations, both admin-only (JWT). Run them together for a full revoke:

EndpointEffect
DELETE /api/devices/{deviceId}Soft-deletes the onboarding device record. Subsequent get_settings / serverkeygen / reenroll calls fail.
POST /api/devices/{deviceId}/delete-provider-clientTells the provider to evict the MQTT user + ACL rules. Returns 202 Accepted once queued.

Order matters only for which call returns last; both are idempotent. After a revoke the OTP is still on file (soft delete is reversible) but the device cannot reach any device-facing endpoint.

Disable / re-enable

Soft-delete is the disable mechanism. Restore brings the device back:

EndpointEffect
DELETE /api/devices/{deviceId}Soft-delete (same as revoke). Device cannot enrol, renew, or re-enrol.
POST /api/devices/{deviceId}/restoreUndoes the soft-delete. Cert (if still valid) works again; OTP still works for get_settings and re-enrollment.
POST /api/devices/bulk-delete / bulk-restoreBatch variants (NDJSON body).

If you re-enable a device whose cert has expired, the device falls back to the Step 6 OTP path on its own.

Security Considerations

  • Permanent OTP — The OTP is never invalidated. It serves as a permanent fallback credential for get_settings and re-enrollment. If the OTP is compromised, only one device is affected (per-device credential).
  • Per-device credential — Each device has a unique OTP, unlike Tier 1 where shared secrets are distributed per enrollment group. A compromised OTP affects only one device.
  • Server-generated keys — The private key is generated by EST and transported once over TLS. After initial enrollment, renewals also generate new keys server-side.
  • Certificate TTL — Determined by the enrollment group configuration. After expiry, the device re-enrolls using its permanent OTP.
  • Secure storage required — The device must protect the private key after receiving it. Without secure storage, consider Tier 3 where keys never leave the device.

Next Steps