blob: f83f7b87ad5f12ce454b974232cda2b6dfe65aad [file] [log] [blame]
openapi: 3.0.1
info:
title: Eclipse Hono™ Device Registry API
description: |
This API defines how to manage *Tenants*, *Devices*, and *Credentials*.
It acts as a common basis which all Hono device registries should
implement.
## Required APIs
All operations, except the `tenants` resource are required. The tenant
management might be outside of the scope of the device registry and
managed by a higher level system. In this case all calls should simply
return `404`. However, if the `tenants` resource is implemented, then all
operations of it must be implemented.
## Security
This specification explicitly leaves out the part of authenticating and
authorizing users with the device registry. It is assumed that some form
of token exchange between the user agent and the backend service will
take place. Like for example HTTP basic authentication, or a bearer token.
## Code generation
This model is not optimized for generating code from it. Code generators
try to understand the model and then translate this into the required
programming language. Even if there would be no bugs in the code
generators, that process would already only be an approximation. So
this model focuses on the description of the API, and does not tweak
the specification in a way to please code generators.
contact:
name: Contact details
url: https://www.eclipse.org/hono/community/get-in-touch/
license:
name: EPL-2.0
url: https://www.eclipse.org/legal/epl-2.0/
version: 1.7.1
externalDocs:
description: Eclipse Hono™ web page
url: https://eclipse.org/hono
tags:
- name: tenants
description: Tenant Management (optional)
externalDocs:
description: Hono Multi-Tenancy
url: https://www.eclipse.org/hono/docs/concepts/tenancy/
- name: devices
description: Device registration
externalDocs:
description: Hono device identity
url: https://www.eclipse.org/hono/docs/concepts/device-identity/
- name: credentials
description: Device credentials
externalDocs:
description: Hono device identity
url: https://www.eclipse.org/hono/docs/concepts/device-identity/
servers:
- url: '{server}/v1'
variables:
server:
default: http://hono.eclipse.org:28080
security:
- BearerAuth: []
- BasicAuth: []
paths:
# Tenant API
/tenants:
post:
tags:
- tenants
summary: Create a new tenant with an auto-generated ID
description: |
Clients use this operation to register a new tenant with an identifier that
is generated by the registry.
operationId: createTenant
requestBody:
description: The configuration properties to register for the tenant.
content:
application/json:
schema:
$ref: '#/components/schemas/Tenant'
examples:
default:
$ref: '#/components/examples/TenantAllAdaptersExample'
mqtt-only:
$ref: '#/components/examples/TenantMqttAdapterOnlyExample'
required: false
responses:
201:
$ref: '#/components/responses/Created'
400:
$ref: '#/components/responses/MalformedRequest'
401:
$ref: '#/components/responses/Unauthorized'
403:
$ref: '#/components/responses/NotAllowed'
409:
description: |
Indicates that an existing tenant uses a certificate authority with the same Subject DN.
If the client has no read access to the conflicting tenant then `403` should be returned instead.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "Root Certificate Authority is already used by other tenant"
subject-dn: "CN=devices,OU=iot,O=ACME"
413:
$ref: '#/components/responses/RequestEntityTooLarge'
get:
tags:
- tenants
summary: Search tenants with optional filters, paging and sorting options.
operationId: searchTenants
parameters:
- $ref: '#/components/parameters/pageSize'
- $ref: '#/components/parameters/pageOffset'
- $ref: '#/components/parameters/filterJson'
- $ref: '#/components/parameters/sortJson'
responses:
200:
description: operation successful
content:
application/json:
schema:
$ref: '#/components/schemas/SearchTenantsResult'
400:
$ref: '#/components/responses/MalformedRequest'
401:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/tenants/{tenantId}:
parameters:
- $ref: '#/components/parameters/tenantId'
post:
tags:
- tenants
summary: Create a new tenant with a given ID
description: |
Clients use this operation to register a new tenant with a given identifier.
operationId: createTenantWithId
requestBody:
description: The configuration properties to register for the tenant.
content:
application/json:
schema:
$ref: '#/components/schemas/Tenant'
examples:
default:
$ref: '#/components/examples/TenantAllAdaptersExample'
mqtt-only:
$ref: '#/components/examples/TenantMqttAdapterOnlyExample'
required: false
responses:
201:
$ref: '#/components/responses/Created'
400:
$ref: '#/components/responses/MalformedRequest'
401:
$ref: '#/components/responses/Unauthorized'
403:
$ref: '#/components/responses/NotAllowed'
409:
description: |
Indicates that a tenant with the given identifier already exists or that an existing tenant uses
a certificate authority with the same Subject DN.
If the client has no read access to the conflicting tenant then `403` should be returned instead.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "tenant with given identifier already exists"
413:
$ref: '#/components/responses/RequestEntityTooLarge'
get:
tags:
- tenants
summary: Get tenant information
description: |
Clients use this operation to retrieve the configuration properties of an existing tenant.
operationId: getTenant
responses:
200:
description: operation successful
content:
application/json:
schema:
$ref: '#/components/schemas/Tenant'
examples:
mqtt-only:
summary: Constrained tenant
description: |
The body contains the configuration properties of a tenant for which
some resource limits have been defined.
value: |
{
"enabled": true,
"resource-limits": {
"max-connections": 1000,
"max-ttl": 3600,
"data-volume": {
"effective-since": "2019-12-01T00:00:00Z",
"max-bytes": 10000000,
"period": {
"mode": "monthly"
}
}
}
}
headers:
ETag:
description: Version of the resource
schema:
type: string
400:
$ref: '#/components/responses/MalformedRequest'
401:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
put:
tags:
- tenants
summary: Update tenant information
description: |
Clients use this operation to replace an existing tenant's registration information
with the information contained in the request body.
operationId: updateTenant
parameters:
- $ref: '#/components/parameters/resourceVersion'
requestBody:
description: The configuration properties to replace the tenant's existing configuration with.
content:
application/json:
schema:
$ref: '#/components/schemas/Tenant'
examples:
disable-tenant:
summary: Disable a tenant
description: |
Disabling a tenant effectively prevents any devices of that tenant
to connect to any of the protocol adapters. Devices that are
already connected to an adapter can no longer upload any data
nor receive any commands. Note that the example payload does
not contain any other properties than *enabled* which means
that all other configuration will be removed.
value: |
{
"enabled": false
}
required: true
responses:
204:
$ref: '#/components/responses/Updated'
400:
$ref: '#/components/responses/MalformedRequest'
401:
$ref: '#/components/responses/Unauthorized'
403:
$ref: '#/components/responses/NotAllowed'
404:
$ref: '#/components/responses/NotFound'
409:
description: |
Indicates that an existing tenant uses a certificate authority with the same Subject DN.
If the client has no read access to the conflicting tenant then `403` should be returned instead.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "Root Certificate Authority is already used by other tenant"
subject-dn: "CN=devices,OU=iot,O=ACME"
412:
$ref: '#/components/responses/ResourceVersionMismatch'
413:
$ref: '#/components/responses/RequestEntityTooLarge'
delete:
tags:
- tenants
summary: Delete tenant
description: |
Clients use this operation to remove an existing tenant from the registry.
When the operation succeeds, the data owned by this tenant (including devices and their
credentials) must no longer be accessible. These entities should be reported as *not found*.
operationId: deleteTenant
parameters:
- $ref: '#/components/parameters/resourceVersion'
responses:
204:
$ref: '#/components/responses/Deleted'
401:
$ref: '#/components/responses/Unauthorized'
403:
$ref: '#/components/responses/NotAllowed'
404:
$ref: '#/components/responses/NotFound'
412:
$ref: '#/components/responses/ResourceVersionMismatch'
# Device API
/devices/{tenantId}:
parameters:
- $ref: '#/components/parameters/tenantId'
post:
tags:
- devices
summary: Create a new device registration with auto-generated ID
description: |
Clients use this operation to register a new device for an existing tenant with
an identifier that is generated by the registry.
operationId: createDeviceRegistration
requestBody:
description: The configuration properties to register for the device.
content:
application/json:
schema:
$ref: '#/components/schemas/Device'
examples:
default:
$ref: '#/components/examples/DeviceDefaultExample'
extensions:
$ref: '#/components/examples/DeviceExtExample'
required: false
responses:
201:
$ref: '#/components/responses/Created'
400:
$ref: '#/components/responses/MalformedRequest'
401:
$ref: '#/components/responses/Unauthorized'
403:
$ref: '#/components/responses/NotAllowed'
404:
$ref: '#/components/responses/TenantNotFound'
413:
$ref: '#/components/responses/RequestEntityTooLarge'
get:
tags:
- devices
summary: Search devices for a tenant with optional filters, paging and sorting options.
operationId: searchDevicesForTenant
parameters:
- $ref: '#/components/parameters/pageSize'
- $ref: '#/components/parameters/pageOffset'
- $ref: '#/components/parameters/filterJson'
- $ref: '#/components/parameters/sortJson'
responses:
200:
description: operation successful
content:
application/json:
schema:
$ref: '#/components/schemas/SearchDevicesResult'
400:
$ref: '#/components/responses/MalformedRequest'
401:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/devices/{tenantId}/{deviceId}:
parameters:
- $ref: '#/components/parameters/tenantId'
- $ref: '#/components/parameters/deviceId'
post:
tags:
- devices
summary: Create a new device registration
description: |
Clients use this operation to register a new device for an existing tenant with
a given identifier
operationId: createDeviceRegistrationWithId
requestBody:
description: The configuration properties to register for the device.
content:
application/json:
schema:
$ref: '#/components/schemas/Device'
examples:
default:
$ref: '#/components/examples/DeviceDefaultExample'
extensions:
$ref: '#/components/examples/DeviceExtExample'
required: false
responses:
201:
$ref: '#/components/responses/Created'
400:
$ref: '#/components/responses/MalformedRequest'
401:
$ref: '#/components/responses/Unauthorized'
403:
$ref: '#/components/responses/NotAllowed'
409:
$ref: '#/components/responses/AlreadyExists'
404:
$ref: '#/components/responses/TenantNotFound'
413:
$ref: '#/components/responses/RequestEntityTooLarge'
get:
tags:
- devices
summary: Get device registration information
description: |
Clients use this operation to retrieve the configuration properties of an existing device.
operationId: getRegistration
responses:
200:
description: operation successful
content:
application/json:
schema:
$ref: '#/components/schemas/Device'
examples:
fully-configured:
summary: Fully configured device
description: |
The body contains the configuration properties of a device which
has been configured extensively.
value: |
{
"enabled": true,
"defaults": {
"ttl": 300,
"content-type": "application/vnd.acme+json"
},
"via": [
"gw-1", "gw-4"
],
"status": {
"created": "2019-10-03T13:45:16Z"
"updated": "2020-05-04T10:11:12Z"
"last-user": "Bob",
"autoProvisioned": false,
"autoProvisioningNotificationSent": false
}
"ext": {
"manufacturer": "ACME",
"model-no": "TEMP-SEN",
"serial-no": "3435A-454"
}
}
headers:
ETag:
description: Version of the resource
schema:
type: string
400:
$ref: '#/components/responses/MalformedRequest'
401:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
put:
tags:
- devices
summary: Update an existing device registration
description: |
Clients use this operation to replace an existing device's registration information
with the information contained in the request body.
operationId: updateRegistration
parameters:
- $ref: '#/components/parameters/resourceVersion'
requestBody:
description: The configuration properties to replace the device's existing configuration with.
content:
application/json:
schema:
$ref: '#/components/schemas/Device'
examples:
disable-device:
summary: Disable a device
description: |
Disabling a device effectively prevents the device
to connect to any of the protocol adapters. If the device is
already connected to an adapter then it can no longer upload
any data nor receive any commands. Note that the example payload does
not contain any other properties than *enabled* which means
that all other configuration will be removed.
value: |
{
"enabled": false
}
required: true
responses:
204:
$ref: '#/components/responses/Updated'
400:
$ref: '#/components/responses/MalformedRequest'
401:
$ref: '#/components/responses/Unauthorized'
403:
$ref: '#/components/responses/NotAllowed'
404:
$ref: '#/components/responses/NotFound'
412:
$ref: '#/components/responses/ResourceVersionMismatch'
413:
$ref: '#/components/responses/RequestEntityTooLarge'
delete:
tags:
- devices
summary: Delete an existing device registration
description: |
Clients use this operation to remove an existing device from the registry.
When the operation succeeds, the data owned by this device (including its credentials)
must no longer be accessible. These entities should be reported as *not found*.
operationId: deleteRegistration
parameters:
- $ref: '#/components/parameters/resourceVersion'
responses:
204:
$ref: '#/components/responses/Deleted'
401:
$ref: '#/components/responses/Unauthorized'
403:
$ref: '#/components/responses/NotAllowed'
404:
$ref: '#/components/responses/NotFound'
412:
$ref: '#/components/responses/ResourceVersionMismatch'
/credentials/{tenantId}/{deviceId}:
parameters:
- $ref: '#/components/parameters/tenantId'
- $ref: '#/components/parameters/deviceId'
get:
tags:
- credentials
summary: Gets a device's set of credentials.
description: |
Clients use this operation to retrieve the set of credentials registered for an existing device.
Hono's protocol adapters use the credentials registered for a device in order to
authenticate the device when it connects to an adapter.
Implementors may return all of the credentials' data including all
details of its secrets like password hash and/or hash algortihm used.
This mode of operation is called *replace mode*. However, this behavior is
discouraged because it might disclose confidential information in plain text.
Instead, implementors should remove all confidential information from the secrets
and include a (unique) identifier with each secret. Clients can then refer to
this identifier in order to update particular secrets. This mode of operation
is called *patch mode*.
operationId: getAllCredentials
responses:
200:
description: Operation successful
content:
application/json:
schema:
$ref: '#/components/schemas/CredentialsSet'
examples:
meta-data:
$ref: '#/components/examples/CredentialsMetaDataExample'
headers:
ETag:
description: Version of the resource
schema:
type: string
400:
$ref: '#/components/responses/MalformedRequest'
401:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/DeviceNotFound'
put:
tags:
- credentials
summary: Updates a device's credentials.
description: |
A client uses this operation to update a device's existing set of credentials
with the credentials contained in the request body.
A registry may run in one of two modes for updating credentials, *replace mode*
or *patch mode*. A client can determine the mode of operation by means of inspecting
any of the secrets returned by the *getAllCredentials* operation. If the secrets
do not contain an `id` property, then the registry uses *replace mode*, otherwise
it operates in *patch mode*.
In replace mode the registry simply replaces a device's existing set of credentials
with the credentials provided in the request body.
In patch mode the registry processes the set of updated credentials provided in the
request body as follows.
1. Start with an empty set `N` of new credentials.
1. For each updated credentials object `c-U` contained in the request body,
the registry looks up an existing credentials object `c-E` of the same device ID, type
and authentication identifier.
1. If no matching credentials object exists, `c-U` is added to the set of new
credentials `N`.
1. Otherwise, `c-E` is patched over with `c-U` as follows. For each of `c-U`'s
secrets `s-U` the registry does the following
1. If `s-U` has no `id` property, the registry assigns a unique identifier to `s-U`.
1. Otherwise, the registry tries to find a secret `s-E` with the same identifier as `s-U`
among the secrets of `c-E`.
1. If no matching secret exists, updating the credentials has failed and the registry
returns a response with status 400 (Bad Request).
1. Otherwise the confidential properties of `s-E` are merged into `s-U`
with the property values of `s-U` taking precedence.
1. `c-U` is added to `N`.
1. The registry replaces the device's existing set of credentials with `N` and returns an
empty response with status code 204 (No Content) to indicate the successful outcome of the
operation.
Note that `N` does not contain any of the existing credentials objects `c-E` for which
no corresponding credentials object `c-U` with the same device ID, type and authentication
identifier exists. This way, existing credentials can be deleted.
operationId: setAllCredentials
parameters:
- $ref: '#/components/parameters/resourceVersion'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CredentialsSet'
examples:
set-password:
$ref: '#/components/examples/CredentialsSetPasswordExample'
change-password:
$ref: '#/components/examples/CredentialsChangePasswordExample'
required: true
responses:
204:
$ref: '#/components/responses/Updated'
400:
$ref: '#/components/responses/MalformedRequest'
401:
$ref: '#/components/responses/Unauthorized'
403:
$ref: '#/components/responses/NotAllowed'
404:
$ref: '#/components/responses/DeviceNotFound'
409:
$ref: '#/components/responses/AlreadyExists'
412:
$ref: '#/components/responses/ResourceVersionMismatch'
413:
$ref: '#/components/responses/RequestEntityTooLarge'
components:
schemas:
# Common schema
Error:
type: object
additionalProperties: true
required:
- error
properties:
"error":
type: string
description: A human readable error message of what went wrong.
DefaultProperties:
type: object
additionalProperties: true
description: Defaults for properties defined on the tenant and device level.
Extensions:
type: object
additionalProperties: true
description: Allows arbitrary properties as extension to the ones
specified by the Hono API.
# Tenant schema
Tenant:
type: object
additionalProperties: false
properties:
"enabled":
type: boolean
default: true
"ext":
$ref: '#/components/schemas/Extensions'
"adapters":
type: array
description: |
A list of configuration options for certain types of protocol adapters.
If set then the array must not be empty.
Multiple entries for the same type are considered an error.
If not set, then all adapters are enabled using their respective
default configuration.
items:
$ref: '#/components/schemas/Adapter'
"defaults":
$ref: '#/components/schemas/DefaultProperties'
"minimum-message-size":
type: integer
default: 0
description: |
The minimum message size in bytes. If set, then reported size of
telemetry, event and command messages is calculated as the minimum multiple
of the configured value that is greater than or equal to the messages
payload size.
"resource-limits":
$ref: '#/components/schemas/ResourceLimit'
"tracing":
$ref: '#/components/schemas/TracingConfig'
"trusted-ca":
type: array
description: |
The set of root certificate authorities which are used for verifying the signature of
client certificates that devices use for authentication.
items:
$ref: '#/components/schemas/TrustedCA'
TenantWithId:
type: object
additionalProperties: false
allOf:
- type: object
properties:
"id":
description: The identifier of the tenant.
type: string
- $ref: '#/components/schemas/Tenant'
TrustedCA:
type: object
additionalProperties: false
properties:
"id":
type: string
required: false
description: |
The identifier of the trust anchor. This identifier must be unique
among a tenant's trust anchors. If this property is not provided,
then the device registry assigns a unique identifier.
example: A user provided identifier could look like "DEFAULT_TENANT_CA_2021_2022".
"subject-dn":
type: string
description: |
The subject DN of the trusted root certificate in
the format defined by [RFC 2253](https://tools.ietf.org/html/rfc2253#section-2).
CAs of the *same* tenant may share the same subject DN, for example
allowing for the definition of overlapping validity periods.
However, CAs of *different* tenants must not share the same
subject DN in order to allow for the unique look up of a tenant by
the subject DN of one of its trusted CAs.
If the `cert` property is used to provide an X.509 certificate
then the subject DN is determined from the certificate and this
property is ignored.
Otherwise, if the `public-key` property is
used, this property is mandatory.
"public-key":
type: string
format: byte
description: |
The Base64 encoded binary DER encoding of the
trusted root certificate’s public key.
If the `cert` property is used to provide an
X.509 certificate then the public key is extracted
from the certificate and this property is ignored.
Either this property or `cert` must be set.
"algorithm":
type: string
description: |
The algorithm used for the public key of the CA.
If the `cert` property is used to provide an
X.509 certificate then the algorithm is determined
from the certificate and this property is ignored.
Otherwise, if the `public-key` property is
used, this property must be set to the algorithm
used, if other than the default.
default: RSA
example: EC
"not-before":
type: string
format: date-time
description: |
The point in time from which on the certificate authority
may be used for authenticating devices.
If the `cert` property is used to provide an
X.509 certificate then the point in time is
determined from the certificate and this property is ignored.
Otherwise, if the `public-key` property is
used, this property is mandatory.
NB: The value MUST be a string that complies with the format defined in
[RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6) as indicated
by the [date-time](http://spec.openapis.org/oas/v3.0.1#dataTypeFormat)
format in the OpenAPI specification.
"not-after":
type: string
format: date-time
description: |
The point in time until which the certificate authority
may be used for authenticating devices.
If the `cert` property is used to provide an
X.509 certificate then the point in time is
determined from the certificate and this property is ignored.
Otherwise, if the `public-key` property is
used, this property is mandatory.
NB: The value MUST be a string that complies with the format defined in
[RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6) as indicated
by the [date-time](http://spec.openapis.org/oas/v3.0.1#dataTypeFormat)
format in the OpenAPI specification.
"cert":
type: string
format: byte
description: |
The Base64 encoded binary DER encoding of the trusted X.509 root certificate.
This property can be used as a convenient alternative to
specifying the `public-key`, `not-before`, `not-after` and
`algorithm` properties explicitly. Implementors of this
API may choose to support this property only for uploading
a certificate but then extract all relevant data and store
it in the properties described above.
Either this property or `public-key` must be set.
"auto-provisioning-enabled":
type: boolean
default: false
description: |
Indicates whether this trusted certificate may be used for automatically provisioning devices.
If it is *true* and the feature is supported by the device registry, the device registry
automatically provisions unregistered devices that authenticate with a client certificate
issued by this CA (that is, creates registration and credentials).
example:
subject-dn: "CN=devices,OU=iot,O=ACME"
public-key: "Tk9UIEEgUFVCTElDIEtFWQ=="
algorithm: "EC"
auto-provisioning-enabled: false
not-before: "2019-10-03T13:45:16+02:00"
not-after: "2021-10-03T00:00:00Z"
Adapter:
type: object
additionalProperties: true
required:
- type
properties:
"type":
type: string
"enabled":
type: boolean
default: false
"device-authentication-required":
type: boolean
default: true
"ext":
$ref: '#/components/schemas/Extensions'
ResourceLimit:
type: object
additionalProperties: false
properties:
"max-connections":
type: integer
default: -1
description: |
The maximum number of concurrent connections allowed from devices of this tenant.
A value of `-1` (the default) indicates that no limit is set.
"max-ttl":
type: integer
default: -1
description: |
The maximum time-to-live (in seconds) to use for events published by
devices of this tenant. Any default TTL value specified
at either the tenant or device level will be limited to
the max value specified here.
If this property is set to a value greater than -1 and no
default TTL is specified for a device, the max value will
be used for events published by the device.
A value of `-1` (the default) indicates that no limit is set.
Note that this property contains the TTL in seconds whereas
the AMQP 1.0 specification defines a message's ttl header
to use milliseconds.
"data-volume":
$ref: '#/components/schemas/DataVolume'
"connection-duration":
$ref: '#/components/schemas/ConnectionDuration'
"ext":
$ref: '#/components/schemas/Extensions'
TracingConfig:
type: object
additionalProperties: false
properties:
"sampling-mode":
type: string
description: |
Defines if and how often OpenTracing spans are being
sampled when processing messages for this tenant.
The value `default` indicates that the underyling tracing
system's default sampling mode should be used.
The value `all` indicates that every span created for
messages of the tenant will be sampled.
The value `none` indicates that no spans should be sampled
at all for the tenant.
The mode defined here may be overridden for specific
devices by means of the `sampling-mode-per-auth-id`
property.
default: default
enum:
- default
- all
- none
"sampling-mode-per-auth-id":
type: object
description: |
Defines if and how often OpenTracing spans are being
sampled when processing messages for specific devices
of this tenant.
This object contains a property for each device for which
specific behavior should be defined, using the device's
authentication identifier as the property name and
the device specific sampling mode as its value.
The value `default` indicates that the underyling tracing
system's default sampling mode should be used.
The value `all` indicates that every span created for
messages of the tenant will be sampled.
The value `none` indicates that no spans should be sampled
at all for the tenant.
The mode defined for a particular device has precedence
over the value defined by the `sampling-mode` property.
additionalProperties:
type: string
description: |
The property name is the device's 'authentication identifier.
default: default
enum:
- default
- all
- none
DataVolume:
type: object
additionalProperties: false
required:
- effective-since
properties:
"effective-since":
type: string
format: date-time
description: |
The point in time at which the data volume limit came into effect.
NB: The value MUST be a string that complies with the format defined in
[RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6) as indicated
by the [date-time](http://spec.openapis.org/oas/v3.0.1#dataTypeFormat)
format in the OpenAPI specification.
"max-bytes":
type: integer
default: -1
description: The maximum amount of data (in bytes) that all of the tenant's devices together may
transfer to and/or receive from protocol adapters during each accounting period.
A value of `-1` (the default) indicates that no limit is set.
"period":
$ref: '#/components/schemas/Period'
ConnectionDuration:
type: object
additionalProperties: false
required:
- effective-since
properties:
"effective-since":
type: string
format: date-time
description: |
The point in time at which the connection duration limit came into effect.
NB: The value MUST be a string that complies with the format defined in
[RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6) as indicated
by the [date-time](http://spec.openapis.org/oas/v3.0.1#dataTypeFormat)
format in the OpenAPI specification.
"max-minutes":
type: integer
default: -1
description: |
The maximum amount of time (in minutes) that all of the tenant's devices together may
be connected to a protocol adapter during each accounting period.
A value of `-1` (the default) indicates that no limit is set.
"period":
$ref: '#/components/schemas/Period'
Period:
type: object
additionalProperties: false
required:
- mode
properties:
"mode":
type: string
description: |
The accounting period's mode of recurrence. The following modes are defined:
* `monthly`: Accounting periods start at midnight (start of day) UTC on the 1st day of each month.
* `days`: Accounting periods start at the time of the initial accounting period every *N* days where
*N* is the value of the *no-of-days* property.
The initial accounting period always starts at the point in time that the plan was put in effect at.
Implementations MUST support the *monthly* and *days* modes and MAY support additional custom modes.
"no-of-days":
type: integer
minimum: 1
description: The accounting period length in days. This property is only used if *mode* is set to value
`days`. Otherwise, this property is ignored.
# Devices schema
Device:
type: object
additionalProperties: false
properties:
"enabled":
type: boolean
default: true
"defaults":
$ref: '#/components/schemas/DefaultProperties'
"via":
type: array
items:
type: string
description: |
The device IDs of the gateways that are registered to act on behalf of this device.
Note that "via" and "memberOf" must not be set at the same time.
"viaGroups":
type: array
items:
type: string
description: |
The IDs of the gateway groups that are registered to act on behalf of this device.
Note that "viaGroups" and "memberOf" must not be set at the same time.
"memberOf":
type: array
items:
type: string
description: |
The IDs of the gateway groups that this device is a member of.
Note that neither "via" nor "viaGroups" must be set if "memberOf" is set.
"authorities":
type: array
items:
type: string
description: |
The authorities granted to a device. Applies to gateways only currently: the authority
`auto-provisioning-enabled` entitles a gateway device to perform auto-provisioning for its
edge devices.
"downstream-message-mapper":
type: string
description: |
The name of a service that can be used by protocol adapters to transform downstream messages
uploaded by devices before sending them to downstream consumers.
The protocol adapter needs to map this name to the particular service to invoke.
NB: This is an experimental feature and thus this property is subject to change without
notice.
"upstream-message-mapper":
type: string
description: |
The name of a service that can be used by protocol adapters to transform upstream commands to be sent to devices.
The protocol adapter needs to map this name to the particular service to invoke.
NB: This is an experimental feature and thus this property is subject to change without
notice.
"ext":
$ref: '#/components/schemas/Extensions'
"status":
$ref: '#/components/schemas/Status'
"command-endpoint":
type: object
additionalProperties: false
description: |
The endpoint of the device that command messages should be sent to. Only relevant for devices
that connect to a type of protocol adapter that actively connects to the device for sending commands,
instead of using a connection initiated by the device.
required:
- uri
properties:
"uri":
type: string
description: |
Configures the URI to which the command should be sent. The placeholder `{{deviceId}}` is
supported and will be replaced with the id of the device to which the command was initially
sent.
"headers":
type: object
additionalProperties: true
description: Allows arbitrary headers which will be added to the command.
"payload-properties":
type: object
additionalProperties: true
description: Allows arbitrary properties which will be added to the command payload.
DeviceWithId:
type: object
additionalProperties: false
allOf:
- type: object
properties:
"id":
description: The identifier of the device.
type: string
readOnly: true
- $ref: '#/components/schemas/Device'
Status:
type: object
additionalProperties: false
description: |
Additional meta data describing the entity.
properties:
"created":
type: string
format: date-time
readOnly: true
description: The point in time when the entity was originally created.
"updated":
type: string
format: date-time
readOnly: true
description: The point in time when the entity was last updated.
"last-user":
type: string
readOnly: true
description: The user who made the last edit on this entity.
"auto-provisioned":
type: boolean
default: false
readOnly: true
description: Indicates if the entity was created via auto-provisioning.
"auto-provisioning-notification-sent":
type: boolean
default: false
readOnly: true
description: Indicates if downstream consumers have been notified about the newly auto-provisioned
entity by means of a corresponding event.
SearchTenantsResult:
type: object
description: The result of a search request for tenants.
additionalProperties: false
properties:
"total":
type: integer
minimum: 0
description: The total number of objects in the result set, regardless of the *pageSize* set in query.
"result":
type: array
items:
$ref: '#/components/schemas/TenantWithId'
SearchDevicesResult:
type: object
description: The result of a search request for devices.
additionalProperties: false
properties:
"total":
type: integer
minimum: 0
description: The total number of objects in the result set, regardless of the *pageSize* set in query.
"result":
type: array
items:
$ref: '#/components/schemas/DeviceWithId'
# Credentials
CredentialsSet:
type: array
description: A set of credentials. The entries in this list must be
unique by the composite key of `auth-id` and `type`.
items:
$ref: '#/components/schemas/TypedCredentials'
TypedCredentials:
additionalProperties: false
oneOf:
- $ref: '#/components/schemas/PasswordCredentials'
- $ref: '#/components/schemas/PSKCredentials'
- $ref: '#/components/schemas/X509CertificateCredentials'
discriminator:
propertyName: type
mapping:
"hashed-password": '#/components/schemas/PasswordCredentials'
"psk": '#/components/schemas/PSKCredentials'
"x509-cert": '#/components/schemas/X509CertificateCredentials'
CommonCredentials:
type: object
additionalProperties: false
properties:
"type":
type: string
"auth-id":
type: string
"enabled":
type: boolean
default: true
"ext":
$ref: '#/components/schemas/Extensions'
PasswordCredentials:
additionalProperties: false
allOf:
- $ref: '#/components/schemas/CommonCredentials'
- type: object
required:
- type
- auth-id
- secrets
additionalProperties: false
properties:
"type":
type: string
pattern: "hashed-password"
"auth-id":
type: string
description: |
The authentication identifier provided by the device as part of the *user name*.
Example: For user name `sensor1@DEFAULT_TENANT` the authentication identifier to be registered
is `sensor1`.
"secrets":
type: array
items:
$ref: '#/components/schemas/PasswordSecret'
minItems: 1
PSKCredentials:
additionalProperties: false
allOf:
- $ref: '#/components/schemas/CommonCredentials'
- type: object
required:
- type
- auth-id
- secrets
additionalProperties: false
properties:
"type":
type: string
pattern: "psk"
"auth-id":
type: string
description: The *PSK identity* provided by the device in the TLS handshake.
"secrets":
type: array
items:
$ref: '#/components/schemas/PSKSecret'
minItems: 1
X509CertificateCredentials:
additionalProperties: false
allOf:
- $ref: '#/components/schemas/CommonCredentials'
- type: object
required:
- type
additionalProperties: false
properties:
"type":
type: string
pattern: "x509-cert"
"auth-id":
type: string
description: |
The *subject DN* of the public key contained in the device's X.509 certificate.
The value MUST be formatted according to the rules defined in
[RFC 2253](https://tools.ietf.org/html/rfc2253#section-2).
"secrets":
type: array
items:
$ref: '#/components/schemas/X509CertificateSecret'
description: |
A secret containing the X.509 certificate's validity period.
minItems: 1
maxItems: 1
"cert":
type: string
format: byte
writeOnly: true
description: |
The Base64 encoded binary DER encoding of the device's X.509 client certificate.
This property can be used as a convenient alternative to specifying the certificate's
meta data in the *auth-id* and *secrets* explicitly.
When provided in a request body, implementors of this API MUST extract the subject DN
from the certificate's public key and store its value properly formatted to the *auth-id*
property. The certificate's validity period MUST be stored in a single secret.
The certificate itself must then be discarded.
CommonSecret:
type: object
additionalProperties: false
properties:
"id":
type: string
description: The device registry can assign an identity to the secret.
This value can be used to update secrets based on their metadata.
"enabled":
type: boolean
default: true
description: Indicates if this secret can be used for authentication.
"not-before":
type: string
format: date-time
description: |
The point in time from which on this secret will be accepted for authentication.
NB: The value MUST be a string that complies with the format defined in
[RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6) as indicated
by the [date-time](http://spec.openapis.org/oas/v3.0.1#dataTypeFormat)
format in the OpenAPI specification.
"not-after":
type: string
format: date-time
description: |
The point in time after which this secret will no longer be accepted for authentication.
NB: The value MUST be a string that complies with the format defined in
[RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6) as indicated
by the [date-time](http://spec.openapis.org/oas/v3.0.1#dataTypeFormat)
format in the OpenAPI specification.
"comment":
type: string
X509CertificateSecret:
additionalProperties: false
allOf:
- $ref: '#/components/schemas/CommonSecret'
PasswordSecret:
additionalProperties: false
allOf:
- $ref: '#/components/schemas/CommonSecret'
- type: object
additionalProperties: false
properties:
"hash-function":
type: string
example: bcrypt
description: The name of the hash function used to create the password hash (defined in `pwd-hash` property).
If the password is defined using a `pwd-plain` property, this value will be ignored by the device registry.
This property should be empty when returning passwords from the device registry using only secret metadata.
In this case the id field must be set instead.
"pwd-hash":
type: string
description: The password hash as a string, either the output of applying the Bcrypt hash function
to the clear text password if the `hash-function` is `bcrypt`, or otherwise the Base64 encoding
of the bytes resulting from applying the hash function to the byte array consisting of the salt bytes
(if a salt is used) and the UTF-8 encoding of the clear text password.
For detail regarding different hash functions and the required encoding refer to the
[Credentials API](https://www.eclipse.org/hono/docs/api/credentials/#hashed-password).
If the password is defined using a `pwd-plain` property, this value will be ignored by the device registry.
This property should be empty when returning passwords from the device registry using only secret metadata.
In this case the id field must be set instead.
"salt":
type: string
format: byte
description: The Base64 encoding of the salt used in the password hash (defined in the `pwd-hash` property).
If the password is defined using a `pwd-plain` property, this value will be ignored by the device registry.
This property should be empty when returning passwords from the device registry using only secret metadata.
In this case the id field must be set instead.
"pwd-plain":
type: string
writeOnly: true
description: The clear text value of the password to be hashed by the device registry.
If this property is specified, the device registry will ignore user-provided hash properties (`hash-function`, `pwd-hash` and `salt`).
This property must never be included in a response from the device registry.
A device registry implementation must never write plain text passwords to a persistent store.
PSKSecret:
additionalProperties: false
allOf:
- $ref: '#/components/schemas/CommonSecret'
- type: object
additionalProperties: false
required:
- key
properties:
"key":
type: string
format: byte
description: The secret key shared between device and Hono.
FilterJson:
description: Filters to be applied to bulk queries.
additionalProperties: false
required:
- field
- value
properties:
"field":
type: string
description: |
A [Json Pointer](https://tools.ietf.org/html/rfc6901) identifying the field to use for filtering.
"op":
type: string
description: The operator to use when applying the filter.
default: eq
enum:
- eq
"value":
oneOf:
- type: boolean
description: The value to filter the boolean typed field with.
- type: integer
description: The value to filter the integer typed field with.
- type: number
description: The value to filter the number typed field with.
- type: string
description: |
The value to filter the string typed field with.
Wildcard characters are supported : `*` will match zero or any number of characters
and `?` will match exactly one character.
parameters:
resourceVersion:
name: If-Match
in: header
description: The expected resource version
required: false
schema:
type: string
tenantId:
name: tenantId
in: path
description: The ID of the tenant
required: true
schema:
type: string
example: DEFAULT_TENANT
deviceId:
name: deviceId
in: path
description: The ID of the device
required: true
schema:
type: string
example: 4711
pageSize:
name: pageSize
in: query
description: |
The maximum number of objects to include in a response.
required: false
schema:
type: integer
minimum: 0
maximum: 200
default: 30
pageOffset:
name: pageOffset
in: query
description: |
The offset into the result set from which to include objects in the response. This allows to retrieve the whole result set page by page.
required: false
schema:
type: integer
minimum: 0
default: 0
filterJson:
name: filterJson
in: query
description: |
A predicate that objects in the result set must match. If this parameter is specified multiple
times, objects in the result set must match all predicates.
The predicate is specified as a string representing a JSON object complying with the following schema
```
{
"type": "object",
"additionalProperties": false,
"required": ["field", "value"],
"properties": {
"field": {
"type": "string",
"description": "A Json Pointer (https://tools.ietf.org/html/rfc6901) identifying the field to use for filtering."
},
"op": {
"type": "string",
"description": "The operator to apply.",
"default": "eq",
"enum": ["eq"]
},
"value": {
"oneOf": [
{
"type": "boolean",
"description": "The value to filter the boolean typed field with."
},{
"type": "number",
"description": "The value to filter the number typed field with."
},{
"type": "string",
"description": "The value to filter the string typed field with.
Wildcard characters are supported : `*` will match zero or any number of characters
and `?` will match exactly one character."
}
]
}
}
}
```
required: false
schema:
type: string
examples:
boolean field:
value: "{\"field\": \"/enabled\",\"value\": true}"
number field:
value: "{\"field\": \"/ext/count\",\"value\": 15}"
string field:
value: "{\"field\": \"/ext/brand\",\"value\": \"eclipse*\"}"
sortJson:
name: sortJson
in: query
description: |
Specifies a property to sort the result set by. If this parameter is specified multiple
times, the sort options are applied in the order they are specified in the query string.
The sort option is specified as a string representing a JSON object complying with the following schema
```
{
"type": "object",
"additionalProperties": false,
"required": ["field"],
"properties": {
"field": {
"type": "string",
"description": "A Json Pointer (https://tools.ietf.org/html/rfc6901) identifying the field to sort by."
},
"direction": {
"type": "string",
"description": "The sort direction.",
"default": "asc",
"enum": ["asc", "desc"]
}
}
}
```
required: false
schema:
type: string
examples:
sort ascending:
value: "{\"field\":\"/ext/brand\"}"
sort descending:
value: "{\"field\":\"/status/created\",\"direction\":\"desc\"}"
responses:
Unauthorized:
description: Authentication credentials are required, but missing.
headers:
"WWW-Authenticate":
schema:
type: string
Created:
description: Object created.
headers:
Location:
description: URL to the resource
schema:
type: string
format: uri
ETag:
description: The new version of the resource
schema:
type: string
content:
application/json:
schema:
type: object
additionalProperties: false
required:
- id
properties:
id:
type: string
description: The ID of the created object
Updated:
description: Object updated.
headers:
ETag:
description: The new version of the resource
schema:
type: string
Deleted:
description: Object deleted.
NotFound:
description: |
Object not found. This may also be returned for some operations
if the user lacks authorization to read the subject of the operation.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
TenantNotFound:
description: |
The referenced tenant could not be found.
This may also be returned for some operations
if the user lacks authorization to read the tenant.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
DeviceNotFound:
description: |
The referenced device could not be found.
This may also be returned for some operations
if the user lacks authorization to read the device.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
NotAllowed:
description: |
Operation not allowed. If the user does not have read access
for this object, then `404` will be returned instead.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
MalformedRequest:
description: Malformed request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
AlreadyExists:
description: |
Object already exists. If the user has no read access for
the existing object, then `403` should be returned instead.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
ResourceVersionMismatch:
description: |
Expected resource version does not match current.
This can only happen when the request header `If-Match`
was set.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
RequestEntityTooLarge:
description: |
The size of the payload in the request body exceeds the registry's configured limit.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
securitySchemes:
BearerAuth:
type: http
scheme: bearer
BasicAuth:
type: http
scheme: basic
examples:
TenantAllAdaptersExample:
summary: All adapters
description: |
An empty request body can be used to create a tenant
using default values. This means that the tenant will be
enabled and devices of the tenant may connect to all
protocol adapters.
value:
TenantMqttAdapterOnlyExample:
summary: MQTT adapter only
description: |
Creates a tenant with only the MQTT adapter enabled.
Devices of the tenant will thus not be able to connect
to any adapter other than the MQTT adapter.
value: |
{
"adapters": [{
"type": "hono-mqtt",
"enabled": true
}]
}
DeviceDefaultExample:
summary: Default properties
description: |
An empty request body can be used to create an enabled device
with no additional configuration.
DeviceExtExample:
summary: Extension properties
description: |
Creates a device with some (application specific) extension properties.
value: |
{
"ext": {
"ep": "IMEI4711"
}
}
CredentialsSetPasswordExample:
summary: Set pre-hashed password
description: |
The secret does not refer to an existing secret (no *id* property). Thus, the
existing secrets (if any) will be replaced with the hashed password secret.
value:
[{
"auth-id": "sensor1",
"type": "hashed-password",
"secrets": [{
"pwd-hash": "AQIDBAUGBwg=",
"salt": "Mq7wFw==",
"hash-function": "sha-512",
"not-after": "2027-12-24T19:00:00Z"
}]
}]
CredentialsChangePasswordExample:
summary: Change password
description: |
The secret refers to an existing hashed password which will be updated
with the included values. The plaintext password will be hashed using
the registry's default hash algorithm.
value:
[{
auth-id: sensor1,
type: hashed-password,
secrets: [{
"id": "349556ea-4902-47c7-beb0-1009ab693fb4",
"pwd-plain": "newpassword",
"not-after": "2027-12-24T19:00:00Z"
}]
}]
CredentialsMetaDataExample:
summary: Meta data only
description: |
The secrets do not contain the confidential information like password hash
or salt. Instead, the secrets contain an identifier which can be
used to refer to the secret in a subsequent update operation.
value:
[{
"enabled": true,
"auth-id": "sensor1",
"type": "hashed-password",
"secrets": [{
"id": "349556ea-4902-47c7-beb0-1009ab693fb4",
"not-after": "2027-12-24T19:00:00Z"
}]
}]