This document describes a formal model and a common representation for a Web of Things (WoT) Thing Description. A Thing Description describes the metadata and interfaces of Things, where a Thing is an abstraction of a physical or virtual entity that provides interactions to and participates in the Web of Things. Thing Descriptions provide a set of interactions based on a small vocabulary that makes it possible both to integrate diverse devices and to allow diverse applications to interoperate. Thing Descriptions, by default, are encoded in a JSON format that also allows JSON-LD processing. The latter provides a powerful foundation to represent knowledge about Things in a machine-understandable way. A Thing Description instance can be hosted by the Thing itself or hosted externally when a Thing has resource restrictions (e.g., limited memory space) or when a Web of Things-compatible legacy device is retrofitted with a Thing Description.

The following features are considered at risk of removal due to potentially insufficient implementation experience (reports).

Text or table entries highlighted with a yellow background indicate an at-risk feature for which insufficient implementation experience currently exists. In each such case the annotation "This feature is at risk" is attached. When an entire section is at risk the annotation "This section is at risk" is placed at the start of the section and highlighted with a yellow background. When an entire section is at risk individual items within that section are not highlighted or annotated.

The Working Group seeks implementation feedback, having set the requirement of at least two implementations of each feature as the exit criteria for the Candidate Recommendation phase. The group aims to obtain reports from one TD producer and one TD consumer for each feature if applicable. For details, including definitions of implementation, TD producer, and TD consumer, see the draft implementation report.

Introduction

The WoT Thing Description (TD) is a central building block in the W3C Web of Things (WoT) and can be considered as the entry point of a Thing (much like the index.html of a Web site). A TD instance has four main components: textual metadata about the Thing itself, a set of Interaction Affordances that indicate how the Thing can be used, schemas for the data exchanged with the Thing for machine-understandability, and, finally, Web links to express any formal or informal relation to other Things or documents on the Web.

The Interaction Model of W3C WoT defines three types of Interaction Affordances: Properties (PropertyAffordance class) can be used for sensing and controlling parameters, such as getting the current value or setting an operation state. Actions (ActionAffordance class) model invocation of physical (and hence time-consuming) processes, but can also be used to abstract RPC-like calls of existing platforms. Events (EventAffordance class) are used for the push model of communication where notifications, discrete events, or streams of values are sent asynchronously to the receiver. See [[wot-architecture]] for details.

In general, the TD provides metadata for different Protocol Bindings identified by URI schemes [[iana-uri-schemes]] (e.g., http, coap, etc.), content types based on media types (e.g., application/json, application/xml, application/cbor, application/exi etc.) [[iana-media-types]], and security mechanisms (for authentication, authorization, confidentiality, etc.). Serialization of TD instances is based on JSON [[rfc8259]], where JSON names refer to terms of the TD vocabulary, as defined in this specification document. In addition the JSON serialization of TDs follows the syntax of JSON-LD 1.1 [[?json-ld11]] to enable extensions and rich semantic processing.

Example 1 shows a TD instance and illustrates the Interaction Model with Properties, Actions, and Events by describing a lamp Thing with the title MyLampThing.

From this TD example, we know there exists one Property affordance with the title status. In addition, information is provided to indicate that this Property is accessible via (the secure form of) the HTTP protocol with a GET method at the URI https://mylamp.example.com/status (announced within the forms structure by the href member), and will return a string-based status value. The use of the GET method is not stated explicitly, but is one of the default assumptions defined by this document.

In a similar manner, an Action affordance is specified to toggle the switch status using the POST method on the https://mylamp.example.com/toggle resource, where POST is again a default assumption for invoking Actions.

The Event affordance enables a mechanism for asynchronous messages to be sent by a Thing. Here, a subscription to be notified upon a possible overheating event of the lamp can be obtained by using HTTP with its long polling subprotocol on https://mylamp.example.com/oh.

This example also specifies the basic security scheme, requiring a username and password for access. Note that a security scheme is first given a name in a securityDefinition and then activated by specifying that name in a security section. In combination with the use of the HTTP protocol this example demonstrates the use of HTTP Basic Authentication. Specification of at least one security scheme at the top level is mandatory, and gives the default access requirements for every resource. However, security schemes can also be specified per-form, with configurations given at the form level overriding configurations given at the Thing level, allowing for the specification of fine-grained access control. It is also possible to use a special nosec security scheme to indicate that no access control mechanisms are used. Additional examples will be provided later.

The Thing Description offers the possibility to add contextual definitions in some namespace. This mechanism can be used to integrate additional semantics to the content of the Thing Description instance, provided that formal knowledge, e.g. logic rules for a specific domain of application, can be found under the given namespace. Contextual information can also help specify some configurations and behavior of the underlying communication protocols declared in the forms field. Example 2 extends the TD sample from Example 1 by introducing a second defintion in the @context to declare the prefix saref as referring to the SAREF vocabulary namespace [[smartM2M]]. The SAREF vocabulary includes terms to describe lighting devices and other home automation devices that one can embed in a TD as semantic labels in the @type property. In the present example, the Thing is labelled with saref:LightSwitch, the form of the status property affordance is labelled with saref:GetCommand, the form of the toggle action affordance with saref:ToggleCommand and the form the overheating event affordance with saref:NotifyCommand.

The declaration mechanism inside some @context is specified by JSON-LD. A TD instance complies to version 1.1 of this specification [[?json-ld11]]. The TD instance can be also processed as an RDF document (details are given in ).

A Thing Description instance complies with this specification if it follows the normative statements in and regarding Thing Description serialization.

A JSON Schema [[?JSON-SCHEMA-VALIDATION]] to validate Thing Description instances is provided in Appendix .

A set of SHACL shapes [[SHACL]] is provided under the TD namespace IRI as an alternative to validate Thing Description instances after transformation to RDF. See Appendix .

Terminology

The fundamental WoT terminology such as Thing, Consumer, Thing Description (TD), Interaction Model, Interaction Affordance, Property, Action, Event, Protocol Binding, Servient, WoT Interface, WoT Runtime, etc. is defined in Section 3 of the WoT Architecture specification [[WOT-ARCHITECTURE]].

In addition, this specification introduces the following definitions:

TD Context Extension
A mechanism to extend Thing Descriptions with additional Vocabulary Terms. It is the basis for semantic annotations and extensions to core mechanisms such as Protocol Bindings, Security Schemes, and Data Schemas.
TD Information Model
Set of Class definitions constructed from pre-defined Vocabularies on which constraints apply, thus defining the semantics of these Vocabularies. Class definitions are typically expressed in terms of a Signature (a set of Vocabulary Terms) and functions over that Signature. The TD Information Model also includes Default Values, defined as a global function over Classes.
TD Processor
A system that can serialize some internal representation of a Thing Description in a given format and deserialize it from that format. A TD Processor must detect semantically inconsistent Thing Descriptions, that is, Thing Descriptions that cannot satisfy constraints on the Instance Relation of the Thing class. For that purpose, a TD Processor may compute canonical forms of Thing Descriptions in which all possible Default Values are assigned. A TD Processor is typically a sub-system of a WoT Runtime.
TD Serialization or TD Document
Textual or binary representation of Thing Descriptions that can be stored and exchanged between Servients. A TD Serialization follows a given representation format, identified by a media type when exchanged over the network. The default representation format for Thing Descriptions is JSON-based as defined by this specification.
Vocabulary
A collection of Vocabulary Terms, identified by a namespace IRI.
Term and Vocabulary Term
A character string. When a Term is part of a Vocabulary, i.e. prefixed by a namespace IRI, it is called a Vocabulary Term. For the sake of readability, Vocabulary Terms present in this document are always written in a compact form and not as full IRIs. See Appendix for a mapping to full IRIs.

These definitions are further developed in .

Namespaces

The version of the TD Information Model defined in of this specification is identified by the following IRI:

https://www.w3.org/2019/wot/td/v1

This IRI, which is also a URI, can be dereferenced to obtain a JSON-LD context file [[?json-ld11]], allowing the compact strings in TD Documents to be expanded to full IRI-based Vocabulary Terms. However, this processing is only required when transforming JSON-based TD Documents to RDF, an optional feature of TD Processor implementations. See for more details on this aspect.

In the present specification, Vocabulary Terms are always presented in their compact form. Their expanded form can be accessed under the namespace IRI of the Vocabulary they belong to. These namespaces follow the structure of . Each Vocabulary used in the TD Information Model has its own namespace IRI, as follows:

Vocabulary Namespace IRI
Core https://www.w3.org/2019/wot/td#
Data Schema https://www.w3.org/2019/wot/json-schema#
Security https://www.w3.org/2019/wot/security#
Hypermedia Controls https://www.w3.org/2019/wot/hypermedia#

The Vocabularies are independent from each other. They may be reused and extended in other W3C specifications. Every breaking change in the design of a Vocabulary will require the assignment of a new year-based namespace URI. Note that to maintain the general coherence of the TD Information Model, the associated JSON-LD context file is versioned such that every version has its own URI (v1, v1.1, v2, ...) to also identify non-breaking changes, in particular the addition of new Terms.

Because a Vocabulary under some namespace IRI can only undergo non-breaking changes, its content can be safely cached or embedded in applications. One advantage of exposing relatively static content under a namespace IRI is to optimize payload sizes of messages exchanged between constrained devices. It also avoids any privacy leakage resulting from devices accessing publicly available vocabularies from private networks (see also ).

TD Information Model

This section introduces the TD Information Model. The TD Information Model serves as the conceptual basis for the processing of Thing Descriptions and their serialization, which is described separately in .

Overview

The TD Information Model is built upon the following, independent Vocabularies:

Each of these Vocabularies is essentially a set of Terms that can be used to build data structures, interpreted as objects in the traditional object-oriented sense. Objects are instances of classes and have properties. In the context of W3C WoT, they denote Things and their Interaction Affordances. A formal definition of objects is given in . The main elements of the TD Information Model are then presented in . Certain object properties may be omitted in a TD when Default Values exist. A list of defaults is given in .

The UML diagram shown next gives an overview of the TD Information Model. It represents all classes as tables and the assocations that exist between classes, starting from the class Thing, as directed arrows. For the sake of readability, the diagram was split in four parts, one for each of the four base Vocabularies.

UML diagram of the TD information model for the TD core vocabulary
TD core vocabulary

UML diagram of the TD information model for the JSON schema vocabulary
JSON schema vocabulary

UML diagram of the TD information model for the security vocabulary
WoT security vocabulary

UML diagram of the TD information model for the hypermedia controls vocabulary
Hypermedia controls vocabulary

Preliminaries

To provide a model that can be easily processes by both, simple rules on a tree-based document (i.e., raw JSON processing) and rich Semantic Web tooling (i.e., JSON-LD processing), this document defines the following formal preliminaries to construct the TD Information Model accordingly.

All definitions in this section refer to sets, which intuitively are collections of elements that can themselves be sets. All arbitrarily complex data structures can be defined in terms of sets. In particular, an Object is a data structure recursively defined as follows:

Though this definition does not prevent Objects to include multiple name-value pairs with the same name, they are generally not considered in this specification. An Object whose elements only have numbers as names is called an Array. Similarly, an Object whose elements only have Terms (that do not belong to any Vocabulary) as names is called a Map. All names appearing in some name-value pair in a Map are assumed to be unique within the scope of the Map.

Moreover, Objects can be instances of some Class. A Class, which is denoted by a Vocabulary Term, is first defined by a set of Vocabulary Terms called a Signature. A Class whose Signature is empty is called a Simple Type.

The Signature of a Class allows to construct two functions that further define Classes: an Assignment Function and a Type Function. The Assignment Function of a Class takes a Vocabulary Term of the Class's Signature as input and returns either true or false as output. Intuitively, the Assignment Function indicates whether an element of the Signature is mandatory or optional when instantiating the Class. The Type Function of a Class also takes a Vocabulary Term of the Class's Signature as input and returns another Class as output. These functions are partial: their domain is limited to the Signature of the Class being defined.

On the basis of these two functions, an Instance Relation can be defined for a pair composed of an Object and a Class. This relation is defined as constraints to be satisfied. That is, an Object is an instance of a Class if the two following constraints are both satisfied:

According to the definition above, an Object would be an instance of every Simple Type, regardless of its structure. Instead, another definition for the Instance Relation is introduced for Simple Types: an Object is an instance of a Simple Type if it is a Term with a given lexical form (e.g. true, false for the boolean type, 1, 2, 3, ... for the unsignedInt type, etc).

Moreover, additional Classes, called Parameterized Classes, can be derived from the generic Map and Array structures. An Object is a Map of some Class, that is, an instance of the Map type parameterized with some Class, if it is a Map such that the value in all the name-value pairs it contains is an instance of this Class. The same applies to Arrays.

Finally, a Class is a Subclass of some other Class if every instance of the former is also an instance of the latter.

Given all definitions above, the TD Information Model is to be understood as a set of Class definitions, which include a Class name (a Vocabulary Term), a Signature (a set of Vocabulary Terms), an Assignment Function, and a Type Function. These Class definitions are provided as tables in . For each table, the values "mandatory" (respectively, "optional") in the assignment column indicates that the Assignment Function returns true (respectively, false) for the corresponding Vocabulary Term.

By convention, Simple Types are denoted by names starting with lowercase. The TD Information Model references the following Simple Types defined in XML Schema [[xmlschema11-2-20120405]]: string, anyURI, dateTime, integer, unsignedInt, double, and boolean. Their definition (i.e. the specification of their lexical form) is outside of the scope of the TD Information Model.

In addition, the TD Information Model defines a global function on pairs of Vocabulary Terms. The function takes a Class name and another Vocabulary Term as input and returns an Object. If the returned Object is different from null, it represents the Default Value for some assignment on the input Vocabulary Term in an instance of the input Class. This function allows to relax the constraint defined above on the Assignment Function: an Object is an instance of a Class if it includes all mandatory assignments or if Default Value exist for the missing assignments. All Default Values are given in the table of . In each table of , the assignment column contains the value "with default" if a Default Value is available for the corresponding combination of Class and Vocabulary Term in the TD Information Model.

