Skip to main content

Consumer Tier 1 — Shared Key

App-assisted onboarding with a Glaze-issued bootstrap key and symmetric MQTT credentials retrieved via GET /get_settings.

This is the simplest onboarding flow. The manufacturer has no PKI — Glaze provisions a bootstrap key for each enrollment group, which the manufacturer flashes onto every device in that group during production. At setup time, a customer app provisions the device to its tenant, and the device uses its bootstrap key to fetch its own MQTT credentials. The device then connects to the broker with username/password — no certificate, no EST.

When to use this flow

Use Tier 1 when the manufacturer cannot operate a PKI or generate OTPs, the device has no secure key generation capability, and mTLS is not a regulatory requirement. This is the lowest barrier to entry for any onboarding model.

Tier 1 trades certificate identity for operational simplicity — MQTT credentials are symmetric (per-device primary + secondary keys), not certificates. Tier 2 / Tier 3 add EST certificates if that matters.

Prerequisites

Manufacturer:

  • Receive a bootstrap key from Glaze per enrollment group (one key per device-batch / SKU)
  • Flash each device with: device_id, bootstrap_key, onboarding URL, Glaze Root CA certificate (for HTTPS trust)

Platform:

  • Beacon Tower onboarding service deployed and reachable
  • Glaze CA operational (only needed for HTTPS server certs; no client certs in this tier)
  • The enrollment group has bootstrap keys generated (POST /api/enrollment-groups/{id}/keys/generate) and a populated response_template that maps {{primaryKey}} / {{secondaryKey}} / {{brokerUrl}} / {{brokerPort}} into the device-facing settings shape

Device hardware:

  • Network connectivity (WiFi via BLE/SoftAP provisioning)
  • TLS client capable of HTTP Basic Auth and basic JSON parsing
  • Persistent storage for the operational MQTT credentials

Sequence Diagram

Flow Walkthrough

Step 1: Provision via App

The customer app scans the device's identifier (QR code, NFC tag, or barcode) and calls onboarding to register and provision the device. Two HTTP calls back-to-back:

# 1a. Register the device — creates the onboarding-side row
curl -X POST https://<onboarding-host>/api/devices/register \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"device_id": "sensor-a1b2c3",
"attestation_type": "shared_key",
"enrollment_group_id": "<enrollment-group-uuid>"
}'

# 1b. Provision — drives the orchestrator chain (onboarding → core-management → mqttprovider)
curl -X POST https://<onboarding-host>/api/provisioning \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"device_id": "sensor-a1b2c3",
"enrollment_group_id": "<enrollment-group-uuid>"
}'
# 201 Created
# {"deviceId":"sensor-a1b2c3","created":true}

The enrollment group defines the tenant, attestation type (shared key), provider configuration, and the device-facing response_template. The orchestrator chain creates the ProviderClient resource in core-management and dispatches a NATS provision to the MQTT provider, which writes the device's MQTT user record and ACL rules. The response is ack-only — credentials live with the provider and are retrieved by the device in step 2.

The app then pushes WiFi credentials plus the bootstrap key to the device over BLE or SoftAP so the device can reach the network and authenticate against /get_settings. The bootstrap key is the enrollment-group-scoped key the manufacturer flashed onto the device; the app does not generate it — it was issued by Glaze when the enrollment group was set up (POST /api/enrollment-groups/{id}/keys/generate).

Step 2: Device Fetches Credentials

Once online, the device calls onboarding's /get_settings endpoint with HTTP Basic Auth (device_id:bootstrap_key) over HTTPS:

GET /get_settings HTTP/1.1
Host: <onboarding-host>
Authorization: Basic c2Vuc29yLWExYjJjMzpib290c3RyYXAta2V5

Onboarding validates the bootstrap key against the enrollment group, resolves the device's MQTT credentials from the provider, and renders them through the enrollment group's response_template. The default response shape is:

{
"deviceId": "sensor-a1b2c3",
"enrollmentGroupId": "<uuid>",
"brokerUrl": "broker.example.com",
"brokerPort": 1883,
"primaryKey": "<symmetric key A>",
"secondaryKey": "<symmetric key B>"
}

The template is per-enrollment-group and customisable — the variable set is {{deviceId}}, {{enrollmentGroupId}}, {{brokerUrl}}, {{brokerPort}}, {{primaryKey}}, {{secondaryKey}}, plus legacy dotted aliases ({{device.id}}, {{device.primary_key}}, {{device.secondary_key}}, {{target.host}}, {{target.port}}).

A successful /get_settings transitions the device state from "provisioned" → "configured" on the onboarding side. Subsequent calls return the same body (idempotent) until the keys are rotated.

Step 3: Connect to Broker

The device opens a plain TCP MQTT connection (port 1883) using username = device_id and password = primaryKey. The broker verifies the credentials against the provider's MQTT user store and grants access to the device's topic namespace.

Step 4: Key Rotation (optional)

If the primary key is rotated or compromised, the device falls back to secondaryKey (retrieved at step 2 alongside primaryKey). To generate a fresh key pair, the customer app calls POST /api/enrollment-groups/{id}/keys/generate (admin scope) and pushes the new keys to the device out-of-band — same channel as the original bootstrap key. There is no device-initiated rotation in this tier.

Lifecycle Operations

The four 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's 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 2's /get_settings: /get_settings is "I just provisioned, give me everything." /reenroll is "I'm already provisioned, tell me where to connect and rotate my MQTT keys if the routing changed."

POST /reenroll
Authorization: Basic <base64(device_id:bootstrap_key)>
StatusMeaning
200Existing routing is healthy — idempotent fast path. Device reconnects with current credentials.
201Routing was refreshed (shard rotation). Response carries new primaryKey + secondaryKey; device must persist them and replace its current primaryKey.
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 call returns 202 Accepted with a Retry-After header instead of rotated 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 succeeds.
    • 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 / reenroll calls fail.
POST /api/devices/{deviceId}/delete-provider-clientTells the provider to evict the MQTT user + ACL rules. Returns 202 Accepted once queued. After this returns, the broker rejects the device's existing MQTT credentials.

Order matters only for which call returns last; both are idempotent. After a revoke the bootstrap key on the device is useless — the soft-delete makes /get_settings fail before key validation.

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 fetch settings or re-enrol.
POST /api/devices/{deviceId}/restoreUndoes the soft-delete. The device's bootstrap key works for /get_settings again; the previously issued primaryKey may or may not still be live at the provider — call /reenroll on first reconnect to be sure.
POST /api/devices/bulk-delete / bulk-restoreBatch variants (NDJSON body).

Security Considerations

  • Symmetric credentials, not certificates — MQTT auth is username/password with the device's primaryKey. No mTLS, no per-device certificate identity. Trade-off in exchange for the lowest device-side complexity.
  • Bootstrap key is enrollment-group-scoped — a single bootstrap key may authorise /get_settings for every device in the enrollment group. Treat it as a batch secret, not a per-device secret. For per-device identity guarantees use Tier 2 (OTP + per-device cert) or Tier 3 (birth-cert + per-device EST cert).
  • HTTPS-only for /get_settings — the bootstrap key travels in an Authorization: Basic header; the device MUST validate the server's TLS certificate against the Glaze Root CA before sending the header.
  • No device-side key generation — this tier does not require hardware security modules or secure enclaves. Suitable for cost-sensitive devices.

Next Steps