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.
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 populatedresponse_templatethat 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)>
| Status | Meaning |
|---|---|
200 | Existing routing is healthy — idempotent fast path. Device reconnects with current credentials. |
201 | Routing was refreshed (shard rotation). Response carries new primaryKey + secondaryKey; device must persist them and replace its current primaryKey. |
202 | Admin approval required — retry after the indicated interval (see below). |
403 | The enrollment group's re-enrollment policy denied the request. |
409 | Re-enroll not supported for the routing target type. |
503 | Provider 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:
- Admin reads the parked request:
GET /api/devices/{deviceRecordId}/pending-reenrollment. - 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 returns403until 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:
| Endpoint | Effect |
|---|---|
DELETE /api/devices/{deviceId} | Soft-deletes the onboarding device record. Subsequent get_settings / reenroll calls fail. |
POST /api/devices/{deviceId}/delete-provider-client | Tells 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:
| Endpoint | Effect |
|---|---|
DELETE /api/devices/{deviceId} | Soft-delete (same as revoke). Device cannot fetch settings or re-enrol. |
POST /api/devices/{deviceId}/restore | Undoes 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-restore | Batch variants (NDJSON body). |
Security Considerations
- Symmetric credentials, not certificates — MQTT auth is
username/passwordwith the device'sprimaryKey. 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_settingsfor 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 anAuthorization: Basicheader; 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
- Consumer Tier 2 — OTP — Higher security with manufacturer-registered OTPs
- Consumer Tier 3 — Birth Certificate — Highest security with manufacturer PKI
- B2B Tier 1 — Shared Key — Same attestation tier without a customer app
- Certificate Onboarding Overview — Decision matrix and key concepts
- Shared-Secret Onboarding — Simpler username/password alternative