The formalization introduced here does not consider the possible relation between Objects as abstract data structures and physical world objects such as Things. However, care was given to the possibility of re-interpreting all Vocabulary Terms involved in the TD Information Model as RDF resources, so as to integrate them in a larger model of the physical world (an ontology). This aspect is dealt with in Appendix .

Class Definitions

A TD Processor MUST be able to detect that a TD does not meet Class instantiation constraints on all Classes defined in , , , and .

Core Vocabulary Definitions

Thing

An abstraction of a physical or a virtual entity whose metadata and interfaces are described by a WoT Thing Description, whereas a virtual entity is the composition of one or more Things.

Vocabulary termDescriptionAssignmentType
@contextJSON-LD keyword to define short-hand names called terms that are used throughout a TD document.mandatoryanyURI or Array
@typeJSON-LD keyword to label the object with semantic tags (or types).optionalstring or Array of string
idunique identifier of the Thing (URI, e.g. custom URN).mandatoryanyURI
titleProvides a human-readable title (e.g., display a text for UI representation) based on a default language.mandatorystring
titlesProvides multi-language human-readable titles (e.g., display a text for UI representation in different languages).optionalMultiLanguage
descriptionProvides additional (human-readable) information based on a default language.optionalstring
descriptionsCan be used to support (human-readable) information in different languages.optionalMultiLanguage
versionProvides version information.optionalVersionInfo
createdProvides information when the TD instance was created.optionaldateTime
modifiedProvides information when the TD instance was last modified.optionaldateTime
supportProvides information about the TD maintainer as URI scheme (e.g., mailto [[RFC6068]], tel [[RFC3966]], https).optionalanyURI
baseDefine the base URI that is used for all relative URI references throughout a TD document. In TD instances, all relative URIs are resolved relative to the base URI using the algorithm defined in [[RFC3986]].

base does not affect the URIs used in @context and the IRIs [[?RFC3987]] used within Linked Data [[?LINKED-DATA]] graphs that are relevant when semantic processing is applied to TD instances.
optionalanyURI
propertiesAll Property-based interaction affordance of the Thing.optionalMap of PropertyAffordance
actionsAll Action-based interaction affordance of the Thing.optionalMap of ActionAffordance
eventsAll Event-based interaction affordance of the Thing.optionalMap of EventAffordance
formsSet of form hypermedia controls that describe how an operation can be performed. Forms are serializations of Protocol Bindings. In this version of TD, all operations that can be described at the Thing level are concerning how to interact with the Thing's property affordances collectively at once.optionalArray of Form
securitySet of security definition names, chosen from those defined in securityDefinitions. These must all be satisfied for access to resources.mandatorystring or Array of string
securityDefinitionsSet of named security configurations (definitions only). Not actually applied unless names are used in a security section.mandatoryMap of SecurityScheme

The @context name-value pair MUST contain the anyURI https://www.w3.org/2019/wot/td/v1 either directly when of type anyURI or as first element when of type Array. When @context is an Array, the anyURI https://www.w3.org/2019/wot/td/v1 MAY be followed by elements of type anyURI or type Map in any order, while it is RECOMMENDED to include only one Map with all the name-value pairs in the @context Array. Maps contained in an @context Array MAY contain name-value pairs, where the value is a namespace identifier of type anyURI and the name a Term or prefix denoting that namespace. One Map contained in an @context Array SHOULD contain a name-value pair that defines the default language for the Thing Description, where the name is the Term @language and the value is a well-formed language tag as defined by [[!BCP47]] (e.g., en, de-AT, gsw-CH, zh-Hans, zh-Hant-HK, sl-nedis).

The computation of the base direction of all human-readable text strings is defined by the following set of rules:

  • If no language tag is given, the base direction SHOULD be inferred through first-strong heuristics or detection algorithms such as the CLDR Likely Subtags [[?LDML]].
  • Outside of MultiLanguage Maps, the base direction MAY be inferred from the language tag of the default language.
  • Inside of MultiLanguage Maps, the base direction of each value of the name-value pairs MAY be inferred from the language tag given in the corresponding name.
  • In cases where a language can be written in more than one script with different base directions, the corresponding language tag given in @language or MultiLanguage Maps MUST include a script subtag, so that an appropriate base direction can be inferred. An example is Azeri, which is written LTR when Latin script is used (specified using az-Latn) and RTL when Arabic script is used (specified using az-Arab).

TD Processors should be aware of certain special cases when processing bidirectional text. They should take care to use bidi isolation when presenting strings to users, particularly when embedding in surrounding text (e.g., for Web user interface). Mixed direction text can occur in any language, even when the language is properly identified.

TD producers should attempt to provide mixed direction strings in a way that can be displayed successfully by a naive user agent. For example, if an RTL string begins with an LTR run (such as a number or a brand or trade name in Latin script), including an RLM character at the start of the string or wrapping opposite direction runs in bidi controls can assist in proper display.

Strings on the Web: Language and Direction Metadata [[?string-meta]] provides some guidance and illustrates a number of pitfalls when using bidirectional text.

In addition to the explicitly provided Interaction Affordances in the properties, actions, and events Arrays, a Thing can also provide meta-interactions, which are indicated by Form instances in its optional forms Array. When the forms Array of a Thing instance contains Form instances, the string values assigned to the name op, either directly or within an Array, MUST be one of the following opteration types: readallproperties, writeallproperties, readmultipleproperties, or writemultipleproperties. (See an example for an usage of form in a Thing instance.)

The data schema for each of these meta-interactions is constructed by combining the data schemas of each PropertyAffordance instance in a single ObjectSchema instance, where the properties Map of the ObjectSchema instance contains each data schema of the PropertyAffordances identified by the name of the corresponding PropertyAffordances instance.

If not specified otherwise (e.g., through a TD Context Extension), the request data of the readmultipleproperties operation is an Array that contains the intended PropertyAffordances instance names, which is serialized to the content type specified by the Form instance.

InteractionAffordance

Metadata of a Thing that shows the possible choices to Consumers, thereby suggesting how Consumers may interact with the Thing. There are many types of potential affordances, but W3C WoT defines three types of Interaction Affordances: Properties, Actions, and Events.

Vocabulary termDescriptionAssignmentType
@typeJSON-LD keyword to label the object with semantic tags (or types).optionalstring or Array of string
titleProvides a human-readable title (e.g., display a text for UI representation) based on a default language.optionalstring
titlesProvides multi-language human-readable titles (e.g., display a text for UI representation in different languages).optionalMultiLanguage
descriptionProvides additional (human-readable) information based on a default language.optionalstring
descriptionsCan be used to support (human-readable) information in different languages.optionalMultiLanguage
formsSet of form hypermedia controls that describe how an operation can be performed. Forms are serializations of Protocol Bindings.mandatoryArray of Form
uriVariablesDefine URI template variables as collection based on DataSchema declarations.optionalMap of DataSchema

The class InteractionAffordance has the following subclasses:

PropertyAffordance

An Interaction Affordance that exposes state of the Thing. This state can then be retrieved (read) and optionally updated (write). Things can also choose to make Properties observable by pushing the new state after a change.

Vocabulary termDescriptionAssignmentType
observableA hint that indicates whether Servients hosting the Thing and Intermediaries should provide a Protocol Binding that supports the observeproperty operation for this Property.optionalboolean

Property instances are also instances of the class DataSchema. Therefore, it can contain the type, unit, readOnly and writeOnly members, among others.

PropertyAffordance is a Subclass of the InteractionAffordance Class and the DataSchema Class. When a Form instance is within a PropertyAffordance Class, the value assigned to op MUST be one of readproperty, writeproperty, observeproperty, unobserveproperty or an Array containing a combination of these terms.

ActionAffordance

An Interaction Affordance that allows to invoke a function of the Thing, which manipulates state (e.g., toggling a lamp on or off) or triggers a process on the Thing (e.g., dimm a lamp over time).

Vocabulary termDescriptionAssignmentType
inputUsed to define the input data schema of the action.optionalDataSchema
outputUsed to define the output data schema of the action.optionalDataSchema
safeSignals if the action is safe (=true) or not. Used to signal if there is no internal state (cf. resource state) is changed when invoking an Action. In that case responses can be cached as example.with defaultboolean
idempotentIndicates whether the action is idempotent (=true) or not. Informs whether the action can be called repeatedly with the same result, if present, based on the same input.with defaultboolean

ActionAffordance is a Subclass of the InteractionAffordance Class. When a Form instance is within an instance of the ActionAffordance Class, the value assigned to op MUST be invokeaction.

EventAffordance

An Interaction Affordance that describes an event source, which asynchronously pushes event data to Consumers (e.g., overheating alerts).

Vocabulary termDescriptionAssignmentType
subscriptionDefines data that needs to be passed upon subscription, e.g., filters or message format for setting up Webhooks.optionalDataSchema
dataDefines the data schema of the Event instance messages pushed by the Thing.optionalDataSchema
cancellationDefines any data that needs to be passed to cancel a subscription, e.g., a specific message to remove a Webhook.optionalDataSchema

EventAffordance is a Subclass of the InteractionAffordance Class. When a Form instance is within an instance of the EventAffordance Class, the value assigned to op MUST be either subscribeevent, unsubscribeevent, or both terms within an Array.

VersionInfo

Metadata of a Thing that provides version information about the TD document. If required, additional version information such as firmware and hardware version (term definitions outside of the TD namespace) can be extended via the TD Context Extension mechanism.

Vocabulary termDescriptionAssignmentType
instanceProvides a version identicator of this TD instance.mandatorystring

It is recommended that the values within instances of the VersionInfo Class follow the semantic versioning pattern, where a sequence of three numbers separated by a dot indicates the major version, minor version, and patch version, respectively. See [[?SemVer]] for details.

MultiLanguage

A Map providing a set of human-readable texts in different languages identified by language tags described in [[BCP47]]. See for example usages of this container in a Thing Description instance.

Each name of the MultiLanguage Map MUST be a language tag as defined in [[!BCP47]]. Each value of the MultiLanguage Map MUST be of type string.

Data Schema Vocabulary Definitions

The data schema definition is reflecting a very common subset of the terms defined by JSON Schema [[?JSON-SCHEMA-VALIDATION]]. It is noted that data schema definitions within Thing Description instances are not limited to this defined subset and MAY use additional terms found in JSON Schema. In that case, it is recommended to use a TD Context Extension for the additional terms as described in , otherwise these terms are semantically ignored by TD Processors (also see ).

DataSchema

Metadata that describes the data format used. It can be used for validation.

Vocabulary termDescriptionAssignmentType
@typeJSON-LD keyword to label the object with semantic tags (or types)optionalstring or Array of string
titleProvides a human-readable title (e.g., display a text for UI representation) based on a default language.optionalstring
titlesProvides multi-language human-readable titles (e.g., display a text for UI representation in different languages).optionalMultiLanguage
descriptionProvides additional (human-readable) information based on a default language.optionalstring
descriptionsCan be used to support (human-readable) information in different languages.optionalMultiLanguage
typeAssignment of JSON-based data types compatible with JSON Schema (one of boolean, integer, number, string, object, array, or null).optionalstring (one of object, array, string, number, integer, boolean, or null)
constProvides a constant value.optionalany type
unitProvides unit information that is used, e.g., in international science, engineering, and business.optionalstring
oneOfUsed to ensure that the data is valid against one of the specified schemas in the array.optionalArray of DataSchema
enumRestricted set of values provided as an array.optionalArray of any type
readOnlyBoolean value that is a hint to indicate whether a property interaction / value is read only (=true) or not (=false).with defaultboolean
writeOnlyBoolean value that is a hint to indicate whether a property interaction / value is write only (=true) or not (=false).with defaultboolean
formatAllows validation based on a format pattern such as "date-time", "email", "uri", etc. (Also see below.)optionalstring

The class DataSchema has the following subclasses:

The format string values are known from a fixed set of values and their corresponding format rules defined in [[?JSON-SCHEMA-VALIDATION]] (Section 7.3 Defined Formats in particluar). Servients MAY use the format value to perform additional validation accordingly. When a value that is not found in the known set of values is assigned to format, such a validation SHOULD succeed.

ArraySchema

Metadata describing data of type Array. This Subclass is indicated by the value array assigned to type in DataSchema instances.

Vocabulary termDescriptionAssignmentType
itemsUsed to define the characteristics of an array.optionalDataSchema or Array of DataSchema
minItemsDefines the minimum number of items that have to be in the array.optionalunsignedInt
maxItemsDefines the maximum number of items that have to be in the array.optionalunsignedInt

BooleanSchema

Metadata describing data of type boolean. This Subclass is indicated by the value boolean assigned to type in DataSchema instances.

NumberSchema

Metadata describing data of type number. This Subclass is indicated by the value number assigned to type in DataSchema instances.

Vocabulary termDescriptionAssignmentType
minimumSpecifies a minimum numeric value. Only applicable for associated number or integer types.optionaldouble
maximumSpecifies a maximum numeric value. Only applicable for associated number or integer types.optionaldouble

IntegerSchema

Metadata describing data of type integer. This Subclass is indicated by the value integer assigned to type in DataSchema instances.

Vocabulary termDescriptionAssignmentType
minimumSpecifies a minimum numeric value. Only applicable for associated number or integer types.optionalinteger
maximumSpecifies a maximum numeric value. Only applicable for associated number or integer types.optionalinteger

ObjectSchema

Metadata describing data of type object. This Subclass is indicated by the value object assigned to type in DataSchema instances.

Vocabulary termDescriptionAssignmentType
propertiesData schema nested definitions.optionalMap of DataSchema
requiredDefines which members of the object type are mandatory.optionalArray of string

StringSchema

Metadata describing data of type string. This Subclass is indicated by the value string assigned to type in DataSchema instances.

NullSchema

