Device Provisioning Guide¶
Provisioning is the process of creating device records and generating MQTT credentials so physical devices can authenticate with the broker. Django DeviceHub provides three provisioning methods: programmatic, management command, and REST API.
How Credentials Work¶
Each device has three authentication fields on the generated Device model (inherited from BaseDevice):
| Field | Purpose | Storage |
|---|---|---|
mqtt_username |
MQTT login username | Plaintext (formatted as {app_label}-{device_id}) |
mqtt_password_hash |
MQTT login password | Hashed via Django's make_password() |
api_key |
REST API authentication | Plaintext hex token (64 chars) |
When generate_credentials() is called, it:
- Sets
mqtt_usernameto{model_label}-{device_id}(e.g.,myapp-weatherstationdevice-STATION-001) - Generates a random 32-byte URL-safe password via
secrets.token_urlsafe(32) - Hashes the password with Django's
make_password()and stores the hash - Generates a random 64-character hex API key via
secrets.token_hex(32) - Returns a dict with the plaintext values
The plaintext MQTT password is only available at generation time. It cannot be retrieved later -- only verified via check_mqtt_password().
Programmatic Provisioning¶
Single device¶
from myapp.models import WeatherStationDevice
device = WeatherStationDevice.objects.create(
device_id="STATION-001",
name="Field Station Alpha",
)
# Generate credentials (returns plaintext, stores hashed)
credentials = device.generate_credentials()
device.save()
print(credentials)
# {
# "mqtt_username": "myapp-weatherstationdevice-STATION-001",
# "mqtt_password": "dG9rZW4tdXJsc2FmZS0zMi1ieXRlcw...",
# "api_key": "a1b2c3d4e5f6..."
# }
With signal notification¶
The device_provisioned signal fires after provisioning, allowing you to hook in additional logic:
from django_devicehub.signals import device_provisioned
@receiver(device_provisioned)
def on_provisioned(sender, device, credentials, **kwargs):
# Log credentials to a secure vault
vault.store(device.device_id, credentials)
# Send credentials to a provisioning service
flash_device(device.device_id, credentials)
Verifying credentials¶
device = WeatherStationDevice.objects.get(device_id="STATION-001")
# Check MQTT password
if device.check_mqtt_password("the-plaintext-password"):
print("Password is correct")
# Check API key (stored in plaintext)
if device.api_key == submitted_api_key:
print("API key is correct")
Bulk Provisioning via Management Command¶
The iot_provision command creates multiple devices and outputs their credentials:
Output (JSON to stdout):
{
"device_type": "WeatherStation",
"count": 10,
"devices": [
{
"device_id": "weatherstation-001",
"name": "WeatherStation 001",
"device_type": "WeatherStation",
"mqtt_username": "myapp-weatherstationdevice-weatherstation-001",
"mqtt_password": "dG9rZW4t...",
"api_key": "a1b2c3d4..."
},
...
]
}
Command options¶
| Option | Default | Description |
|---|---|---|
device_type |
(required) | Name of a registered DeviceType (case-insensitive) |
--count |
1 |
Number of devices to create |
--prefix |
"" |
Prefix for device IDs |
--output |
(stdout) | Write credentials to a JSON file |
Saving to file¶
python manage.py iot_provision weatherstation \
--count 50 \
--prefix "farm-" \
--output credentials.json
This creates devices with IDs like farm-weatherstation-001 through farm-weatherstation-050 and writes all credentials to credentials.json.
Device ID format¶
The command generates device IDs in the format {prefix}{type_name}-{NNN}:
type_nameis the DeviceType class name in lowercaseNNNis a zero-padded sequential number- The starting index is determined by counting existing devices with the same prefix
Existing devices are skipped (not overwritten).
Security warning¶
The command outputs plaintext credentials. Store them securely:
# Write to file with restricted permissions
python manage.py iot_provision weatherstation --count 10 --output creds.json
chmod 600 creds.json
REST API Provisioning¶
If AUTO_API is enabled (the default) and Django REST Framework is installed, each device type gets a /provision/ action on its ViewSet:
Response:
{
"device_id": "STATION-001",
"credentials": {
"mqtt_username": "myapp-weatherstationdevice-STATION-001",
"mqtt_password": "dG9rZW4t...",
"api_key": "a1b2c3d4..."
},
"topics": {
"data": "myproject/weatherstation/STATION-001/data",
"status": "myproject/weatherstation/STATION-001/status",
"commands": "myproject/weatherstation/STATION-001/cmd"
}
}
The response includes the MQTT topics the device should publish to and subscribe to, making it easy to configure the device firmware.
The device_provisioned signal fires after the API call.
Credential Rotation¶
To rotate credentials for an existing device, call generate_credentials() again:
device = WeatherStationDevice.objects.get(device_id="STATION-001")
new_credentials = device.generate_credentials()
device.save()
This overwrites the previous mqtt_username, mqtt_password_hash, and api_key. The device will need to be updated with the new credentials.
For bulk rotation:
for device in WeatherStationDevice.objects.filter(is_active=True):
creds = device.generate_credentials()
device.save()
# Store or distribute new credentials
distribute_credentials(device.device_id, creds)
API Key Authentication¶
The DeviceAuthBackend supports two authentication methods:
MQTT username/password¶
Used by the broker auth endpoint (/iot/broker/auth/):
from django_devicehub.auth.backends import DeviceAuthBackend
device = DeviceAuthBackend.authenticate("mqtt-username", "mqtt-password")
if device:
print(f"Authenticated: {device.device_id}")
API key¶
Used for REST API device authentication:
device = DeviceAuthBackend.authenticate_api_key("a1b2c3d4...")
if device:
print(f"Authenticated: {device.device_id}")
Both methods search across all registered device models, so they work regardless of which DeviceType the device belongs to. Only active devices (is_active=True) can authenticate.
Device Lifecycle¶
A typical provisioning workflow:
- Create the device record (via admin, API, or management command)
- Provision credentials with
generate_credentials() - Flash the credentials onto the physical device
- Connect -- the device authenticates via MQTT, the broker calls the auth endpoint, and the device is marked online
- Operate -- the device publishes data and status messages
- Rotate credentials periodically for security
- Deactivate -- set
is_active=Falseto block a device without deleting it
Device status values¶
| Status | Description |
|---|---|
online |
Device is connected and sending data |
offline |
Device is disconnected |
error |
Device reported an error |
maintenance |
Device is under maintenance |
low_battery |
Device battery is low |
provisioning |
Device has been created but not yet connected |