Metadata describing data of type null. This Subclass is indicated by the value null assigned to type in DataSchema instances. This Subclass describes only one acceptable value, namely null. It can be used as part of a oneOf declaration, where it is used to indicate, that the data can also be null.

Security Vocabulary Definitions

This specification provides a selection of well-established security mechanisms that are directly built into protocols eligable as Protocol Bindings for W3C WoT or are widely in use with those protocols. The current set of HTTP security schemes is partly based on OpenAPI 3.0.1 (see also [[?OPENAPI]]). However while the HTTP security schemes, Vocabulary, and syntax given in this specification share many similarities with OpenAPI, they are not compatible.

SecurityScheme

Metadata describing the configuration of a security mechanism. The value assigned to the name scheme MUST be defined within a Vocabulary included in the Thing Description, either in the standard Vocabulary defined in or in a TD Context Extension.

Vocabulary termDescriptionAssignmentType
@typeJSON-LD keyword to label the object with semantic tags (or types).optionalstring or Array of string
schemeIdentification of the security mechanism being configured.mandatorystring (e.g. nosec, basic, cert, digest, bearer, pop, psk, public, oauth2, or apikey)
descriptionProvides additional (human-readable) information based on a default language.optionalstring
descriptionsCan be used to support (human-readable) information in different languages.optionalMultiLanguage
proxyURI of the proxy server this security configuration provides access to. If not given, the corresponding security configuration is for the endpoint.
This feature is at risk.
optionalanyURI

The class SecurityScheme has the following subclasses:

NoSecurityScheme

A security configuration corresponding to identified by the Vocabulary Term nosec (i.e., "scheme": "nosec"), indicating there is no authentication or other mechanism required to access the resource.

BasicSecurityScheme

Basic authentication security configuration identified by the Vocabulary Term basic (i.e., "scheme": "basic"), using an unencrypted username and password. This scheme should be used with some other security mechanism providing confidentiality, for example, TLS.

Vocabulary termDescriptionAssignmentType
inSpecifies the location of security authentication information.with defaultstring (one of header, query, body, or cookie)
nameName for query, header, or cookie parameters.optionalstring

DigestSecurityScheme

Digest authentication security configuration identified by the Vocabulary Term digest (i.e., "scheme": "digest"). This scheme is similar to basic authentication but with added features to avoid man-in-the-middle attacks.

Vocabulary termDescriptionAssignmentType
qopQuality of protection.
This feature is at risk.
with defaultstring (one of auth, or auth-int)
inSpecifies the location of security authentication information.with defaultstring (one of header, query, body, or cookie)
nameName for query, header, or cookie parameters.optionalstring

APIKeySecurityScheme

This section is at risk.

API key authentication security configuration identified by the Vocabulary Term apikey (i.e., "scheme": "apikey"). This is for the case where the access token is opaque and is not using a standard token format.

Vocabulary termDescriptionAssignmentType
inSpecifies the location of security authentication information.with defaultstring (one of header, query, body, or cookie)
nameName for query, header, or cookie parameters.optionalstring

BearerSecurityScheme

Bearer token authentication security configuration identified by the Vocabulary Term bearer (i.e., "scheme": "bearer"). This scheme is intended for situations where bearer tokens are used independently of OAuth2. If the oauth2 scheme is specified it is not generally necessary to specify this scheme as well as it is implied. For format, the value jwt indicates conformance with [[!RFC7519]], jws indicates conformance with [[!RFC7797]], cwt indicates conformance with [[!RFC8392]], and jwe indicates conformance with [[!RFC7516]], with values for alg interpreted consistently with those standards. Other formats and algorithms for bearer tokens MAY be specified in vocabulary extensions..

Vocabulary termDescriptionAssignmentType
authorizationURI of the authorization server.optionalanyURI
algEncoding, encryption, or digest algorithm.with defaultstring (e.g. MD5, ES256, or ES512-256)
formatSpecifies format of security authentication information.with defaultstring (e.g. jwt, cwt, jwe, or jws)
inSpecifies the location of security authentication information.with defaultstring (one of header, query, body, or cookie)
nameName for query, header, or cookie parameters.optionalstring

CertSecurityScheme

This section is at risk.

Certificate-based asymmetric key security configuration conformant with [[!X509V3]] identified by the Vocabulary Term cert (i.e., "scheme": "cert").

Vocabulary termDescriptionAssignmentType
identityIdentifier providing information which can be used for selection or confirmation.optionalstring

PSKSecurityScheme

This section is at risk.

Pre-shared key authentication security configuration identified by the Vocabulary Term psk (i.e., "scheme": "psk").

Vocabulary termDescriptionAssignmentType
identityIdentifier providing information which can be used for selection or confirmation.optionalstring

PublicSecurityScheme

This section is at risk.

Raw public key asymmetric key security configuration identified by the Vocabulary Term public (i.e., "scheme": "public").

Vocabulary termDescriptionAssignmentType
identityIdentifier providing information which can be used for selection or confirmation.optionalstring

PoPSecurityScheme

This section is at risk.

Proof-of-possession (PoP) token authentication security configuration identified by the Vocabulary Term pop (i.e., "scheme": "pop"). Here jwt indicates conformance with [[!RFC7519]], jws indicates conformance with [[!RFC7797]], cwt indicates conformance with [[!RFC8392]], and jwe indicates conformance with [[!RFC7516]], with values for alg interpreted consistently with those standards. Other formats and algorithms for PoP tokens MAY be specified in vocabulary extensions..

Vocabulary termDescriptionAssignmentType
authorizationURI of the authorization server.optionalanyURI
algEncoding, encryption, or digest algorithm.with defaultstring (e.g. MD5, ES256, or ES512-256)
formatSpecifies format of security authentication information.with defaultstring (e.g. jwt, cwt, jwe, or jws)
inSpecifies the location of security authentication information.with defaultstring (one of header, query, body, or cookie)
nameName for query, header, or cookie parameters.optionalstring

OAuth2SecurityScheme

This section is at risk.

OAuth2 authentication security configuration for systems conformant with [[!RFC6749]] and [[!RFC8252]], identified by the Vocabulary Term oauth2 (i.e., "scheme": "oauth2"). For the implicit flow authorization MUST be included. For the password and client flows token MUST be included. For the code flow both authorization and token MUST be included. If no scopes are defined in the SecurityScheme then they are considered to be empty.

Vocabulary termDescriptionAssignmentType
authorizationURI of the authorization server.optionalanyURI
tokenURI of the token server.optionalanyURI
refreshURI of the refresh server.optionalanyURI
scopesSet of authorization scope identifiers provided as an array. These are provided in tokens returned by an authorization server and associated with forms in order to identify what resources a client may access and how. The values associated with a form should be chosen from those defined in an OAuth2SecurityScheme active on that form.
This feature is at risk.
optionalstring or Array of string
flowAuthorization flow.with defaultstring (one of implicit, password, client, or code)

Hypermedia Controls Vocabulary Definitions

The present model provides a representation for (typed) Web links and Web forms exposed by a Thing. The Link class definition is reflecting a very common subset of the terms defined in Web Linking [[!RFC8288]]. The defined terms can be used, e.g., to describe the relation to another Thing such as a Lamp Thing is controlled by a Switch Thing. The Form class corresponds to a newly introduced form of hypermedia control to manipulate the state of Things (and other Web resources).

Link

A link can be viewed as a statement of the form "link context has a relation type resource at link target", where the optional target attributes may further describe the resource.

Vocabulary termDescriptionAssignmentType

Form

A form can be viewed as a statement of "To perform an operation type operation on form context, make a request method request to submission target" where the optional form fields may further describe the required request. In Thing Descriptions, the form context is the surrounding Object, such as Properties, Actions, and Events or the Thing itself for meta-interactions.

Vocabulary termDescriptionAssignmentType
opIndicates the semantic intention of performing the operation(s) described by the form. For example, the Property interaction allows get and set operations. The protocol binding may contain a form for the get operation and a different form for the set operation. The op attribute indicates which form is for which and allows the client to select the correct form for the operation required. op can be assigned one or more interaction verb(s) each representing a semantic intention of an operation.with defaultstring or Array of string (one of readproperty, writeproperty, observeproperty, unobserveproperty, invokeaction, subscribeevent, unsubscribeevent, readallproperties, writeallproperties, readmultipleproperties, or writemultipleproperties)
hreftarget IRI of a link or submission target of a form.mandatoryanyURI
contentTypeAssign a content type based on a media type [[IANA-MEDIA-TYPES]] (e.g., 'text/plain') and potential parameters (e.g., 'charset=utf-8') for the media type.with defaultstring
contentCodingContent coding values indicate an encoding transformation that has been or can be applied to a representation. Content codings are primarily used to allow a representation to be compressed or otherwise usefully transformed without losing the identity of its underlying media type and without loss of information. Examples of content coding include "gzip", "deflate", etc. .optionalstring
subprotocolIndicates the exact mechanism by which an interaction will be accomplished for a given protocol when there are multiple options. For example, for HTTP and Events, it indicates which of several available mechanisms should be used for asynchronous notifications such as long polling, websub (also see https://www.w3.org/TR/websub/), or server sent events (also see https://www.w3.org/TR/eventsource/). Please note that there is no restriction on the sub-protocol selection and other mechanisms can also be announced by this subprotocol term.optionalstring (e.g. longpoll, websub, or sse)
securitySet of security definition names, chosen from those defined in securityDefinitions. These must all be satisfied for access to resources.optionalstring or Array of string
scopesSet of authorization scope identifiers provided as an array. These are provided in tokens returned by an authorization server and associated with forms in order to identify what resources a client may access and how. The values associated with a form should be chosen from those defined in an OAuth2SecurityScheme active on that form.
This feature is at risk.
optionalstring or Array of string
responseThis optional term can be used if, e.g., the output communication metadata differ from input metdata (e.g., output contentType differ from the input contentType). The response name contains metadata that is only valid for the reponse messages.optionalExpectedResponse

The list of possible operation types of a form is fixed. As of this version of the specification, it only includes the well-known types necessary to implement the WoT interaction model described in [[WOT-ARCHITECTURE]]. Future versions of the standard may extend this list but operations types SHOULD NOT be arbitrarily set by servients .

The optional response name-value pair can be used to provide metadata for the expected response message. With the core vocabulary, it only includes content type information, but TD Context Extensions could be applied. If no response name-value pair is provided, it MUST be assumed that the content type of the response is equal to the content type assigned to the Form instance. Note that contentType within an ExpectedResponse Class does not have a Default Value. For instance, if the value of the content type of the form is application/xml the assumed value of the content type of the response will be also application/xml.

In some use cases, input and output data might be represented in a different form, for instance an Action that accepts JSON, but returns an image. In such a case, the optional response name-value pair can describe the content type of the expected response. If the content type of the expected response differs from the content type of the form, the Form instance MUST include a name-value pair with the name response. For instance, an ActionAffordance could only accept application/json for its input data, while it will respond with an image/jpeg content type for its output data. In that case the content types differ and the response name-value pair has to be used to provide response content type (image/jpeg) information to the Consumer.

Possible values for the contentCoding property can be found e.g. in the IANA HTTP content coding registry.

ExpectedResponse

Communication metadata describing the expected response message.

Vocabulary termDescriptionAssignmentType
contentTypeAssign a content type based on a media type [[IANA-MEDIA-TYPES]] (e.g., 'text/plain') and potential parameters (e.g., 'charset=utf-8') for the media type.mandatorystring

Default Value Definitions

When assignments in a TD are missing, a TD Processor MUST follow the Default Value assignments expressed in the table of .

The following table gives all Default Values defined in the TD Information Model.

Class Vocabulary Term Default Value Comment
Form contentType application/json
DataSchema readOnly false
DataSchema writeOnly false
ActionAffordance safe false
ActionAffordance idempotent false
Form op Array of string with the elements readproperty and writeproperty
If defined within an instance of PropertyAffordance
Form op invokeaction If defined within an instance of ActionAffordance
Form op subscribeevent If defined within an instance of EventAffordance
BasicSecurityScheme in header
DigestSecurityScheme in header
BearerSecurityScheme in header
PoPSecurityScheme
This feature is at risk.
in header
APIKeySecurityScheme
This feature is at risk.
in query
DigestSecurityScheme
This feature is at risk.
qop auth
BearerSecurityScheme alg ES256
PoPSecurityScheme
This feature is at risk.
alg ES256
BearerSecurityScheme format jwt
PoPSecurityScheme
This feature is at risk.
format jwt
OAuth2SecurityScheme
This feature is at risk.
flow implicit

TD Representation Format

WoT Thing Descriptions represent Things and are modeled and structured based on . This section defines a JSON-based representation format for Things, a serialization of instances of the Class Thing defined by the TD Information Model.

A TD Processor MUST be able to serialize Thing Descriptions into the JSON format [[!RFC8259]] and deserialize Thing Descriptions from that format, according to the rules noted in and .

The JSON serialization of the TD Information Model is aligned with the syntax of JSON-LD 1.1 [[?json-ld11]] in order to streamline semantic evaluation. Hence, the TD representation format can be processed either as raw JSON or with a JSON-LD 1.1 processor, as further detailed in .

In order to support interoperable internationalization, TDs MUST be serialized according to the requirements defined in Section 8.1 of RFC8259 [[!RFC8259]] for open ecosystems. In summary, this requires the following:

Mapping to JSON Types

The TD Information Model is constructed, so that there is an easy mapping between model Objects and JSON types. Every Class instances maps to a JSON object, where each name-value pair of the Class instance is a member of the JSON object.

Every Simple Type mentioned in (i.e., string, anyURI, dateTime, integer, unsignedInt, double, and boolean) maps to a primitive JSON type (string, number, boolean), as per the rules listed below. These rules apply to values in name-value pairs:

Every complex type of the TD Information Model (i.e., Arrays, Maps, and Class instances) maps to a structured JSON type (array and object), as per the rules listed below:

Omitting Default Values

A Thing Description serialization may omit Vocabulary Term for which Default Values are defined, as listed in the table given in .

The following example shows the TD instance from Example 1 with a checkbox to also include the members with Default Values (=checkbox checked). These members can be omitted (=checkbox unchecked) to simplify the TD serialization. Note that a TD Processor interprets these omitted members identically as if they were explicitly present with a given Default Value.

Please note that, depending on the Protocol Binding used, additional protocol-specific Vocabulary Terms may apply. They may also have associated Default Values, and hence can also be omitted as explained in this subsection. Further information can be found in .

Information Model Serialization

Thing Root Object

A Thing Description is a data structure rooted at an Object of type Thing. In turn, a JSON serialization of the Thing Description is a JSON object, which is the root of a syntax tree constructed from the TD Information Model.

The root element of a TD Serialization MUST be a JSON object that includes a member with the name @context and a value of type string or array that equals or respectively contains https://www.w3.org/2019/wot/td/v1.

In general, this URI is used to identify the TD representation format version defined by this specification. For JSON-LD processing [[?json-ld11]], this URI specifies the Thing Description context file. An @context of type array indicates TD Context Extensions (see for details).

{  
    "@context": "https://www.w3.org/2019/wot/td/v1",
    ...
}

All name-value pairs of an instance of Thing, where the name is a Vocabulary Term in the Signature of Thing, MUST be serialized as JSON members of the root object.

A TD snippet for a serialized root object including all mandatory and optional members is given below:

{
    "@context": "https://www.w3.org/2019/wot/td/v1",
    "@type": "Thing",
    "id": "urn:dev:ops:32473-Thing-1234",
    "title": "MyThing",
    "titles": {...},
    "description": "Human readable information.",
    "descriptions": {...},
    "support": "mailto:support@example.com",
    "version" : {...},
    "created" : "2018-11-14T19:10:23.824Z",
    "modified" : "2019-06-01T09:12:43.124Z",
    "securityDefinitions": {...},
    "security": ...,
    "base": "https://servient.example.com/",
    "properties": {...},
    "actions": {...},
    "events": {...},
    "links": [...],
    "forms": [...]
}

All values assigned to version, securityDefinitions, properties, actions, and events in an instance of the Class Thing MUST be serialized as JSON objects.

All values assigned to links, and forms in an instance of the Class Thing MUST be serialized as JSON arrays containing JSON objects as defined in and , respectively.

The value assigned to security in an instance of Class Thing MUST be serialized as JSON string or as JSON array whose elements are JSON strings.

Human-Readable Metadata

JSON members named title and description are used within a TD document to provide human-readable metadata. They can be used as comments for developers inspecting a TD document or as display texts for user interface.

As defined in , the base text direction used to display human-readable metadata can either be estimated using heuristics such as the first-strong rule or inferred from language information. In TD documents the default language is defined by a value assigned to @language in the @context, and this, along with a script subtag if necessary, can be used to determine a base text direction. However, when interpreting human-readable text, each human-readable string value MUST be processed independently. In other words, a TD Processor cannot carry forward changes in direction from one string to another, or infer direction for one string from another one elsewhere in the TD.

Strings on the Web [[?string-meta]] suggests both strong-first and language-based inferencing as means to determine the base text direction. Given that the Thing Description format is based on JSON-LD 1.1 [[?json-ld11]], which currently lacks explicit direction metadata, these approaches are currently considered appropriate at the time of this publication. However, if JSON-LD 1.1 adopts support for explicit base direction metadata as recommended by [[?string-meta]], the Thing Description format should be updated to take advantage of that feature.

A TD snippet using title and description is shown below. The default language is set to en through the definition of the @language member within a JSON object in the @context array.

{
    "@context": [
        "https://www.w3.org/2019/wot/td/v1",
        { "@language" : "en" }
    ],
    "title": "MyThing",
    "description": "Human readable information.",
    ...
    "properties": {
        "on": {
            "title" : "On/Off",
            "type": "boolean",
            "forms": [...]
        },
        "status": {
            "title" : "Status",
            "type": "object",
            ...
            "forms": [...]
        }
    },
    ...
}

The JSON members named titles and descriptions are used within the TD document to provide human-readable metadata in multiple languages within a single TD document. All name-value pairs of a MultiLanguage Map MUST be serialized as members of a JSON object, where the name is a well-formed language tag as defined by [[!BCP47]] and the value is a human-readable string in the language indicated by the tag. See for details. All MultiLanguage object within a TD document SHOULD contain the same set of language members.

A TD snippet using titles and descriptions at different levels is given below:

{
    "@context": "https://www.w3.org/2019/wot/td/v1",
    "title": "MyThing",
    "titles": {
        "en":"MyThing",
        "de": "MeinDing",
        "ja" : "私の物",
        "zh-Hans" : "我的东西", 
        "zh-Hant" : "我的東西"
    },
    "descriptions": {
        "en":"Human readable information.",
        "de": "Menschenlesbare Informationen.",
        "ja" : "人間が読むことができる情報",
        "zh-Hans" : "人们可阅读的信息", 
        "zh-Hant" : "人們可閱讀的資訊"
    },
    ...
    "properties": {
        "on": {
            "titles": {
                "en": "On/Off",
                "de": "An/Aus",
                "ja": "オンオフ",
                "zh-Hans": "开关",
                "zh-Hant": "開關" },
            "type": "boolean",
            "forms": [...]
        },
        "status": {
            "titles": {
                "en": "Status",
                "de": "Zustand",
                "ja": "状態",
                "zh-Hans": "状态",
                "zh-Hant": "狀態" },
            "type": "object",
            ...
            "forms": [...]
        }
    },
    ...
}

TD instances may also combine the use of title and description with titles and descriptions. When title and titles or description and descriptions are present within the same JSON object, the values of title and description MAY be seen as the default text. When title and titles or description and descriptions are present in a TD document, each title and description member SHOULD have a corresponding titles and descriptions member, respectively. The the language of the default text is indicated by the default language, which is usually set by the creator of the Thing Description instance.

{
    "@context": [
        "https://www.w3.org/2019/wot/td/v1",
        { "@language" : "de" }
    ],
    "title": "MyThing",
    "titles": {
        "en":"MyThing",
        "de": "MeinDing",
        "ja" : "私の物",
        "zh-Hans" : "我的东西", 
        "zh-Hant" : "我的東西"
    },
    "description": "Menschenlesbare Informationen.",
    "descriptions": {
        "en":"Human readable information.",
        "de": "Menschenlesbare Informationen.",
        "ja" : "人間が読むことができる情報",
        "zh-Hans" : "人们可阅读的信息", 
        "zh-Hant" : "人們可閱讀的資訊"
    },
    ...
    "properties": {
        "on": {
            "title" : "An/Aus",
            "titles": {
                "en": "On/Off",
                "de": "An/Aus",
                "ja": "オンオフ",
                "zh-Hans": "开关",
                "zh-Hant": "開關" },
            "type": "boolean",
            "forms": [...]
        },
        "status": {
            "title" : "Zustand",
            "titles": {
                "en": "Status",
                "de": "Zustand",
                "ja": "状態",
                "zh-Hans": "状态",
                "zh-Hant": "狀態" },
            "type": "object",
            ...
            "forms": [...]
        }
    },
    ...
}

Another possibility to set the default language is through a language negotiation mechanism, such as the Accept-Language header field of HTTP. In cases where the default language has been negotiated, an @language member MUST be present to indicate the result of the negotiation and the corresponding default language of the returned content. When the default language has been negotiated successfully, TD documents SHOULD include the appropriate matching values for the members title and description in preference to MultiLanguage objects in titles and descriptions members. Note however that Things MAY choose to not support such dynamically-generated TDs nor to support language negotiation (e.g., because of resource constraints).

version

All name-value pairs of an instance of VersionInfo, where the name is a Vocabulary Term included in the Signature of VersionInfo, MUST be serialized as JSON members with the Vocabulary Term as name.

A TD snippet of a version information object is given below:

{
    ...
    "version": { "instance": "1.2.1" },
    ...
}

The version member is intended as container for additional application- and/or device-specific version information based on TD Context Extensions. See for details.

securityDefinitions and security

In a Thing instance, the value assigned to securityDefinitions is a Map of instances of SecurityScheme. All name-value pairs of a Map of SecurityScheme instances MUST be serialized as members of the JSON object that results from serializing the Map; the name of a pair MUST be serialized as a JSON string and the value of the pair, an instance of SecurityScheme, MUST be serialized as a JSON object.

All name-value pairs of an instance of one of the Subclasses of SecurityScheme, where the name is a Vocabulary Term included in the Signature of that Subclass or in the Signature of SecurityScheme, MUST be serialized as members of the JSON object that results from serializing the SecurityScheme Subclass's instance, with the Vocabulary Term as name.

The following TD snippet shows a simple security configuration specifying basic username/password authentication in the header. The value given for in is actually the Default Value (header) and could be omitted. A named security configuration must be given in the securityDefinitions map. That definition must be activated by including its JSON name in the security member, which can be of type string when only one definition is activated.

    ...
    "securityDefinitions": {
        "basic_sc": {
            "scheme": "basic",
            "in": "header"
        }
    },
    "security": "basic_sc",
    ...

Here is a more complex example: a TD snippet showing digest authentication on a proxy combined with bearer token authentication on the Thing. In the digest scheme, the Default Value of in (i.e., header) is omitted, but still applies. Note that the corresponding private security configuration such as username/password and tokens must be configured in the Consumer to interact successfully. When activating multiple security definitions, the security member becomes an array.

    ...
    "securityDefinitions": {
        "proxy_sc": {
            "scheme": "digest",
            "proxy": "https://portal.example.com/"
        },
        "bearer_sc": {
            "in":"header",
            "scheme": "bearer",
            "format": "jwt",
            "alg": "ES256",
            "authorization": "https://servient.example.com:8443/"
        }
    },
    "security": ["proxy_sc", "bearer_sc"],
    ...

Security configuration in the TD is mandatory. At least one security definition MUST be activated through the security array at the Thing level (i.e., in the TD root object). This configuration can be seen as the default security mechanism required to interact with the Thing. Security definitions MAY also be activated at the form level by including a security member in form objects, which overrides (i.e., completely replace) all definitions activated at the Thing level.

The nosec security scheme is provided for the case that no security is needed. The minimal security configuration for a Thing is activation of the nosec security scheme at the Thing level, as shown in the following example:

{
    "@context": "https://www.w3.org/2019/wot/td/v1",
    "id": "urn:dev:ops:32473-Thing-1234",
    "title": "MyThing",
    "description": "Human readable information.",
    "support": "https://servient.example.com/contact",
    "securityDefinitions": { "nosec_sc": { "scheme": "nosec" }},
    "security": "nosec_sc",
    "properties": {...},
    "actions": {...},
    "events": {...},
    "links": [...]
}

To give a more complex example, suppose we have a Thing where all Interaction Affordances require basic authentication except for one, for which no authentication is required. For the status Property and the toggle Action, basic authentication is required and defined at the Thing level. For the overheating Event, however, no authentication is required, and hence the security configuration is overridden at the form level.

{
    ...
    "securityDefinitions": {
        "basic_sc": {"scheme": "basic"},
        "nosec_sc": {"scheme": "nosec"}
    },
    "security": ["basic_sc"],
    ...
    "properties": {
        "status": {
            ...
            "forms": [{
                "href": "https://mylamp.example.com/status"
            }]
        }
    },
    "actions": {
        "toggle": {
            ...
            "forms": [{
                "href": "https://mylamp.example.com/toggle"
            }]
        }
    },
    "events": {
        "overheating": {
            ...
            "forms": [{
                "href": "https://mylamp.example.com/oh",
                "security": ["nosec_sc"]
            }]
        }
    }
}

Security configurations can also can be specified for different forms within the same Interaction Affordance. This may be required for devices that support multiple protocols, for example HTTP and CoAP [[?RFC7252]], which support different security mechanisms. This is also useful when alternative authentication mechanisms are allowed. Here is a TD snippet demonstrating three possible ways to activate a Property affordance: via HTTPS with basic authentication, via HTTPS via digest authentication, or via CoAPS with a pre-shared key (PSK). In other words, the use of different security configurations within multiple forms provides a way to combine security mechanisms in an "OR" fashion. In contrast, putting multiple security configurations in the same security member combines them in an "AND" fashion, since in that case they would all need to be satisfied to allow activation of the Interaction Affordance. Note that activating one (default) configuration at the Thing level is still mandatory.

{
    ...
    "securityDefinitions": {
        "basic_sc": { "scheme": "basic" },
        "digest_sc": { "scheme": "digest", "qop": "auth", "in": "header" },
        "psk_sc": { "scheme": "psk" }
    },
    "security": ["basic_sc"],
    ...
    "properties": {
        "status": {
            ...
            "forms": [{
                "href": "https://mylamp.example.com/status"
            }, {
                "href": "https://mylamp.example.com/status",
                "security": ["digest_sc"]
            }, {
                "href": "coaps://mylamp.example.com:5684/status",
                "security": ["psk_sc"]
            }]
        }
    },
    ...
}

As another more complex example, OAuth2 makes use of scopes. These are identifiers that may appear in tokens and must match with corresponding identifiers in a resource to allow access to that resource (or Interaction Affordance in the case of W3C WoT). For example, in the following, the status Property can be read by Consumers using bearer tokens containing the scope limited, but the configure Action can only be invoked with a token containing the special scope. Scopes are not identical to roles, but are often associated with them; for example, perhaps only those in an administrative role are authorized to perform "special" interactions. Tokens can have more than one scope. In this example, an administrator would probably be issued tokens with both the limited and special scopes, while ordinary users would only be issued tokens with the limited scope.

{
    ...
    "securityDefinitions": {
        "oauth2_sc": {
            "scheme": "oauth2",
            ...
            "flow": "implicit",
            "authorization": "https://example.com/authorization",
            "scopes": ["limited", "special"]
        }
    },
    "security": ["oauth2_sc"],
    ...
    "properties": {
        "status": {
            ...
            "forms": [{
                "href": "https://scopes.example.com/status",
                "scopes": ["limited"]
            }]
        }
    },
    "action": {
        "configure": {
            ...
            "forms": [{
                "href": "https://scopes.example.com/configure",
                "scopes": ["special"]
            }]
        }
    },
    ...
}

properties

The value assigned to properties in a Thing instance is a Map of instances of PropertyAffordance. All name-value pairs of a Map of PropertyAffordance instances MUST be serialized as members of the JSON object that results from serializing the Map; the name of a pair MUST be serialized as a JSON string and the value of the pair, an instance of PropertyAffordance, MUST be serialized as a JSON object.

All name-value pairs of an instance of PropertyAffordance, where the name is a Vocabulary Term included in (one of) the Signatures of PropertyAffordance, InteractionAffordance, or DataSchema, MUST be serialized as members of the JSON object that results from serializing the PropertyAffordance instance, with the Vocabulary Term as name. See for details on serializing DataSchema instances.

The value assigned to forms in an instance of PropertyAffordance MUST be serialized as a JSON array containing one or more JSON object serializations as defined in .

A snippet for two Property affordances is given below:

actions

In a Thing instance, the value assigned to actions is a Map of instances of ActionAffordance. All name-value pairs of a Map of ActionAffordance instances MUST be serialized as members of the JSON object that results from serializing the Map; the name of a pair MUST be serialized as a JSON string and the value of the pair, an instance of ActionAffordance, MUST be serialized as a JSON object.

All name-value pairs of an instance of ActionAffordance, where the name is a Vocabulary Term included in (one of) the Signatures of ActionAffordance or InteractionAffordance, MUST be serialized as members of the JSON object that results from serializing the ActionAffordance instance, with the Vocabulary Term as name.

The values assigned to input and output in an instance of ActionAffordance MUST be serialized as JSON objects. They rely on the the Class DataSchema, whose serialization is defined in .

The value assigned to forms in an instance of ActionAffordance MUST be serialized as a JSON array containing one or more JSON object serializations as defined in .

A TD snippet of an Action affordance is given below:

events

In a Thing instance, the value assigned to events is a map of instances of EventAffordance. All name-value pairs of a Map of EventAffordance instances MUST be serialized as members of the JSON object that results from serializing the Map; the name of a pair MUST be serialized as a JSON string and the value of the pair, an instance of EventAffordance, MUST be serialized as a JSON object.

All name-value pairs of an instance of EventAffordance, where the name is a Vocabulary Term included in (one of) the Signatures of EventAffordance or InteractionAffordance, MUST be serialized as members of the JSON object that results from serializing the EventAffordance instance, with the Vocabulary Term as name.

The values assigned to subscription, data, and cancellation in an instance of EventAffordance MUST be serialized as JSON objects. They rely on the the Class DataSchema, whose serialization is defined in .

The value assigned to forms in an instance of EventAffordance MUST be serialized as a JSON array containing one or more JSON object serializations as defined in .

A TD snippet of an Event object is given below:

Event affordances have been defined in a flexible manner, in order to adopt existing (e.g., WebSub) or customer-oriented event mechanisms (e.g., Webhooks). For this reason, subscription and cancellation can be defined according to the desired mechanism. Please find further details in [[WoT-Binding-Templates]]. Example illustrates how Events can use subscription and cancellation to describe Webhooks.

forms

All name-value pairs of an instance of Form, where the name is a Vocabulary Term included in the Signature of Form, MUST be serialized as members of the JSON object that results from serializing the Form instance, with the Vocabulary Term as name.

If required, form objects MAY be supplemented with protocol-specific Vocabulary Terms identified with a prefix. See also .

A TD snippet of a form object in the forms array is given below:

href may also carry a URI that contains dynamic variables such as p and d in http://192.168.1.25/left?p=2&d=1. In that case the URI can be defined as template as defined in [[RFC6570]]: http://192.168.1.25/left{?p,d}.

In such a case, the URI Template variables MUST be collected in the JSON-object based uriVariables member with the associated (unique) variable names as JSON names.

The serialization of each value in the map assigned to uriVariables in an instance of Form MUST rely on the Class DataSchema, whose serialization is defined in .

A TD snippet using a URI Template and uriVariables is given below:

{
    "@context": [
        "https://www.w3.org/2019/wot/td/v1",
        { "eg": "http://www.example.org/iot" }
    ],
    ...
    "actions": {
        "LeftDown": {
            ...
            "uriVariables": {
                "p" : { "type": "integer", "minimum": 0, "maximum": 16, "@type": "eg:SomeKindOfAngle" },
                "d" : { "type": "integer", "minimum": 0, "maximum": 1, "@type": "eg:Direction" }
            },
            "forms": [{
              "href" : "http://192.168.1.25/left{?p,d}",
              "htv:methodName": "GET"
            }]
        },
        ...
    },
    ...
}

The contentType member is used to assign a media types [[!IANA-MEDIA-TYPES]] including media type parameters as attribute-value pairs separated by a ; character. Example:

    ...
    "contentType" : "text/plain; charset=utf-8",
    ...

In some use cases, the form metadata of the Interaction Affordance not only describes the request, but also provides metadata for the expected response. For instance, an Action takePhoto defines an input schema to submit parameter settings of a camera (aperture priority, timer, etc.) using JSON for the request payload (i.e., "contentType": "application/json"). The output of this action is the photo taken, which is available in JPEG format, for example. In such cases, the response member is used to indicate the representation format of the response payload (e.g., "contentType": "image/jpeg"). Here no output schema is required, as the content type fully specifies the representation format.

If present, the value assigned to response in an instance of Form MUST be a JSON object. If present, the response object MUST contain a contentType member as defined in the Class definition of ExpectedResponse.

A form snippet with the response member is shown below based on the takePhoto Action described above:

{
    ...
    "actions": {
        "takePhoto": {
            ...
            "forms": [{
                "op": "invokeaction",
                "href": "http://camera.example.com/api/snapshot",
                "contentType": "application/json",
                "response": {
                    "contentType": "image/jpeg"
                }
            }]
        }
    },
    ...
}

When forms is present at the top level, it can be used to describe meta interactions offered by a Thing. For example, the operation types "readallproperties" and "writeallproperties" are for meta interactions with a Thing by which Consumers can read and write all properties at once. In the example below, a forms member is included in the TD root object and the Consumer can use the submission target https://mylamp.example.com/allproperties both to read or write all Properties (i.e., on, brightness, and timer) of the Thing in a single protocol transaction.

{
    ...
    "properties": {
        "on": {
            "type": "boolean",
            "forms": [...]
        },
        "brightness": {
            "type": "number",
            "forms": [...]
        },
        "timer": {
            "type": "integer",
            "forms": [...]
        }
    },
    ...
    "forms": [{
        "op": "readallproperties",
        "href": "https://mylamp.example.com/allproperties",
        "contentType": "application/json",
        "htv:methodName": "GET"
    }, {
        "op": "writeallproperties",
        "href": "https://mylamp.example.com/allproperties",
        "contentType": "application/json",
        "htv:methodName": "PUT"
    }]
}

Data Schemas

The data schemas of the WoT Thing Description defined through the DataSchema Class are based on a subset of the JSON Schema terms [[?JSON-SCHEMA-VALIDATION]]. Thus, serializations of the TD data schemas can be fed directly into JSON Schema validator implementations to validate the data exchanged with Things.

Data schema serialization applies to PropertyAffordance instances, the values assigned to input and output in ActionAffordance instances, the values assigned to subscription, data, and cancellation in EventAffordance instances, and the value assigned to uriVariables in instances of Subclasses of InteractionAffordance (when a form object uses a URI Template).

All name-value pairs of an instance of one of the Subclasses of DataSchema, where the name is a Vocabulary Term included in the Signature of that Subclass or in the Signature of DataSchema, MUST be serialized as members of the JSON object that results from serializing the DataSchema Subclass's instance, with the Vocabulary Term as name.

The value assigned to properties in an instance of ObjectSchema MUST be serialized as a JSON object.

The values assigned to enum, required, and oneOf in an instance of DataSchema MUST be serialized as a JSON array.

The value assigned to items in an instance of ArraySchema MUST be serialized as a JSON object or a JSON array containing JSON objects.

A TD snippet data schema members is given below. Note that the surrounding object may be a data schema object (e.g., for input and output) or a Property object, which would contain additional members.

The terms readOnly and writeOnly can be used signal which data items are exchanged in read interactions (i.e., when reading a Property) and which in write interactions (i.e., when writing a Property). This can be used as workaround when Properties of an unconventional Thing exhibit different data for reading and writing, which can be the case when augmenting an existing device or service with a Thing Description.

A TD snippet with the usage of readOnly and writeOnly is given below:

    ...
    "properties": {
        "status": {
            "description": "Read or write On/Off status.",
            "type": "object",
            "properties": {
                "latestStatus": {
                    "type": "string",
                    "enum": ["On", "Off"],
                    "readOnly": true
                },
                "newStatusValue": {
                    "type": "string",
                    "enum": ["On", "Off"],
                    "writeOnly": true
                }
            },
            forms: [...]
        }
    }
    ...

When the status Property is read, the status data is returned using a latestStatus member in the payload. To update the status Property, the new value must be provided through a newStatusValue member in the payload.

As an additional feature, a Thing Description instance allows the usage of a unit member within data schemas. This can be used to associate a unit of measure to a data item. Its string value can be selected freely, however, it is recommended to select units based on existing definitions by integrating the corresponding namespace (e.g., from Smart Appliances REFerence (SAREF) ontology or Ontology of units of Measure (OM)). See for details.

Identification

The JSON-based serialization of Thing Descriptions is identified by the media type application/td+json or the CoAP Content-Format ID T.B.D. (see ).

CoAP-based WoT implementations can use the experimental Content-Format 65100 until the final Content-Format ID has been assigned.

TD Context Extensions

In addition to the standard Vocabulary definitions in , the WoT Thing Description offers the possibility to add context knowledge from additional namespaces. This mechanism can be used to enrich the Thing Description instances with additional (e.g., domain-specific) semantics. It can also be used to import additional Protocol Bindings or new security schemes in the future.

For such TD Context Extensions, the Thing Descriptions use the @context mechanism known from JSON-LD [[?json-ld11]]. When using TD Context Extensions, the value of @context of the Class Thing is an Array with additional elements of type anyURI identifying JSON-LD context files or Map containing namespace IRIs as defined in .

The serialization rules for complex types in define the serialization of an extended @context name-value pair. A snippet with TD Context Extensions is given below:

{
    "@context": [
        "https://www.w3.org/2019/wot/td/v1",
        {
            "iot": "http://example.org/iot",
            "cov": "http://www.example.org/coap-binding#"
        },
        "https://schema.org/"
    ],
    ...
}

Semantic Annotations

TD Context Extensions allow for additional Vocabulary Terms to a Thing Description instance. If the included namespaces are based on Class definitions such as those provided by the RDF Schema or OWL, they can be used to annotate any Class instance of a Thing Description semantically by associating the instance to a such an external Class definition. This is done by assigning a Class name to the @type name-value pair or including Class name in its Array value for multiple associations/annotations. Following the serialization rules in , @type is either serialized as JSON string or as JSON array. @type is the JSON-LD keyword [[?json-ld11]] used to set the type of a node.

TD Context Extensions also allow the inclusion of additional name-value pairs and well-defined values within any Class instance of a Thing Description. These pairs and values are defined through the included Vocabulary Terms and are serialized as additional members in the corresponding JSON objects or values of existing members, respectively. Examples are additional version metadata for the Thing or units of measure for data items.

As an example, the TD snippet given below extends the version information container by addind version numbers for the hardware and firmware of the Thing, semantically annotates a Property, and uses a well-defined value for the data schema unit.

{
    "@context": [
        "https://www.w3.org/2019/wot/td/v1",
        {
            "v": "http://www.example.org/versioningTerms#",
            "saref": "https://w3id.org/saref#",
            "om": "http://www.wurvoc.org/vocabularies/om-1.8/"
        }
    ],
    "@type": "Thing",
    "version": {
        "instance": "1.2.1",
        "v:firmware": "0.9.1",
        "v:hardware": "1.0"
    },
    ...
    "properties": {
        "temperature": {
            "@type": "saref:Temperature",
            "description": "Temperature value of the weather station",
            "type": "number",
            "minimum": -32.5,
            "maximum": 55.2,
            "unit": "om:degree_Celsius",
            "forms": [...]
        },
        ...
    },
    ...
}

In many cases, context extension may be used to annotate pieces of a data schema, as in the TD snippet below. The example references SSN/SOSA [[vocab-ssn]] and OM 1.8, an ontology for units of measure [[Rijgersberg-et-al-2013]]. Note that object assigned to temperature is a data schema and not the actual temperature property of the physical world object. More details on modeling the physical world can be found in Appendix .

{
    "@context": [
        "https://www.w3.org/2019/wot/td/v1",
        {
            "sosa": "http://www.w3.org/ns/sosa/",
            "ssn": "http://www.w3.org/ns/ssn/",
            "om": "http://www.wurvoc.org/vocabularies/om-1.8/"
        }
    ],
    "@type": "Thing",
    "id": "urn:dev:ops:32473-WoTLamp-1234",
    "sosa:observes": {
        "@id": "urn:dev:ops:32473-WoTStation-1234/temperature",
        "@type": "om:Temperature"
    },
    ...
    "properties": {
        "temperature": {
            "ssn:forProperty": "urn:dev:ops:32473-WoTStation-1234/temperature",
            "description": "Temperature measurement of the weather station",
            "type": "number",
            "minimum": -32.5,
            "maximum": 55.2,
            "unit": "om:degree_Celsius",
            "forms": [...]
        },
        ...
    },
    ...
}

Adding Protocol Bindings

With the TD Context Extensions in a Thing Description, the communication metadata can be supplemented or new Protocol Bindings added through additional Vocabulary Terms serialized into JSON objects representing a Form instance. (see also ).

The following TD example uses a fictional CoAP Protocol Binding, as no such Protocol Binding is available at the time of writing this specification. This TD Context Extension assumes that there is a CoAP RDF vocabulary similar to [[HTTP-in-RDF10]] that is accessable via the namespace http://www.example.org/coap-binding#. The supplemented cov:methodName member instructs the Consumer which CoAP method has to be applied (e.g., GET for the CoAP Method Code 0.01, POST for the CoAP Method Code 0.02, or iPATCH for CoAP Method Code 0.07).

Adding Security Schemes

Finally, new security schemes that are not included in can be imported using the TD Context Extension mechanism. This example uses a fictional ACE security scheme based on [[?draft-ietf-ace-oauth-authz]] that is, for this example, defined by the namespace at http://www.example.org/ace-security#. Note that such additional security schemes must be Subclasses of the Class SecurityScheme.

{
    @context: [
        "https://www.w3.org/2019/wot/td/v1",
        {
            "cov": "http://www.example.org/coap-binding#",
            "ace": "http://www.example.org/ace-security#"
        }
    ],
    ...
    "securityDefinitions": {
        "ace_sc": {
            "scheme": "ace:ACESecurityScheme",
            ...
            "ace:as": "coaps://as.example.com/token",
            "ace:audience": "coaps://rs.example.com",
            "ace:scopes": ["limited", "special"],
            "ace:cnonce": true
        }
    },
    "security": ["ace_sc"],
    "properties": {
        "status": {
            ...
            "forms": [{
                "op": "readproperty",
                "href": "coaps://rs.example.com/status",
                "contentType": "application/cbor",
                "cov:methodName": "GET",
                "ace:scopes": ["limited"]
            }]
        }
    },
    "action": {
        "configure": {
            ...
            "forms": [{
                "op": "invokeaction",
                "href": "coaps://rs.example.com/configure",
                "contentType": "application/cbor",
                "cov:methodName": "POST",
                "ace:scopes": ["special"]
            }]
        }
    },
    ...
}

Note that all security schemes defined in are already part of the TD context and need not to be included through a context extension.

Behavioral Assertions

The following assertions relate to the behavior of components of a WoT system, as opposed to the representation or information model of the TD. However, note that TDs are descriptive, and may in particular be used to describe pre-existing network interfaces. In these cases, assertions cannot be made that constrain the behaviour of such pre-existing interfaces. Instead, the assertions must be interpreted as constraints on the TD to accurately represent such interfaces.

Security Configurations

To enable secure interoperation, security configurations must accurately reflect the requirements of the Thing:

Some security protocols may ask for authentication information dynamically, including required encoding or encryption schemes. One consequence of the above is that if a protocol asks for a form of security credentials or an encoding or encryption scheme not declared in the Thing Description then the Thing Description is to be considered invalid.

Data Schemas

The data schemas provided in the TD should accurately represent the data payloads returned and accepted by the described Thing in the interactions specified in the TD. In general, Consumers should follow the data schemas strictly, not generating anything not given in the WoT Thing Description, but should accept additional data from the Thing not given explicitly in the WoT Thing Decription. In general, Things are described by WoT Thing Descriptions, but Consumers are constrained to follow WoT Thing Descriptions when interacting with Things.

Protocol Bindings

A Protocol Binding is the mapping from an Interaction Affordance to concrete messages of a specific protocol such as HTTP [[!RFC7231]], CoAP [[!RFC7252]], or MQTT [[!MQTT]]. Protocol Bindings of Interaction Affordances are serialized as forms as defined in .

Every form in a WoT Thing Description must have a submission target, given by the href member. The URI scheme of this submission target indicates what Protocol Binding the Thing implements [[WoT-Architecture]]. For instance, if the target starts with http or https, a Consumer can then infer the Thing implements the HTTP Protocol Binding and it should expect HTTP-specific terms in the form instance (see next section, ).

HTTP Protocol Binding

Per default the Thing Description supports the HTTP Protocol Binding and includes the HTTP RDF vocabulary set definitions from [[HTTP-in-RDF10]] and can be directly used within TD instances by the usage of the prefix htv, which points to http://www.w3.org/2011/http#.

To interact with a Thing that implements the HTTP Protocol Binding, a Consumer needs to know what HTTP method to use when submitting a form. In the general case, a Thing Description can explicitly include a term indicating the method, i.e., htv:methodName. For the sake of conciseness, the HTTP Protocol Binding defines Default Values for each operation type, which also aims at convergence of the methods expected by Things (e.g., GET to read, PUT to write). When no method is indicated in a form representing an HTTP Protocol Binding, a Default Value MUST be assumed as shown in the following table.

Vocabulary term Default value Context
htv:methodName GET Form with operation type readproperty
htv:methodName PUT Form with operation type writeproperty
htv:methodName POST Form with operation type invokeaction

For example, the following Default Values should be assumed for forms in the introductory TD example:

Other Protocol Bindings

The number of Protocol Bindings a Thing can implement is not restricted. Other Protocol Bindings (e.g., for CoAP, MQTT, or OPC UA) are intended to be standardized in separate documents such as a protocol Vocabulary similar to HTTP Vocabulary in RDF 1.0 [[HTTP-in-RDF10]] or specifications including Default Value definitions. Such protocols can be simply integrated into the TD by the usage of the context extension mechanism ().

Security and Privacy Considerations

In general the security measures taken to protect a WoT system will depend on the threats and attackers that system may face and the value of the assets needs to protect. A detailed discussion of security and privacy considerations for the Web of Things, including a threat model that can be adapted to various circumstances, is presented in the informative document [[WOT-SECURITY-CONSIDERATIONS]]. This section discusses only security and privacy risks and possible mitigations directly relevant to the WoT Thing Description.

A WoT Thing Description can describe both secure and insecure network interfaces. When a Thing Description is retro-fitted to an existing network interface, no change in the security status of the network interface is to be expected.

The use of a WoT Thing Description introduces the security and privacy risks given in the following sections. After each risk, we suggest some possible mitigations.

Context Dereferencing Privacy Risk

Deferencing the vocabulary files given in the @context member of any JSON-LD [[?json-ld11]] document can be a privacy risk. In the case of the WoT, an attacker can observe the network traffic produced by such deferences and can use the metadata of the dereference, such as the destination IP address, to infer information about the device especially if domain-specific vocabularies are used. This is a risk even if the connection is encrypted, and is related to DNS privacy leaks.

Mitigation:
Avoid actual dereferencing of vocabulary files. Vocabulary files should be cached whenever possible. Ideally they would be made immutable, built into the interpreting device, and not derefenced at all, with the URI in the @context member serving only as an identifier of the (known) vocabulary. This requires the use of strict version control, as updates should use a new URI to ensure that existing URIs can refer to immutable data. Use well-known standard vocabulary files whenever possible to improve the chances that the context file will be available locally to systems interpreting the metadata in a Thing Description.
Immutable Identifiers Privacy Risk

The fact that a Thing Description contains a unique identifier means that should it be associated with a person it can be used to track that person and therefore pose a risk to privacy.

Mitigation:
All identifiers should be mutable, and there should be a mechanism to update the id of a Thing. Specifically, the id of a Thing should not be fixed in hardware. This does, however, conflict with the Linked Data ideal that identifiers are fixed URIs. In many circumstances it will be acceptable to only allow updates to identifiers if a Thing is reinitialized. In this case as a software entity the old Thing ceases to exist and a new Thing is created. This can be sufficient to break a tracking chain when, for example, a device is sold to a new owner. Alternatively, if more frequent changes are desired during the operational phase of a device, a mechanism can be put into place to notify only authorized users of the change in identifier when a change is made. Note however that some classes of devices, e.g. medical devices, may require immutable IDs by law in some jurisdictions. In this case extra attention should be paid to secure access to files, such as Thing Descriptions, containing such immutable identifiers.

Fingerprinting Privacy Risk

As noted above, the id member in a TD can pose a privacy risk. However, even if the id is updated as described to mitigate its tracking risk, it may still be possible to associate a TD with a particular physical device, and from there to a person, through fingerprinting.

Mitigation:
Only authorized users should be provided access to the Thing Description for a Thing. If the TD is only distributed to authorized users through secure and confidential channels, for example through a directory service that requires authentication, the risk can be minimized.
TD Interception and Tampering Security Risk

Intercepting and tampering with TDs can be used to launch man-in-the-middle attacks, for example by rewriting URLs in TDs to redirect accesses to a malicious intermediary that can capture or manipulate data.

Mitigation:
Obtain Thing Descriptions only through mutually authenticated channels. This ensures that the Consumer and the server are both sure of the identity of the other party to the communication. This is also necessary in order to deliver TDs only to authorized users.
Context Interception and Tampering Security Risk

Intercepting and tampering with context files can be used to facilitate attacks by modifying the interpretation of vocabulary.

Mitigation:
Ideally context files would only be obtained through authenticated channels but it is notable (and unfortunate) that many contexts are indicated using HTTP URLs, which are vulnerable to interception and modification if dereferenced. However, if context files are immutable and cached, and dereferencing is avoided whenever possible, then this risk can be reduced.
Inferencing of Personally Identifiable Information Privacy Risk

In many locales, in order to protect the privacy of users, there are legal requirements for the handling of personally identifiable information, that is, information that can be associated with a particular person. Such information can of course be generated by IoT devices directly. However, the existence and metadata of IoT devices (the kind of data stored in a Thing Description) can also contain or be used to infer personally identifiable information. This information can be as simple as the fact that a certain person owns a certain type of device, which can lead to additional inferences about that person.

Mitigation:
Treat a Thing Description associated with a personal device as if it contained personally identifiable information. As an example application of this principle, consider how to obtain user consent. Consent for usage of personally identifiable data generated by a Thing is often obtained when a Thing is paired with system consuming the data, which is frequently also when the Thing Description is registered with a local directory or the system consuming the Thing Description in order to access the device. In this case, consent for using data from a Thing can be combined with consent for accessing the Thing Description of the Thing. As a second example, if we consider a TD to contain personally identifiable information, then it should not be retained indefinitely or used for purposes other than those for which consent was given.

IANA Considerations

application/td+json Media Type Registration

Type name:
application
Subtype name:
td+json
Required parameters:
None
Optional parameters:
None
Encoding considerations:
See RFC 6839, section 3.1.
Security considerations:
See RFC 8259.

Since WoT Thing Description is intended to be a pure data exchange format for Thing metadata, the serialization SHOULD NOT be passed through a code execution mechanism such as JavaScript's eval() function to be parsed. An (invalid) document may contain code that, when executed, could lead to unexpected side effects compromising the security of a system.

WoT Thing Descriptions can be evaluated with a JSON-LD 1.1 processor, which typically follows links to remote contexts (i.e., TD context extensions, see ) automatically, resulting in the transfer of files without the explicit request of the Consumer for each one. If remote contexts are served by third parties, it may allow them to gather usage patterns or similar information leading to privacy concerns. While implementations on resource-constrained devices are expected to perform raw JSON processing (as opposed to JSON-LD processing), implementations in general SHOULD statically cache vetted versions of their supported context extensions and not to follow links to remote contexts. Supported context extensions can be managed through a secure software update mechanism instead.

Context Extensions (see ) that are loaded from the Web over non-secure connections, such as HTTP, run the risk of being altered by an attacker such that they may modify the TD Information Model in a way that could compromise security. For this reason, Consumer again SHOULD vet and cache remote contexts before allowing the system to use it.

Given that JSON-LD processing usually includes the substitution of long IRIs with short terms, WoT Thing Descriptions may expand considerably when processed using a JSON-LD 1.1 processor and, in the worst case, the resulting data might consume all of the recipient's resources. Consumers SHOULD treat any TD metadata with due skepticism.

Interoperability considerations:
See RFC 8259.

Rules for processing both conforming and non-conforming content are defined in this specification.

Published specification:
https://w3c.github.io/wot-thing-description
Applications that use this media type:
All participating entities in the W3C Web of Things, that is, Things, Consumers, and Intermediaries as defined in the Web of Things (WoT) Architecture.
Fragment identifier considerations:
See RFC 6839, section 3.1.
Additional information:
Magic number(s):
Not Applicable
File extension(s):
.jsontd
Macintosh file type code(s):
TEXT
Person & email address to contact for further information:
Matthias Kovatsch <w3c@kovatsch.net>
Intended usage:
COMMON
Restrictions on usage:
None
Author(s):
The WoT Thing Description specification is a product of the Web of Things Working Group.
Change controller:
W3C

CoAP Content-Format Registration

IANA assigns compact CoAP Content-Format IDs for media types in the CoAP Content-Formats subregistry within the Constrained RESTful Environments (CoRE) Parameters registry [[RFC7252]]. The Content-Format ID for WoT Thing Description is (t.b.d.) in the 256-9999 range (IETF Review or IESG Approval).

Media Type:
application/td+json
Encoding:
-
ID:
T.B.D.
Reference:
["Web of Things (WoT) Thing Description", May 2019]

Example Thing Description Instances

MyLampThing Example with CoAP Protocol Binding

Feature list of the Thing:

  {
     "@context": [
        "https://www.w3.org/2019/wot/td/v1",
        {
        "cov": "http://www.example.org/coap-binding#"
        }
      ],
      "id": "urn:dev:ops:32473-WoTLamp-1234",
      "title": "MyLampThing",
      "description" : "MyLampThing uses JSON serialization",
      "securityDefinitions": {"psk_sc":{"scheme": "psk"}},
      "security": ["psk_sc"],
      "properties": {
          "status": {
              "description" : "Shows the current status of the lamp",
              "type": "string",
              "forms": [{
                  "href": "coaps://mylamp.example.com/status",
                  "cov:methodName" : "GET" 
              }]
          }
      },
      "actions": {
          "toggle": {
              "description" : "Turn on or off the lamp",
              "forms": [{
                  "href": "coaps://mylamp.example.com/toggle",
                  "cov:methodName" : "POST" 
              }]
          }
      },
      "events": {
          "overheating": {
              "description" : "Lamp reaches a critical temperature (overheating)",
              "data": {"type": "string"},
              "forms": [{
                  "href": "coaps://mylamp.example.com/oh",
                  "cov:methodName" : "GET",
                  "subprotocol" : "cov:observe" 
              }]
          }
      }
  }
  

MyLightSensor Example with MQTT Protocol Binding

Feature list of the Thing:

          {   
              "@context": "https://www.w3.org/2019/wot/td/v1",
              "title": "MyLightSensor",
              "id": "urn:dev:ops:32473-WoTLightSensor-1234",
              "securityDefinitions": {"nosec_sc": {"scheme": "nosec"}},
              "security": ["nosec_sc"],
              "events": {
                  "lightSensor": {
                      "data":{"type": "integer"},
                      "forms": [
                          {
                              "href": "mqtt://192.168.1.187:1883/lightSensor",
                              "contentType" : "text/plain"
                          }
                      ]
                  }
              } 
          }
  

Webhook Event Example

Feature list of the Thing:

{
    "@context": "https://www.w3.org/2019/wot/td/v1",
    "id": "urn:dev:ops:32473-Thing-1234",
    "title": "WebhookThing",
    "description": "Webhook-based Event with subscription and unsubscribe form.",
    "securityDefinitions": {"nosec_sc": {"scheme": "nosec"}},
    "security": ["nosec_sc"],
    "events": {
        "temperature": {
            "description": "Provides periodic temperature value updates.",
            "subscription": {
                "type": "object",
                "properties": {
                    "callbackURL": {
                        "type": "string",
                        "format": "uri",
                        "description": "Callback URL provided by subscriber for Webhook notifications.",
                        "writeOnly": true
                    },
                    "subscriptionID": {
                        "type": "string",
                        "description": "Unique subscription ID for cancellation provided by WebhookThing.",
                        "readOnly": true
                    }
                }
            },
            "data": {
                "type": "number",
                "description": "Latest temperature value that is sent to the callback URL."
            },
            "cancellation": {
                "type": "object",
                "properties": {
                    "subscriptionID": {
                        "type": "integer",
                        "description": "Required subscription ID to cancel subscription.",
                        "writeOnly": true
                    }
                }
            },
            "uriVariables": {
                "subscriptionID": { "type": "string" }
            },
            "forms": [
                {
                    "op": "subscribeevent",
                    "href": "http://192.168.0.124:8080/events/temp/subscribe",
                    "contentType": "application/json",
                    "htv:methodName": "POST"
                },
                {
                    "op": "unsubscribeevent",
                    "href": "http://192.168.0.124:8080/events/temp/{subscriptionID}",
                    "htv:methodName": "DELETE"
                }
            ]
        }
    }
}

JSON Schema for TD Instance Validation

Below is a JSON Schema [[?JSON-SCHEMA-VALIDATION]] document for syntactically validating Thing Description instances serialized in JSON based format.

The Thing Description defined by this document allows for adding external vocabularies by using @context mechanism known from JSON-LD [[?json-ld11]], and the terms in those external vocabularies can be used in addition to the terms defined in . For this reason, the below JSON schema is intentionally non-strict in that regard. You can replace the value of additionalProperties schema property true with false in different scopes/levels in order to perform a stricter validation in case no external vocabularies are used.

Please note that some JSON Schema validation tools do not support the iri string format.

The following JSON Schema for validating TD instances does not require the terms with Default Values to be present. Thus the terms with Default Values are optional. (see also )

    {
    "title": "WoT TD Schema - 08 May 2019",
    "description": "JSON Schema for validating TD instances against the TD model. TD instances can be with or without terms that have default values",
    "$schema ": "http://json-schema.org/draft-07/schema#",
    "definitions": {
        "thing-context-w3c-uri": {
            "type": "string",
            "enum": [
                "https://www.w3.org/2019/wot/td/v1"
            ]
        },
        "thing-context": {
            "oneOf": [{
                    "type": "array",
                    "items": {
                        "anyOf": [{
                                "$ref": "#/definitions/anyUri"
                            },
                            {
                                "type": "object"
                            }
                        ]
                    },
                    "contains": {
                        "$ref": "#/definitions/thing-context-w3c-uri"
                    }
                },
                {
                    "$ref": "#/definitions/thing-context-w3c-uri"
                }
            ]
        },
        "type_declaration": {
            "oneOf": [{
                    "type": "string"
                },
                {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                }
            ]
        },
        "property_element": {
            "type": "object",
            "properties": {
                "@type": {
                    "$ref": "#/definitions/type_declaration"
                },
                "description": {
                    "$ref": "#/definitions/description"
                },
                "descriptions": {
                    "$ref": "#/definitions/descriptions"
                },
                "title": {
                    "$ref": "#/definitions/title"
                },
                "titles": {
                    "$ref": "#/definitions/titles"
                },
                "uriVariables": {
                    "type": "object",
                    "additionalProperties": {
                        "$ref": "#/definitions/dataSchema"
                    }
                },
                "forms": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                        "$ref": "#/definitions/form_element_property"
                    }
                },
                "observable": {
                    "type": "boolean"
                },
                "writeOnly": {
                    "type": "boolean"
                },
                "readOnly": {
                    "type": "boolean"
                },
                "oneOf": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/dataSchema"
                    }
                },
                "unit": {
                    "type": "string"
                },
                "enum": {
                    "type": "array",
                    "minItems": 1,
                    "uniqueItems": true
                },
                "format": {
                    "type": "string"
                },
                "const": {},
                "type": {
                    "type": "string",
                    "enum": [
                        "boolean",
                        "integer",
                        "number",
                        "string",
                        "object",
                        "array",
                        "null"
                    ]
                },
                "items": {
                    "oneOf": [{
                            "$ref": "#/definitions/dataSchema"
                        },
                        {
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/dataSchema"
                            }
                        }
                    ]
                },
                "maxItems": {
                    "type": "integer",
                    "minimum": 0
                },
                "minItems": {
                    "type": "integer",
                    "minimum": 0
                },
                "minimum": {
                    "type": "number"
                },
                "maximum": {
                    "type": "number"
                },
                "properties": {
                    "additionalProperties": {
                        "$ref": "#/definitions/dataSchema"
                    }
                },
                "required": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                }
            },
            "required": [
                "forms"
            ],
            "additionalProperties": true
        },
        "action_element": {
            "type": "object",
            "properties": {
                "description": {
                    "type": "string"
                },
                "descriptions": {
                    "$ref": "#/definitions/descriptions"
                },
                "title": {
                    "$ref": "#/definitions/title"
                },
                "titles": {
                    "$ref": "#/definitions/titles"
                },
                "uriVariables": {
                    "type": "object",
                    "additionalProperties": {
                        "$ref": "#/definitions/dataSchema"
                    }
                },
                "@type": {
                    "$ref": "#/definitions/type_declaration"
                },
                "forms": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                        "$ref": "#/definitions/form_element_action"
                    }
                },
                "input": {
                    "$ref": "#/definitions/dataSchema"
                },
                "output": {
                    "$ref": "#/definitions/dataSchema"
                },
                "safe": {
                    "type": "boolean"
                },
                "idempotent": {
                    "type": "boolean"
                }
            },
            "required": [
                "forms"
            ],
            "additionalProperties": true
        },
        "event_element": {
            "type": "object",
            "properties": {
                "description": {
                    "type": "string"
                },
                "descriptions": {
                    "$ref": "#/definitions/descriptions"
                },
                "title": {
                    "$ref": "#/definitions/title"
                },
                "titles": {
                    "$ref": "#/definitions/titles"
                },
                "uriVariables": {
                    "type": "object",
                    "additionalProperties": {
                        "$ref": "#/definitions/dataSchema"
                    }
                },
                "@type": {
                    "$ref": "#/definitions/type_declaration"
                },
                "forms": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                        "$ref": "#/definitions/form_element_event"
                    }
                },
                "subscription": {
                    "$ref": "#/definitions/dataSchema"
                },
                "data": {
                    "$ref": "#/definitions/dataSchema"
                },
                "cancellation": {
                    "$ref": "#/definitions/dataSchema"
                },
                "type": {
                    "not": {}
                },
                "enum": {
                    "not": {}
                },
                "const": {
                    "not": {}
                }
            },
            "required": [
                "forms"
            ],
            "additionalProperties": true
        },
        "form_element_property": {
            "type": "object",
            "properties": {
                "href": {
                    "$ref": "#/definitions/anyUri"
                },
                "op": {
                    "oneOf": [{
                            "type": "string",
                            "enum": [
                                "readproperty",
                                "writeproperty",
                                "observeproperty",
                                "unobserveproperty"
                            ]
                        },
                        {
                            "type": "array",
                            "items": {
                                "type": "string",
                                "enum": [
                                    "readproperty",
                                    "writeproperty",
                                    "observeproperty",
                                    "unobserveproperty"
                                ]
                            }
                        }
                    ]
                },
                "contentType": {
                    "type": "string"
                },
                "security": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "scopes": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "subProtocol": {
                    "type": "string",
                    "enum": [
                        "longpoll",
                        "websub",
                        "sse"
                    ]
                },
                "response": {
                    "type": "object",
                    "properties": {
                        "contentType": {
                            "type": "string"
                        }
                    }
                }
            },
            "required": [
                "href"
            ],
            "additionalProperties": true
        },
        "form_element_action": {
            "type": "object",
            "properties": {
                "href": {
                    "$ref": "#/definitions/anyUri"
                },
                "op": {
                    "oneOf": [{
                            "type": "string",
                            "enum": [
                                "invokeaction"
                            ]
                        },
                        {
                            "type": "array",
                            "items": {
                                "type": "string",
                                "enum": [
                                    "invokeaction"
                                ]
                            }
                        }
                    ]
                },
                "contentType": {
                    "type": "string"
                },
                "security": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "scopes": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "subProtocol": {
                    "type": "string",
                    "enum": [
                        "longpoll",
                        "websub",
                        "sse"
                    ]
                },
                "response": {
                    "type": "object",
                    "properties": {
                        "contentType": {
                            "type": "string"
                        }
                    }
                }
            },
            "required": [
                "href"
            ],
            "additionalProperties": true
        },
        "form_element_event": {
            "type": "object",
            "properties": {
                "href": {
                    "$ref": "#/definitions/anyUri"
                },
                "op": {
                    "oneOf": [{
                            "type": "string",
                            "enum": [
                                "subscribeevent",
                                "unsubscribeevent"
                            ]
                        },
                        {
                            "type": "array",
                            "items": {
                                "type": "string",
                                "enum": [
                                    "subscribeevent",
                                    "unsubscribeevent"
                                ]
                            }
                        }
                    ]
                },
                "contentType": {
                    "type": "string"
                },
                "security": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "scopes": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "subProtocol": {
                    "type": "string",
                    "enum": [
                        "longpoll",
                        "websub",
                        "sse"
                    ]
                },
                "response": {
                    "type": "object",
                    "properties": {
                        "contentType": {
                            "type": "string"
                        }
                    }
                }
            },
            "required": [
                "href"
            ],
            "additionalProperties": true
        },
        "form_element_root": {
            "type": "object",
            "properties": {
                "href": {
                    "$ref": "#/definitions/anyUri"
                },
                "op": {
                    "oneOf": [{
                            "type": "string",
                            "enum": [
                                "readallproperties",
                                "writeallproperties",
                                "readmultipleproperties",
                                "writemultipleproperties"
                            ]
                        },
                        {
                            "type": "array",
                            "items": {
                                "type": "string",
                                "enum": [
                                    "readallproperties",
                                    "writeallproperties",
                                    "readmultipleproperties",
                                    "writemultipleproperties"
                                ]
                            }
                        }
                    ]
                },
                "contentType": {
                    "type": "string"
                },
                "security": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "scopes": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "subProtocol": {
                    "type": "string",
                    "enum": [
                        "longpoll",
                        "websub",
                        "sse"
                    ]
                },
                "response": {
                    "type": "object",
                    "properties": {
                        "contentType": {
                            "type": "string"
                        }
                    }
                }
            },
            "required": [
                "href"
            ],
            "additionalProperties": true
        },
        "description": {
            "type": "string"
        },
        "title": {
            "type": "string"
        },
        "descriptions": {
            "type": "object"
        },
        "titles": {
            "type": "object"
        },
        "dataSchema": {
            "type": "object",
            "properties": {
                "@type": {
                    "$ref": "#/definitions/type_declaration"
                },
                "description": {
                    "$ref": "#/definitions/description"
                },
                "title": {
                    "$ref": "#/definitions/title"
                },
                "descriptions": {
                    "$ref": "#/definitions/descriptions"
                },
                "titles": {
                    "$ref": "#/definitions/titles"
                },
                "writeOnly": {
                    "type": "boolean"
                },
                "readOnly": {
                    "type": "boolean"
                },
                "oneOf": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/dataSchema"
                    }
                },
                "unit": {
                    "type": "string"
                },
                "enum": {
                    "type": "array",
                    "minItems": 1,
                    "uniqueItems": true
                },
                "format": {
                    "type": "string"
                },
                "const": {},
                "type": {
                    "type": "string",
                    "enum": [
                        "boolean",
                        "integer",
                        "number",
                        "string",
                        "object",
                        "array",
                        "null"
                    ]
                },
                "items": {
                    "oneOf": [{
                            "$ref": "#/definitions/dataSchema"
                        },
                        {
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/dataSchema"
                            }
                        }
                    ]
                },
                "maxItems": {
                    "type": "integer",
                    "minimum": 0
                },
                "minItems": {
                    "type": "integer",
                    "minimum": 0
                },
                "minimum": {
                    "type": "number"
                },
                "maximum": {
                    "type": "number"
                },
                "properties": {
                    "additionalProperties": {
                        "$ref": "#/definitions/dataSchema"
                    }
                },
                "required": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                }
            }
        },
        "link_element": {
            "type": "object",
            "properties": {
                "anchor": {
                    "$ref": "#/definitions/anyUri"
                },
                "href": {
                    "$ref": "#/definitions/anyUri"
                },
                "rel": {
                    "type": "string"
                },
                "type": {
                    "type": "string"
                }
            },
            "required": [
                "href"
            ],
            "additionalProperties": true
        },
        "securityScheme": {
            "oneOf": [{
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/anyUri"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "nosec"
                            ]
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/anyUri"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "basic"
                            ]
                        },
                        "in": {
                            "type": "string",
                            "enum": [
                                "header",
                                "query",
                                "body",
                                "cookie"
                            ]
                        },
                        "name": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/anyUri"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "cert"
                            ]
                        },
                        "identity": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/anyUri"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "digest"
                            ]
                        },
                        "qop": {
                            "type": "string",
                            "enum": [
                                "auth",
                                "auth-int"
                            ]
                        },
                        "in": {
                            "type": "string",
                            "enum": [
                                "header",
                                "query",
                                "body",
                                "cookie"
                            ]
                        },
                        "name": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/anyUri"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "bearer"
                            ]
                        },
                        "authorization": {
                            "$ref": "#/definitions/anyUri"
                        },
                        "alg": {
                            "type": "string",
                            "enum": [
                                "MD5",
                                "ES256",
                                "ES512-256"
                            ]
                        },
                        "format": {
                            "type": "string",
                            "enum": [
                                "jwt",
                                "jwe",
                                "jws"
                            ]
                        },
                        "in": {
                            "type": "string",
                            "enum": [
                                "header",
                                "query",
                                "body",
                                "cookie"
                            ]
                        },
                        "name": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/anyUri"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "psk"
                            ]
                        },
                        "identity": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/anyUri"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "public"
                            ]
                        },
                        "identity": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/anyUri"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "oauth2"
                            ]
                        },
                        "authorization": {
                            "$ref": "#/definitions/anyUri"
                        },
                        "token": {
                            "$ref": "#/definitions/anyUri"
                        },
                        "refresh": {
                            "$ref": "#/definitions/anyUri"
                        },
                        "scopes": {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        },
                        "flow": {
                            "type": "string",
                            "enum": [
                                "implicit",
                                "password",
                                "client",
                                "code"
                            ]
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/anyUri"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "apikey"
                            ]
                        },
                        "in": {
                            "type": "string",
                            "enum": [
                                "header",
                                "query",
                                "body",
                                "cookie"
                            ]
                        },
                        "name": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                },
                {
                    "type": "object",
                    "properties": {
                        "@type": {
                            "$ref": "#/definitions/type_declaration"
                        },
                        "description": {
                            "$ref": "#/definitions/description"
                        },
                        "descriptions": {
                            "$ref": "#/definitions/descriptions"
                        },
                        "proxy": {
                            "$ref": "#/definitions/anyUri"
                        },
                        "scheme": {
                            "type": "string",
                            "enum": [
                                "pop"
                            ]
                        },
                        "authorization": {
                            "$ref": "#/definitions/anyUri"
                        },
                        "format": {
                            "type": "string",
                            "enum": [
                                "jwt",
                                "jwe",
                                "jws"
                            ]
                        },
                        "alg": {
                            "type": "string",
                            "enum": [
                                "MD5",
                                "ES256",
                                "ES512-256"
                            ]
                        },
                        "in": {
                            "type": "string",
                            "enum": [
                                "header",
                                "query",
                                "body",
                                "cookie"
                            ]
                        },
                        "name": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "scheme"
                    ]
                }
            ]
        },
        "anyUri": {
            "type": "string",
            "format": "iri-reference"
        }
    },
    "type": "object",
    "properties": {
        "id": {
            "type": "string",
            "format": "uri"
        },
        "title": {
            "$ref": "#/definitions/title"
        },
        "titles": {
            "$ref": "#/definitions/titles"
        },
        "properties": {
            "type": "object",
            "additionalProperties": {
                "$ref": "#/definitions/property_element"
            }
        },
        "actions": {
            "type": "object",
            "additionalProperties": {
                "$ref": "#/definitions/action_element"
            }
        },
        "events": {
            "type": "object",
            "additionalProperties": {
                "$ref": "#/definitions/event_element"
            }
        },
        "description": {
            "$ref": "#/definitions/description"
        },
        "descriptions": {
            "$ref": "#/definitions/descriptions"
        },
        "version": {
            "type": "object",
            "properties": {
                "instance": {
                    "type": "string"
                }
            },
            "required": [
                "instance"
            ]
        },
        "links": {
            "type": "array",
            "items": {
                "$ref": "#/definitions/link_element"
            }
        },
        "forms": {
            "type": "array",
            "minItems": 1,
            "items": {
                "$ref": "#/definitions/form_element_root"
            }
        },
        "base": {
            "$ref": "#/definitions/anyUri"
        },
        "securityDefinitions": {
            "type": "object",
            "minProperties": 1,
            "additionalProperties": {
                "$ref": "#/definitions/securityScheme"
            }
        },
        "support": {
            "$ref": "#/definitions/anyUri"
        },
        "created": {
            "type": "string"
        },
        "modified": {
            "type": "string"
        },
        "security": {
            "type": "array",
            "minItems": 1,
            "items": {
                "type": "string"
            }
        },
        "@type": {
            "$ref": "#/definitions/type_declaration"
        },
        "@context": {
            "$ref": "#/definitions/thing-context"
        }
    },
    "required": [
        "title",
        "id",
        "security",
        "securityDefinitions",
        "@context"
    ],
    "additionalProperties": true
}
    

Thing Templates

A Thing Template is a description for a class of Things. It describes the properties, actions, events and common metadata that are shared for an entire group of Things, to enable the common handling of thousands of devices by a cloud server, which is not practical on a per-Thing basis. The Thing Template uses the same core vocabulary and information model from section 5.

The Thing Template enables:

The Thing Template is a logical description of the interface and possible interaction with devices (properties, actions and events), however it does not contain device-specific information, such as a serial number, GPS location, security information or concrete protocol endpoints.

Since a Thing Template does not contain a Protocol Binding to specific endpoints and does not define a specific security mechanism, the forms and securityDefinitions and security keys must not be present.

The same Thing Template can be implemented by Things from multiple vendors, a Thing can implement multiple Thing Templates, define additional metadata (vendor, location, security) and define bindings to concrete protocols. To avoid conflicts between properties, actions and events from different Thing Templates that are combined into a common Thing, all these identifiers must be unique within a Thing.

A common Thing Template for a class of devices enables writing applications across vendors and creates a more attractive market for application developers. A concrete Thing Description can implement multiple Thing Templates and thus can aggregate function blocks into a combined device.

The business models of cloud vendors are typically built on managing thousands of identical devices. All devices with the same Thing Template can be managed in the same way by cloud applications. It is easy to create multiple simulated devices, if the interface and the instance are treated separately.

Since a Thing Template is a subset of the Thing Description in which some optional and mandatory Vocabulary Terms do not exist, however, it can be serialized in the same way and in the same formats as a Thing Description. Note that Thing Template instances cannot be validated in the same way as Thing Description instances due to some missing mandatory terms.

Thing Template Examples

This section shows a Thing Template for a lamp and a Thing Template for a buzzer.

Thing Template: Lamp

    {
        "@context": ["https://www.w3.org/2019/wot/td/v1"], 
        "@type" : "ThingTemplate",
        "title": "Lamp Thing Template",
        "description" : "Lamp Thing Template",
        "properties": {
            "status": {
                "description" : "current status of the lamp (on|off)",
                "type": "string",
                "readOnly": true
            }
        },
        "actions": {
            "toggle": {
                "description" : "Turn the lamp on or off"
            }
        },
        "events": {
            "overheating": {
                "description" : "Lamp reaches a critical temperature (overheating)",
                "data": {"type": "string"}
            }
        }
    }
    

Thing Template: Buzzer

    {
        "@context": ["https://www.w3.org/2019/wot/td/v1"], 
        "@type" : "ThingTemplate",
        "title": "Buzzer Thing Template",
        "description" : "Thing template of a buzzer that makes noise for 10 seconds",
         "actions": {
            "buzz": {
                "description" : "buzz for 10 seconds"
            }
         }
    }
    

Transformation to RDF

To integrate a Thing Description instance with external knowledge and contextual information (like SAREF annotations), the use of JSON-LD 1.1 and its processing API [[json-ld11-api]], as well as RDF-based tools [[rdf11-concepts]] and libraries is highly recommended. This appendix introduces two non-normative elements of the Thing Description model based on RDF: the default JSON-LD context for TD and the TD ontology.

Thing Description JSON-LD Context

A TD document can be transformed into RDF by a standard JSON-LD processor (to then be uploaded to an RDF store for further processing). The following procedure loads the context of the TD, given by the term @context, and generates RDF triples:

JsonLdProcessor.toRdf

When applying this procedure to the introductory TD example () with all Default Values, the following triples are obtained:

Most importantly, the JSON-LD context maps JSON strings to RDF IRIs (hence, the notion of context: in two different contexts, the same string can have different meanings). The mapping here is rather straightforward: every vocabulary of the TD information model is defined its own namespace and every vocabulary term maps to some name, appended to the corresponding namespace. Strings that are not part of any vocabulary map to RDF literals (strings with an optional datatype). For instance, title maps to https://www.w3.org/2019/wot/td#title and MyLampThing remains unchanged. Applying this mapping is called context expansion.

Then, after expanding JSON strings to full IRIs, all map structures of the TD document must be turned into RDF triples. In a simple case, a triple is produced for every key/value pair in the map. For instance, the very first triple of the example above was produced from "title": "myLampThing".

Other cases rely on specific JSON-LD features. Most of these features were introduced in the 1.1 version of the standard and thus require an appropriate JSON-LD 1.1 implementation. They are listed below:

The last two JSON-LD features (property-based data indexing and indexing without a predicate) are still experimental; they have not been published in any Editors' Draft yet.

Thing Description Ontology

As presented in the previous section, all Vocabulary Terms (including those denoting Classes) follow the RDF convention of belonging to a Vocabulary identified by a namespace IRI. As a result, the TD information model can be reformulated in the Web Ontology Language (OWL) [[owl2-overview]]. Class definitions become OWL axioms defined on the Vocabulary Terms of the TD model. The axioms that are particularly of interest in the present document are those of the TD ontology available under the TD namespace IRI, both as an RDF file and as a human-readable HTML documentation. Default Values cannot be directly translated to OWL, they are therefore ignored in the TD ontology.

The axioms included in the TD ontology may be used to validate a TD but its primary purpose is to serve as an entry point for a deeper semantic description of WoT Things that would make clients behave in a more autonomous way, as desired in WoT [[wot-architecture]]. A semantic description is nothing more than a description of the physical world, in which WoT systems may have tangible effects. OWL should be the preferred language for this purpose. OWL is indeed a language to specify ontologies, that is, conceptualizations of the physical world. To this end, an ontology does not cover one possible model of the physical world by constructing abstract data structures. Instead, it provides necessary constraints on all possible models of the world for these models to be sound. This principle, at the basis of model theory, is what the semantics of RDF (and OWL) is based on [[rdf11-mt]]. In the following diagram, because the only fact we know about urn:dev:ops:32473-WoTLamp-1234 is that it is a light switch with generic affordances, it could be any light switch, be it mechanical, digital or even virtual.

TD Serialization, TD and Thing on a light switch example

As a consequence, the TD ontology is meant to be integrated into a larger ontology, as it would not suffice to describe physical world objects alone. An ontology is generally designed for a specific domain of application, like transportation or home automation. For the latter domain, the TD ontology can e.g. be integrated with SAREF, as illustrated in several examples in this document.

An intelligent WoT client can be assigned the task of turning a light off in ontological terms, using SAREF. For instance, the task could be expressed as a post-condition on the saref:OnOffState of some saref:LightSwitch. Assuming a server exposes the TD of , the client has two possibilities to perform this task: it can either write the status property as off or it can invoke the action toggle and see if the resulting status is indeed equal to off.

Yet, in the TD example, the switch state is not directly exposed. Assuming the client has no prior knowledge of the meaning of status, it must infer possible operations from the semantic annotations available in the TD and its domain-specific ontology, that includes SAREF. The following ontological axioms can be formulated for SAREF, in the OWL Manchester syntax [[owl2-manchester-syntax]]:

They respectively state that a light switch must have an on/off state and that a toggle command must act on some on/off state. They may seem intuitive to humans but it is only possible for the client to know what to do from such axioms. If we assume that a saref:GetCommand always exposes the state of the Thing, the client can then automatically infer what form(s) to submit to change the switch state: a writeproperty on the saref:GetCommand or an invokeaction on the saref:ToggleCommand. Note that the result of the operation cannot be known for certain, as the TD does not expose its internal state. However, by selecting certain models of the physical world, either by statistical means or by further axiomatization, clients can still reach a certain level of autonomy with an ontological approach.

Recent Specification Changes

Changes from Third Public Working Draft

Changes from Second Public Working Draft

Changes from Second Public Working Draft are described in the Third Public Working Draft

Acknowledgements

The editors would like to thank Matthias Kovatsch, Michael Koster, Michael Lagally, Kazuyuki Ashimura, Ege Korkan, Daniel Peintner, Toru Kawaguchi, María Poveda, Dave Raggett, Kunihiko Toumura, Takeshi Yamada, Ben Francis, Manu Sporny, Klaus Hartke, Addison Phillips and Jose M. Cantera for providing contributions, guidance and expertise.

Also, many thanks to the W3C staff and all other active Participants of the W3C Web of Things Interest Group (WoT IG) and Working Group (WoT WG) for their support, technical input and suggestions that led to improvements to this document.