§ Identity Hub
Specification Status: Draft
Latest Draft: identity.foundation/identity-hub/spec
- Editors:
- Daniel Buchner (Block)
- Tobias Looker (Mattr)
- Contributors:
- Henry Tsai (Microsoft)
- XinAn Xu (Microsoft)
- Moe Jangda (Block)
- Participate:
- GitHub repo
- File a bug
- Commit history
§ Abstract
Most digital activities between people, organizations, devices, and other entities require the exchange of messages and data. For entities to exchange messages and data for credential, app, or service flows, they need an interface through which to store, discover, and fetch data related to the flows and experiences they are participating in. Identity Hubs are a data storage and message relay mechanism entities can use to locate public or private permissioned data related to a given Decentralized Identifier (DID). Identity Hubs are a mesh-like datastore construction that enable an entity to operate multiple instances that sync to the same state across one another, enabling the owning entity to secure, manage, and transact their data with others without reliance on location or provider-specific infrastructure, interfaces, or routing mechanisms.
§ Status of This Document
Identity Hub is a DRAFT specification under development within the Decentralized Identity Foundation (DIF). It incorporates requirements and learnings from related work of many active industry players into a shared specification that meets the collective needs of the community.
The specification will be updated to incorporate feedback, from DIF members and the wider community, with a reference implementation being developed within DIF that exercises the features and requirements defined here. We encourage reviewers to submit GitHub Issues as the means by which to communicate feedback and contributions.
§ Terminology
- Identity Hub
- A decentralized personal and application data storage and message relay node, as defined in the DIF Identity Hub specification.
- Hub Instance
- An instance of an Identity Hub running on a local device or at a remote location.
- Hub Operator
- Any entity, including individuals, who runs an Hub Instance on a device or infrastructure they control.
- Hub User
- An entity that stores DID-associated data and transmits messages via a given Hub Instance, which may be running on a device in their possession, or on the device or infrastructure of a Hub Operator.
- Decentralized Identifiers
- Unique ID URI string and PKI metadata document format for describing the cryptographic keys and other fundamental PKI values linked to a unique, user-controlled, self-sovereign identifier in a target system (e.g., blockchain, distributed ledger).
§ Topology
§ Protocol Stack
Identity Hubs are comprised of the following component layers, each of which is defined in this specification to ensure multiple Hub implementations can be used together and operate as a single logical unit for users.
DID Authentication |
Access & Authorization |
Interface Definitions |
Interface Processing |
Object Format |
Object Signing / Encryption |
File Structure |
IPFS |
Finalize the component stack list - are these correct? Are we missing any?
§ Service Endpoints
The following DID Document Service Endpoint entries MUST be present in the DID Document of a target DID for DID-relative URL resolution to properly locate the URI for addressing a DID owner’s Hub instances:
{
"id": "did:example:123",
"service": [{
"id":"#hub",
"type": "IdentityHub",
"serviceEndpoint": {
"instances": ["https://hub.example.com", "https://example.org/hub"]
}
}]
}
§ Addressing
A user’s logical Identity Hub (their collection of Hub Instances) can be addressed in many ways, but the mechanisms below MUST be supported by a compliant Identity Hub implementation:
§ DID-Relative URLs
The following DID URL constructions are used to address Hub Instances found to be associated with a given DID, as located via the DID resolution process.
§ Composition
The following process defines how a Identity Hub DID-Relative URL is composed:
- Let the base URI authority portion of the DID URL string be the target DID being addressed.
- Append a
service
parameter to the DID URL string with the valueIdentity Hub
. - Assemble an array of the Message Descriptor objects are desired for encoding in the DID-relative URL
- JSON stringify the array of Message Descriptor objects from Step 3, then Base64Url encode the stringified output.
- Append a
queries
parameter to the DID URL string with the value set to the JSON stringified, Base64Url encoded output of Step 4.
DID-relative URLs are composed of the following segments
did:example:123
+ ?service=IdentityHub
+ &queries=
+ toBase64Url( JSON.stringify( [{ DESCRIPTOR_1 }, { DESCRIPTOR_N }] ) )
did:example:123?service=IdentityHub&queries=W3sgTUVTU0FHRV8xIH0sIHsgTUVTU0FHRV9OIH1d...
§ Resolution
The following process defines how a DID-Relative URL addressing an Identity Hub is resolved:
- Resolve the DID in the authority portion of the URL in accordance with the W3C Decentralized Identifier Resolution process, which returns the DID Document for the resolved DID.
- As indicated by the presence of the
service
parameter, locate theIdentityHub
entry in the DID Document’s Service Endpoint entries. - Parse the
IdentityHub
Service Endpoint object and select the first URI present in theserviceEndpoint
objectsinstance
array. NOTE: implementers SHOULD select from the URIs in theinstance
array in index order. - If the URI located in step 3 is not a DID URI, proceed to step 5. If the URI from step 3 is a DID, resolve the DID and follow steps 2 and 3 to select the first URI in the DID’s
IdentityHub
Service Endpoint objectinstance
array that is not a DID URI. Do not iterate this loop more than once - if a non-DID URI cannot be located after one loop of recursive resolution, terminate resolution and produce an error. - Assuming a non-DID URI was located in steps 2-4, let the located URI be the base URI of the Hub request being constructed.
§ Request Construction
DID-Relative URL example for passing multiple messages:
For example purposes, the queries
parameter value below is neither JSON stringified nor Base64Url encoded, but should be when using Identity Hub URLs in practice (see the DID-relative URL Composition instructions above).
did:example:123?service=IdentityHub&queries=[{ "method": "CollectionsQuery", "schema": "https://schema.org/SocialMediaPosting" }]
did:example:123?service=IdentityHub&queries=W3sgTUVTU0FHRV8xIH0sIHsgTUVTU0FHRV9OIH1d...
Resolve DID to locate the Identity Hub URIs:
did:example:123
--> resolve to Identity Hub endpoint(s) --> https://hub.example.com/
Construct the Request Object:
- Create a JSON object for the request.
- The Request Object MUST include a
id
property, and its value MUST be an [RFC4122] UUID Version 4 string to identify the request. - The Request Object MUST include a
target
property, and its value MUST be the Decentralized Identifier base URI of the DID-relative URL. - The Request Object MUST include a
messages
property, and its value MUST be an array composed of Message objects that are generated by parsing the DID-relative URL’squeries
parameter value as a JSON array and performing the following steps for each entry:- Construct a Message object.
- Set the
descriptor
property of the Message object to the entry, ensuring it is a valid Message Descriptor object. - Augment the Message object with any signing and authorization values required, as described in the Messages section.
- Append the object to the Request Object’s
messages
array.
HTTP POST example:
POST https://hub.example.com/
BODY {
"requestId": "c5784162-84af-4aab-aff5-f1f8438dfc3d",
"target": "did:example:123",
"messages": [
{
"descriptor": {
"method": "CollectionsQuery",
"schema": "https://schema.org/SocialMediaPosting"
}
},
{...}
]
}
§ Request Objects
Request Objects are JSON object envelopes used to pass messages to Identity Hub instances.
{ // Request Object
"requestId": "c5784162-84af-4aab-aff5-f1f8438dfc3d",
"target": "did:example:123",
"messages": [ // Message Objects
{...},
{...},
{...}
]
}
Request Objects are composed as follows:
- The Request Object MUST include a
requestId
property, and its value MUST be an [RFC4122] UUID Version 4 string to identify the request. - The Request Object MUST include a
target
property, and its value MUST be the Decentralized Identifier base URI of the DID-relative URL. - The Request Object MUST include a
messages
property, and its value MUST be an array composed of Message objects.
§ Messages
All Identity Hub messaging is transacted via Messages JSON objects. These objects contain message execution parameters, authorization material, authorization signatures, and signing/encryption information. For various purposes Messages rely on IPFS CIDs and DAG APIs.
{ // Request Object
"requestId": "c5784162-84af-4aab-aff5-f1f8438dfc3d",
"target": "did:example:123",
"messages": [ // Message Objects
{
"data": BASE64_STRING,
"descriptor": {
"method": INTERFACE_METHOD_STRING,
"cid": DATA_CID_STRING,
"dataFormat": DATA_FORMAT_STRING,
},
"attestation": {
"protected": {
"alg": "ES256K",
"kid": "did:example:123#key-1"
},
"payload": CID(descriptor),
"signature": Sign(protected + payload)
},
"authorization": {
"protected": {
"alg": "ES256K",
"kid": "did:example:456#key-2",
"capabilities": "...",
},
"payload": CID(descriptor),
"signature": Sign(protected + payload)
}
},
{...}
]
}
Messages objects MUST be composed as follows:
In order to enable data replication features for a Hub Instance, all Messages MUST be committed to an IPFS DAG in a tree allocated to the DID of the owner after all subtrees are composed and committed. The top-level of Message objects MUST be committed as a DAG CBOR encoded object.
- Message objects MUST contain a
descriptor
property, and its value MUST be an object, as defined by the Message Descriptors section of this specification. - Message objects MAY contain a
data
property, and if present its value MUST be a JSON value of the Message’s data. - Message objects MAY contain an
attestation
property, and if present its value MUST be an object, as defined by the Signed Data section of this specification. - If a Message object requires signatory and/or permission-evaluated authorization, it must include an
authorization
property, and its value MUST be a [RFC7515] JSON Web Signature composed as follows:- The Message object must include a
payload
property, and its value must be the stringified Version 1 CID of the DAG CBOR encodeddescriptor
object, whose composition is defined in the Message Descriptor section of this specification. - The Message object MUST include a
protected
property, and its value must be an object composed of the following values:- The object MUST include an
alg
property, and its value MUST be the string representing the algorithm used to verify the signature (as defined by the [RFC7515] JSON Web Signature specification). - The object MUST include a
kid
property, and its value MUST be a DID URL string identifying the key to be used in verifying the signature. - If the message requires authorization to execute, the Message object MUST include a
capabilities
property with the required authorization material as its value.
- The object MUST include an
- The Message object MUST include a
signature
property, and its value must be a signature string produced by signing thepayload
value in Step 1, in accordance with the [RFC7515] JSON Web Signature specification.
- The Message object must include a
§ Message Descriptors
The Identity Hub data structure that resides in the descriptor
property of the Message is comprised of a common JSON structure that contains the following properties regardless of whether the message data is signed/encrypted:
{ // Request Object
"requestId": "c5784162-84af-4aab-aff5-f1f8438dfc3d",
"target": "did:example:123",
"messages": [ // Message Objects
{
"data": BASE64_STRING,
"descriptor": { // Message Descriptor
"method": INTERFACE_METHOD_STRING,
"cid": DATA_CID_STRING,
"dataFormat": DATA_FORMAT_STRING,
},
"attestation": {...},
"authorization": {...}
},
{...}
]
}
Message Descriptors are JSON objects that contains the parameters, signatory proof, and other details about the message and any data associated with it. All Message Descriptor objects share the following property options:
- The object MUST contain a
method
property, and its value MUST be a string that matches a Hub Interface method. - If the Message has data associated with it, passed directly via the
data
property of the Message object or through a channel external to the message object, thedescriptor
object MUST contain acid
property, and its value MUST be the stringified Version 1 CID of the DAG PB encoded data. - If the Message has data associated with it, passed directly via the
data
property of the Message object or through a channel external to the message object, thedescriptor
object MUST contain adataFormat
property, and its value MUST be a string that corresponds with a registered IANA Media Type data format (the most common being plain JSON, which is indicated by setting the value of thedataFormat
property toapplication/json
), or one of the following format strings pending registration:application/vc+jwt
- the data is a JSON Web Token (JWT) [RFC7519] formatted variant of a W3C Verifiable Credential.application/vc+ldp
- the data is a JSON-LD formatted W3C Verifiable Credential.
Individual Interface methods may describe additional properties that the descriptor
object MUST or MAY contain, which are detailed in the Interfaces section of the specification.
§ Raw Data
If there is no need or desire to sign or encrypt the content of a message (i.e. public repudiable data), the message descriptor
object is the only property required in a Message (with any method-specific properties required). An optional data
property may be passed at the Message level that contains the data associated with the message (when data is desired or required to be present for a given method invocation).
{ // Message
"data": BASE64_STRING,
"descriptor": {
"objectId": "b6464162-84af-4aab-aff5-f1f8438dfc1e",
"cid": CID(data),
"dateCreated": 123456789,
"method": "CollectionsWrite",
"schema": "https://schema.org/SocialMediaPosting",
"dataFormat": "application/json"
}
}
§ Signed Data
If the object is to be attested by a signer (e.g the Hub owner via signature with their DID key), the object MUST contain the following additional properties to produce a [RFC7515] Flattened JSON Web Signature (JWS) object:
{ // Message
"data": {...},
"descriptor": {
"objectId": "b6464162-84af-4aab-aff5-f1f8438dfc1e",
"cid": CID(data),
"dateCreated": 123456789,
"method": "CollectionsWrite",
"schema": "https://schema.org/SocialMediaPosting",
"dataFormat": "application/json"
},
"attestation": {
"protected": {
"alg": "ES256K",
"kid": "did:example:123#key-1"
},
"payload": CID(descriptor),
"signature": Sign(protected + payload)
},
...
}
The message generating party MUST construct the signed message object as follows:
- If the Message includes associated data, passed directly via the Message object’s
data
property or through a channel external to the Message, add acid
property to thedescriptor
object and set its value as the stringified Version 1 CID of the DAG PB encoded data. - The Message object MUST contain an
attestation
property, and its value MUST be a Flattened object representation of a [RFC7515] JSON Web Signature composed as follows: - The Message object must include a
payload
property, and its value must be the stringified Version 1 CID of the DAG CBOR encodeddescriptor
object, whose composition is defined in the Message Descriptor section of this specification. - The Message object MUST include a
protected
property, and its value must be an object composed of the following values:- The object MUST include an
alg
property, and its value MUST be the string representing the algorithm used to verify the signature (as defined by the [RFC7515] JSON Web Signature specification). - The object MUST include a
kid
property, and its value MUST be a DID URL string identifying the key to be used in verifying the signature.
- The object MUST include an
- The Message object MUST include a
signature
property, and its value must be a signature string produced by signing theprotected
andpayload
values, in accordance with the [RFC7515] JSON Web Signature specification.
§ Encrypted Data
If the object is to be encrypted (e.g the Hub owner encrypting their data to keep it private), the descriptor
object MUST be constructed as follows:
{ // Message
"data": {
"protected": ...,
"recipients": ...,
"ciphertext": ...,
"iv": ...,
"tag": ...
},
"descriptor": {
"objectId": "b6464162-84af-4aab-aff5-f1f8438dfc1e",
"cid": CID(data),
"dateCreated": 123456789,
"method": "CollectionsWrite",
"schema": "https://schema.org/SocialMediaPosting",
"dataFormat": "application/json",
"encryption": "jwe"
},
...
}
The message generating party MUST construct an encrypted message as follows:
- The
encryption
property of thedescriptor
object MUST be set to the string valueJWE
. - Generate an [RFC7516] JSON Web Encryption (JWE) object for the data that is to be represented in the message.
- Generate a Version 1 CID from the JWE of the data produced in Step 1, and set the
cid
property of thedescriptor
object as the stringified representation of the CID.
§ Signed & Encrypted Data
If the object is to be both attributed to a signer and encrypted encrypted, it MUST be structured as follows:
{ // Message
"data": {
"protected": ...,
"recipients": ...,
"ciphertext": ...,
"iv": ...,
"tag": ...
},
"descriptor": {
"objectId": "b6464162-84af-4aab-aff5-f1f8438dfc1e",
"cid": CID(data),
"dateCreated": 123456789,
"method": "CollectionsWrite",
"schema": "https://schema.org/SocialMediaPosting",
"dataFormat": "application/json",
"encryption": "jwe"
},
"attestation": {
"protected": {
"alg": "ES256K",
"kid": "did:example:123#key-1"
},
"payload": CID(descriptor),
"signature": Sign(protected + payload)
}
}
The message generating party MUST construct the signed and encrypted message as follows:
- Follow the instructions described in the Encrypted Data section to add the required properties to the
descriptor
and produce a [RFC7516] JSON Web Encryption (JWE) object from the associated data. - Follow the instructions described in the Signed Data section to add an
attestation
property with a Flattened object representation of a [RFC7515] JSON Web Signature as its value.
§ Response Objects
Responses from Interface method invocations are JSON objects that MUST be constructed as follows:
- The object MUST include an
requestId
property, and its value MUST be the [RFC4122] UUID Version 4 string from therequestId
property of the Request Object it is in response to. - The object MAY have a
status
property if an error is produced from a general request-related issue, and if present its value MUST be an object composed of the following properties:- The status object MUST have a
code
property, and its value MUST be an integer set to the HTTP Status Code appropriate for the status of the response. - The status object MAY have a
message
property, and if present its value MUST be a string that describes a terse summary of the status. It is recommended that the implementer set the message text to the standard title of the HTTP Status Code, when a title/message has already been defined for that code.
- The status object MUST have a
- The object MAY have a
replies
property, and if present its value MUST be an array of Message Result Objects, which are constructed as follows:- The object MUST have a
messageId
property, and its value MUST be the stringified Version 1 CID of the associated message in the Request Object from which it was received. - The object MUST have a
status
property, and its value MUST be an object composed of the following properties:- The status object MUST have a
code
property, and its value MUST be an integer set to the HTTP Status Code appropriate for the status of the response. - The status object MAY have a
message
property, and if present its value MUST be a string that describes a terse summary of the status. It is recommended that the implementer set the message text to the standard title of the HTTP Status Code, when a title/message has already been defined for that code.
- The status object MUST have a
- The object MAY have a
entries
property if the message request was successful. If present, its value MUST be the resulting message entries returned from the invocation of the corresponding message.
- The object MUST have a
§ Request-Level Status Coding
If any of the scenarios described in this section are encountered during general message processing, the implementation must include a request-level status
property, and its value must be an object as defined below.
Target DID not found
If the DID targeted by a request object is not found within the Hub instance, the implementation MUST produce a request-level status
with the code 404
, and SHOULD use Target DID not found within the Identity Hub instance
as the status text
.
Response Example:
{
"requestId": "c5784162-84af-4aab-aff5-f1f8438dfc3d",
"status": {
"code": 404,
"text": "Target DID not found within the Identity Hub instance"
}
}
General request-level processing errors
If a general request-level error in processing occurs that is not covered by one of the specific status cases above and prevent the implementation from correctly evaluating the request, the implementation MUST produce a request-level status
with the code 500
, and SHOULD use The request cannot not be processed
as the status text
.
Response Example:
{
"requestId": "c5784162-84af-4aab-aff5-f1f8438dfc3d",
"status": {
"code": 500,
"text": "The request could not be processed correctly"
}
}
§ Message-Level Status Coding
If any of the scenarios described in this section are encountered during the processing of an individual message, the implementation must include a message-level status
property, and its value must be an object as defined below.
Message succeeded for query/read-type interface that expects results
If a message is processed correctly and a set of result entries
is expected, the implementation MUST include a message-level status
object with its code
property set to 200
, and SHOULD use The message was successfully processed
as the status text
.
If no results are found, the status
remains 200
, and the implementation MUST return an empty entries
array.
Request Example:
{ // Request Object
"requestId": "c5784162-84af-4aab-aff5-f1f8438dfc3d",
"target": "did:example:123",
"messages": [ // Message Objects
{
"descriptor": {
"method": "CollectionsQuery",
"schema": "https://schema.org/SocialMediaPosting"
}
},
...
]
}
Response Example:
{
"requestId": "c5784162-84af-4aab-aff5-f1f8438dfc3d",
"replies": [
{
"messageId": "bm4vvfvsdfovsj...",
"status": { "code": 200, "text": "OK" },
"entries": [...]
}
]
}
Improperly constructed message
If a message is malformed or constructed with invalid properties/values, the implementation MUST include a message-level status
object with its code
property set to 400
, and SHOULD use The message was malformed or improperly constructed
as the status text
.
Request Example:
{ // Request Object
"requestId": "c5784162-84af-4aab-aff5-f1f8438dfc3d",
"target": "did:example:123",
"messages": [ // Message Objects
{
"descriptorization": {
"methodical": "CollectionsQuery",
"schemata": "https://schema.org/SocialMediaPosting"
}
}
]
}
Response Example:
{
"requestId": "c5784162-84af-4aab-aff5-f1f8438dfc3d",
"replies": [
{
"messageId": "bm4vvfvsdfovsj...",
"status": { "code": 400, "text": "The message was malformed or improperly constructed" }
}
]
}
Message failed authorization requirements
If a message fails to meet authorization requirements during processing, the implementation MUST include a message-level status
object with its code
property set to 401
, and SHOULD use The message failed authorization requirements
as the status text
.
Request Example:
{ // Request Object
"requestId": "c5784162-84af-4aab-aff5-f1f8438dfc3d",
"target": "did:example:123",
"messages": [ // Message Objects
{ // Message
"data": {...},
"descriptor": {
"objectId": "b6464162-84af-4aab-aff5-f1f8438dfc1e",
"cid": CID(data),
"dateCreated": 123456789,
"method": "CollectionsWrite",
"schema": "https://schema.org/SocialMediaPosting",
"dataFormat": "application/json"
}
^ `authorization` PROPERTY MISSING
}
]
}
Response Example:
{
"requestId": "c5784162-84af-4aab-aff5-f1f8438dfc3d",
"replies": [
{
"messageId": "bm2343w4vw45gh...",
"status": { "code": 401, "text": "OK" }
}
]
}
Interface is not implemented
If a message attempts to invoke an interface method
that is not the implementation does not support, the implementation MUST include a message-level status
object with its code
property set to 501
, and SHOULD use The interface method is not implemented
as the status text
.
Request Example:
{ // Request Object
"requestId": "c5784162-84af-4aab-aff5-f1f8438dfc3d",
"target": "did:example:123",
"messages": [ // Message Objects
{ // Message
"data": {...},
"descriptor": {
"objectId": "b6464162-84af-4aab-aff5-f1f8438dfc1e",
"cid": CID(data),
"method": "ThreadsCreate",
"schema": "https://schema.org/LikeAction",
"dataFormat": "application/json"
}
}
]
}
Response Example:
{
"requestId": "c5784162-84af-4aab-aff5-f1f8438dfc3d",
"replies": [
{
"messageId": "bm2343w4vw45gh...",
"status": { "code": 501, "text": "The interface method is not implemented" }
}
]
}
§ Access & Permissions
Agree on an access/permission scheme (e.g. Object Capabilities) for Hub interactions that require it.
§ Sync & Replication
IPFS can provide this to some extent, but do we need anything in addition to what native IPFS provides?
§ Interfaces
§ Feature Detection
The Identity Hub specification defines well-recognized Hub configurations to maximize interoperability (see Hub Configurations), but implementers may wish to support a custom subset of the Interfaces and features. The Feature Detection interface is the means by which a Hub expresses support for the Interfaces and features it implements.
§ Data Model
A compliant Identity Hub MUST produce a Feature Detection object defined as follows:
{
"type": "FeatureDetection",
"interfaces": { ... }
}
§ Properties & Values
The following properties and values are defined for the Feature Detection object:
- The object MUST include an
interfaces
property, and its value MUST be an object composed as follows:- The object MAY contain a
collections
property. If the property is not present, it indicates the Hub implementation does not support any methods of the interface. If the property is present, its value MUST be an object that MAY include any of the following properties, wherein a booleantrue
value indicates support for the interface method, while a booleanfalse
value or omission of the property indicates the interface method is not supported:CollectionsQuery
CollectionsWrite
CollectionsCommit
CollectionsDelete
- The object MAY contain a
actions
property. If the property is not present, it indicates the Hub implementation does not support any methods of the interface. If the property is present, its value MUST be an object that MAY include any of the following properties, wherein a booleantrue
value indicates support for the interface method, while a booleanfalse
value or omission of the property indicates the interface method is not supported:ThreadsQuery
ThreadsCreate
ThreadsReply
ThreadsClose
ThreadsDelete
- The object MAY contain a
permissions
property. If the property is not present, it indicates the Hub implementation does not support any methods of the interface. If the property is present, its value MUST be an object that MAY include any of the following properties, wherein a booleantrue
value indicates support for the interface method, while a booleanfalse
value or omission of the property indicates the interface method is not supported:PermissionsRequest
PermissionsGrant
PermissionsRevoke
- The object MAY contain a
- The object MAY contain a
messaging
property, and its value MAY be an object composed of the following:- The object MAY contain a
batching
property, and if present its value MUST be a boolean indicating whether the Hub Instance handles multiple messages in a single request. The absence of this property shall indicate that the Hub Instance does support multiple messages in a single request, thus if an implementer does not support multiple messages in a request, they MUST include this property and explicitly set its value tofalse
.
- The object MAY contain a
§ Read
All compliant Hubs MUST respond with a valid Feature Detection object when receiving the following request object:
{ // Message
"descriptor": { // Message Descriptor
"method": "FeatureDetectionRead"
}
}
§ Collections
To maximize decentralized app and service interoperability, the Collections interface of Identity Hubs provides a mechanism to store data relative to shared schemas. By storing data in accordance with a given schema, which may be well-known in a given vertical or industry, apps and services can leverage the same datasets across one another, enabling a cohesive, cross-platform, cross-device, cross-app experience for users.
§ Query
CollectionsQuery
messages are JSON objects that include general Message Descriptor properties and the following additional properties, which must be composed as follows:
- The message object MUST contain a
descriptor
property, and its value MUST be a JSON object composed as follows:- The object MUST contain a
method
property, and its value MUST be the stringCollectionsQuery
. - The object MAY contain an
objectId
property, and if present its value MUST be an [RFC4122] UUID Version 4 string intended to identify a logical object the Hub Instance contains. - The object MAY contain a
schema
property, and if present its value Must be a URI string that indicates the schema of the associated data. - The object MAY contain a
dataFormat
property, and its value MUST be a string that indicates the format of the data in accordance with its MIME type designation. The most common format is JSON, which is indicated by setting the value of thedataFormat
property toapplication/json
. - The object MAY contain a
dateSort
field, and if present its value MUST be one of the following strings:createdAscending
: return results in order from the earliestdateCreated
value to the latest.createdDescending
: return results in order from the latestdateCreated
value to the earliest.publishedAscending
: return results in order from the earliestdatePublished
value to the latest.publishedDescending
: return results in order from the latestdatePublished
value to the earliest.
- The object MUST contain a
Get a single object by its ID reference:
{ // Message
"descriptor": {
"method": "CollectionsQuery",
"objectId": "b6464162-84af-4aab-aff5-f1f8438dfc1e"
}
}
Get a objects of a given schema type:
{ // Message
"descriptor": {
"method": "CollectionsQuery",
"schema": "https://schema.org/MusicPlaylist"
}
}
Get all objects of a given schema type:
{ // Message
"descriptor": {
"method": "CollectionsQuery",
"dataFormat": "image/gif"
}
}
§ Write
CollectionsWrite
messages are JSON objects that include general Message Descriptor properties and the following additional properties, which must be composed as follows:
- The message object MUST contain a
descriptor
property, and its value MUST be a JSON object composed as follows:- The object MUST contain a
method
property, and its value MUST be the stringCollectionsWrite
. - The object MUST contain an
objectId
property, and its value MUST be an [RFC4122] UUID Version 4 string. - The object MAY contain a
schema
property, and if present its value Must be a URI string that indicates the schema of the associated data. - The object MUST contain a
dateCreated
property, and its value MUST be an Unix epoch timestamp that MUST be set and interpreted as the time the logical entry was created by the DID owner or another permitted party. - The object MAY contain a
datePublished
property, and its value MUST be an Unix epoch timestamp that MUST be set and interpreted as the time the logical entry was published by the DID owner or another permitted party.
- The object MUST contain a
{ // Message
"data": {...},
"descriptor": { // Message Descriptor
"objectId": "b6464162-84af-4aab-aff5-f1f8438dfc1e",
"cid": CID(data),
"dateCreated": 123456789,
"method": "CollectionsWrite",
"schema": "https://schema.org/SocialMediaPosting",
"dataFormat": DATA_FORMAT
}
}
§ Processing Instructions
When processing a CollectionsWrite
message, Hub instances MUST perform the following additional steps:
- If the incoming message has a higher
dateCreated
value than all of the other messages for the logical entry known to the Hub Instance, the message MUST be designated as the latest state of the logical entry and fully replace all previous messages for the entry. - If the incoming message has a lower
dateCreated
value than the message that represents the current state of the logical entry, the message MUST NOT be applied to the logical entry and its data MAY be discarded. - If the incoming message has a
dateCreated
value equal to the message that represents the current state of the logical entry, the incoming message’s IPFS CID and the IPFS CID of the message that represents the current state must be lexicographically compared and handled as follows:- If the incoming message has a higher lexicographic value than the message that represents the current state, perform the actions described in Step 1 of this instruction set.
- If the incoming message has a lower lexicographic value than the message that represents the current state, perform the actions described in Step 2 of this instruction set.
§ Commit
{ // Message
"data": {...},
"descriptor": { // Message Descriptor
"objectId": "b6464162-84af-4aab-aff5-f1f8438dfc1e",
"cid": CID(data),
"dateCreated": 123456789,
"method": "CollectionsCommit",
"schema": "https://schema.org/SocialMediaPosting",
"strategy": "merge-patch",
"dataFormat": DATA_FORMAT
}
}
CollectionsCommit
messages are JSON objects that include general Message Descriptor properties and the following additional properties, which must be composed as follows:
- The message object MUST contain a
descriptor
property, and its value MUST be a JSON object composed as follows:- The object MUST contain a
method
property, and its value MUST be the stringCollectionsCommit
. - The object MUST contain an
objectId
property, and its value MUST be an [RFC4122] UUID Version 4 string. - The object MAY contain a
schema
property, and if present its value Must be a URI string that indicates the schema of the associated data. - The object MUST contain a
dateCreated
property, and its value MUST be an Unix epoch timestamp that MUST be set and interpreted as the time the logical entry was created by the DID owner or another permitted party. - The object MAY contain a
datePublished
property, and its value MUST be an Unix epoch timestamp that MUST be set and interpreted as the time the logical entry was published by the DID owner or another permitted party.
- The object MUST contain a
§ Delete
{ // Message
"descriptor": { // Message Descriptor
"method": "CollectionsDelete",
"objectId": "Qm65765jrn7be64v5q35v6we675br68jr"
}
}
CollectionsDelete
messages are JSON objects that include general Message Descriptor properties and the following additional properties, which must be composed as follows:
- The message object MUST contain a
descriptor
property, and its value MUST be a JSON object composed as follows:- The object MUST contain a
method
property, and its value MUST be the stringCollectionsDelete
. - The object MUST contain an
objectId
property, and its value MUST be an [RFC4122] UUID Version 4 string of the object to be deleted.
- The object MUST contain a
§ Threads
Threads are a linked series of topically associated messages that are intended to result in activities performed by entities participating in the message thread.
§ Query
{ // Message
"descriptor": { // Message Descriptor
"method": "ThreadsQuery",
"schema": "https://schema.org/LikeAction"
}
}
§ Create
{ // Message
"data": {...},
"descriptor": { // Message Descriptor
"objectId": "b6464162-84af-4aab-aff5-f1f8438dfc1e",
"method": "ThreadsCreate",
"schema": "https://schema.org/LikeAction"
}
}
ThreadsCreate
messages are JSON objects that include general Message Descriptor properties and the following additional properties, which must be composed as follows:
- The message object MUST contain a
descriptor
property, and its value MUST be a JSON object composed as follows:- The object MUST contain a
method
property, and its value MUST be the stringThreadsCreate
. - The object MUST contain an
objectId
property, and its value MUST be an [RFC4122] UUID Version 4 string for the Thread being created. - The object MUST contain a
schema
property, and its value Must be a URI string that indicates the schema of the associated data.
- The object MUST contain a
§ Reply
{ // Message
"data": {...},
"descriptor": { // Message Descriptor
"objectId": "65efm7eg-84af-4aab-aff5-f1f8438dfc1e",
"method": "ThreadsReply",
"schema": "https://fintech.org/BidAcceptance",
"root": "b6464162-84af-7gab-aff5-j8f8438dfc1e",
"parent": "r7874162-84af-4aab-aff5-f1f8438dfc1e"
}
}
ThreadsReply
messages are JSON objects that include general Message Descriptor properties and the following additional properties, which must be composed as follows:
- The message object MUST contain a
descriptor
property, and its value MUST be a JSON object composed as follows:- The object MUST contain a
method
property, and its value MUST be the stringThreadsReply
. - The object MUST contain an
objectId
property, and its value MUST be an [RFC4122] UUID Version 4 string representing the reply object. - The object MUST contain a
schema
property, and its value Must be a URI string that indicates the schema of the associated data. - The object MUST contain a
root
property, and its value MUST be an [RFC4122] UUID Version 4 string of the initiating Thread message. - The object MUST contain a
parent
property, and its value MUST be an [RFC4122] UUID Version 4 string of the message in the Thread being replied to.
- The object MUST contain a
§ Close
{ // Message
"descriptor": { // Message Descriptor
"method": "ThreadsClose",
"root": "b6464162-84af-4aab-aff5-f1f8438dfc1e",
}
}
ThreadsClose
messages are JSON objects that include general Message Descriptor properties and the following additional properties, which must be composed as follows:
- The message object MUST contain a
descriptor
property, and its value MUST be a JSON object composed as follows:- The object MUST contain a
method
property, and its value MUST be the stringThreadsClose
. - The object MUST contain a
root
property, and its value MUST be an [RFC4122] UUID Version 4 string of the initiating Thread message.
- The object MUST contain a
§ Delete
{ // Message
"descriptor": { // Message Descriptor
"method": "ThreadsDelete",
"root": "b6464162-84af-4aab-aff5-f1f8438dfc1e",
}
}
ThreadsDelete
messages are JSON objects that include general Message Descriptor properties and the following additional properties, which must be composed as follows:
- The message object MUST contain a
descriptor
property, and its value MUST be a JSON object composed as follows:- The object MUST contain a
method
property, and its value MUST be the stringThreadsDelete
. - The object MUST contain a
root
property, and its value MUST be an [RFC4122] UUID Version 4 string of the initiating Thread message.
- The object MUST contain a
§ Permissions
The Permissions interface provides a mechanism for external entities to request access to various data and functionality provided by an Identity Hub. Permissions employ a capabilities-based architecture that allows for DID-based authorization and delegation of authorized capabilities to others, if allowed by the Identity Hub owner.
§ Request
PermissionsRequest
messages are JSON objects that include general Message Descriptor properties and the following additional properties, which must be composed as follows:
- The message object MUST contain a
descriptor
property, and its value MUST be a JSON object composed as follows:- The object MUST contain a
method
property, and its value MUST be the stringPermissionsRequest
. - The object MUST contain an
objectId
property, and its value MUST be an [RFC4122] UUID Version 4 string representing the reply object. - The object MUST contain a
requester
property, and its value MUST be the DID URI of the party requesting the permission. - The object MAY contain a
description
property, and its value MUST be a string that the requesting party uses to communicate what the permission is being used for. - The object MUST contain a
ability
property, and its value Must be an object of the following properties:- The object MUST contain a
can
property, and its value Must be an object of the following properties:- The object MUST contain a
method
property, and its value MUST be the interface method the requesting party wants to invoke. - The object MAY contain a
schema
property, and its value Must be a URI string that indicates the schema of the associated data.
- The object MUST contain a
- The object MAY contain a
conditions
property, and its value Must be an object of the following properties:- The object MAY contain an
attestation
property, and if present its value Must be an integer representing the signing conditions detailed below. If the property is not present it MUST be evaluated as if it were set to a value of1
.0
- the object WILL NOT be signed.1
- the object MAY be signed using a key linked to the DID of the Hub owner or authoring party (whichever is relevant to the application-level use case), and the signature MUST be in the [RFC7515] JSON Web Signature (JWS) format.2
- the object MUST be signed using a key linked to the DID of the Hub owner or authoring party (whichever is relevant to the application-level use case), and the signature MUST be in the [RFC7515] JSON Web Signature (JWS) format.
- The object MAY contain an
encryption
property, and if present its value Must be an integer representing the encryption conditions detailed below. If the property is not present it MUST be evaluated as if it were set to a value of1
. - The object MAY contain a
delegation
property, and its value Must be a boolean, whereintrue
indicates the requesting party wants the ability to delegate the capability to other entities, andfalse
or the omission of the property indicates no request is being made for delegation ability. - The object MAY contain a
sharedAccess
property, and its value Must be a boolean, whereintrue
indicates the requesting party wants the ability to use the permission against any object or data that aligns with the capability’s definition, regardless of which entity created the object or data. A value offalse
or omission of the property MUST be evaluated as false, and indicates the requesting party only needs the ability to invoke the permission against objects or data it creates.
- The object MAY contain an
- The object MUST contain a
- The object MUST contain a
- The message object MUST contain an
attestation
property, which MUST be a JSON object as defined by the Signed Data section of this specification, with the requirement that thekid
andsignature
MUST match the DID of the requesting party.
{
"descriptor": {
"method": "PermissionsRequest",
"objectId": "b6464162-84af-4aab-aff5-f1f8438dfc1e",
"requester": "did:example:bob",
"description": "Help you create and edit your music playlists",
"ability": {
"can": {
"method": "CollectionsWrite",
"schema": "https://schema.org/MusicPlaylist"
},
"conditions": {
"encryption": 1,
"attestation": 0,
"delegation": true,
"sharedAccess": true
}
}
},
"attestation": {
"protected": {
"alg": "ES256K",
"kid": "did:example:bob#key-1"
},
"payload": CID(descriptor),
"signature": Sign(protected + payload)
}
}
§ Grant
PermissionsGrant
messages are JSON objects that are generated either in response to evaluation of a PermissionsRequest
message or optimistically by a user agent. PermissionsGrant
messages include general Message Descriptor properties and the following additional properties, which must be composed as follows:
- The message object MUST contain a
descriptor
property, and its value MUST be a JSON object composed as follows:- The object MUST contain a
method
property, and its value MUST be the stringPermissionsGrant
. - The object MUST contain an
objectId
property, and its value MUST be an [RFC4122] UUID Version 4 string representing the reply object. - If the granted permission is in response to a
PermissionRequest
, the object MUST contain agrantedFor
property, and its value MUST be the [RFC4122] UUID Version 4 string of thePermissionRequest
object the permission is being granted in relation to. - The object MUST contain a
cid
property, and its value MUST be the stringified Version 1 CID of the DAG PB encoded JSON Web Token for the granted permission, as defined in the Capability Objects section below. - The object MUST contain a
dataFormat
property, and its value MUST be the stringapplication/json
, as all granted permissions are represented as JSON Web Tokens generally adherent to the UCAN capabilities construction.
- The object MUST contain a
- The message object MUST contain an
attestation
property, which MUST be a JSON object as defined by the Signed Data section of this specification, with the requirement that thekid
andsignature
MUST match the DID of the requesting party. - The message will contain a
data
payload, which is a JSON Web Token representation of the granted permission as defined in the Capability Objects section below.
{
"descriptor": {
"method": "PermissionsGrant",
"objectId": "f45wve-5b56v5w-5657b4e-56gqf35v",
"grantedFor": "b6464162-84af-4aab-aff5-f1f8438dfc1e",
"cid": "bf34455ev6v365eb7r8n9mnbesv5e6be7rn879m",
"dataFormat": "application/json"
},
"data": {
"payload": {
"iss": "did:example:alice",
"aud": "did:example:bob",
"exp": 1575606941,
"att": [{
"can": {
"method": "CollectionsWrite",
"schema": "https://schema.org/MusicPlaylist",
},
"conditions": {
"encryption": 1,
"attestation": 0,
"sharedAccess": true
}
}]
},
"signature": "fw547v63bo5687wvwbcqp349vwo876uc3q..."
}
}
§ Grantor PermissionsGrant
Storage
After generating a PermissionsGrant
the user agent (e.g. wallet app with access to authoritative keys for a given DID) MUST commit the granted permission object to the Hub of the DID the grant was issued from. This will ensure that the permission is present when addressed in subsequent interface method invocations.
§ Grantee PermissionsGrant
Delivery
Once a user agent (e.g. wallet app with access to authoritative keys for a given DID) generates a PermissionsGrant
for an entity to permit access to data and Hub functionality, it is the responsibility of the user agent that generated the PermissionsGrant
to deliver it to the entity that is the subject. To do this, the user agent MUST generate a Request that includes the PermissionsGrant
and send it to the Hub of the subject it has been granted to, in accordance with the Resolution and Request Construction sections of this specification.
§ Revoke
Revocation of a permission is the act of closing off any additional or invalid invocations of that permission. The Revoke interface method enables revocation of a permission via direct reference to the permission’s objectId
. When executing a valid PermissionsRevoke
invocation an implementation MUST use the inclusionProof
value to ensure that only the entries in the Hub indicated by the proof are allowed to be retained in relation to the permission. The process of permission revocation effectively encapsulates all valid invocations of the permission and provides a deterministic means for ensuring no invalid invocations are allowed or persisted across any Hub instance.
{ // Message
"descriptor": { // Message Descriptor
"method": "PermissionsRevoke",
"objectId": "Qm65765jrn7be64v5q35v6we675br68jr",
"inclusionProof": "..."
}
}
§ Capability Objects
Capabilities granted via the Permissions interface are [RFC7516] JSON Web Token (JWT) used to secure and attenuate the scope permitted activities. The JWTs used in this specification to represent capabilities generally adhere to the JWT variant defined in the UCAN capability-based authorization construction.
Capability objects are JSON Web Tokens that must be composed as follows:
- The message object MUST contain a
header
property, and its value MUST be an object composed as follows:- The object MUST contain an
alg
property, and its value MUST be a string that notes the algorithm used in signing the JWT. - The object MUST contain an
typ
property, and its value MUST be the stringJWT
, indicating the object is a [RFC7516] JSON Web Token.
- The object MUST contain an
- The message object MUST contain a
payload
property, and its value MUST be an object composed as follows:- The object MUST contain an
iss
property, and its value MUST be the DID URI string of the party issuing the capability. - The object MUST contain an
aud
property, and its value MUST be the DID URI string of requesting party. - The object MAY contain an
nbf
property, and its value MUST be a number representing the UTC Unix Timestamp of when the capability is first active. - The object MUST contain an
exp
property, and its value MUST be a number representing the UTC Unix Timestamp of when the capability expires. - The object MAY contain an
nnc
property, and its value MUST be a unique string that SHOULD be cryptographically random. - The object MUST contain an
att
property, and its value MUST be an array with exactly one entry that is a JSON object composed as follows, with values selected at the discretion of the granting Hub owner:- The object MUST contain a
can
property, and its value Must be an object of the following properties:- The object MUST contain a
method
property, and its value MUST be the interface method the granting Hub owner will allow the requesting party wants to invoke. - The object MAY contain a
schema
property, and its value Must be a URI string that indicates the schema of the associated data the Hub owner is allowing the grantee to access.
- The object MUST contain a
- The object MAY contain a
conditions
property, and its value Must be an object of the following properties:- The object MAY contain an
attestation
property, and if present its value Must be an integer representing the signing conditions detailed below. If the property is not present it MUST be evaluated as if it were set to a value of1
.0
- the object MUST NOT be signed.1
- the object MAY be signed using a key linked to the DID of the Hub owner or authoring party (whichever is relevant to the application-level use case), and the signature MUST be in the [RFC7515] JSON Web Signature (JWS) format.2
- the object MUST be signed using a key linked to the DID of the Hub owner or authoring party (whichever is relevant to the application-level use case), and the signature MUST be in the [RFC7515] JSON Web Signature (JWS) format.
- The object MAY contain an
encryption
property, and if present its value Must be an integer representing the encryption conditions detailed below. If the property is not present it MUST be evaluated as if it were set to a value of1
. - The object MAY contain a
delegation
property, and its value Must be a boolean, whereintrue
indicates the ability to delegate the capability to other entities has been granted, andfalse
or the omission of the property indicates the ability to delegate has not been granted. - The object MAY contain a
sharedAccess
property, and its value Must be a boolean, whereintrue
indicates the issuing party is allowing the grantee the ability to access any object or data that aligns with the capability’s definition, regardless of which entity created the object or data. A value offalse
or omission of the property MUST be evaluated as false, and indicates the grantee MUST NOT be allowed to invoke the capability against any object or data they are not the author of.
- The object MAY contain an
- The object MUST contain a
- The object MAY contain an
prf
property, and its value MUST be an array of Capability Objects in stringified form that provide proof of delegation for the capability being invoked. - The object MAY contain an
fct
property, and if present its value MUST be an array of facts or assertions required for processing the capability that can be verified by the Hub evaluating invocation of the capability.
- The object MUST contain an
{
"payload": {
"iss": "did:example:alice",
"aud": "did:example:bob",
"nbf": 1529496683,
"exp": 1575606941,
"nnc": "f5we67hrn8676bwv5cq24WF5WVE6B76F",
"att": [{
"can": {
"method": "CollectionsWrite",
"schema": "https://schema.org/MusicPlaylist",
},
"conditions": {
"encryption": 1,
"attestation": 0,
"sharedAccess": true
}
}],
"prf": ["eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsInVhdiI6IjAuMS4wIn0.eyJhdWQiOiJkaWQ6a2V5OnpTdEVacHpTTXRUdDlrMnZzemd2Q3dGNGZMU..."]
},
"signature": "fw547v63bo5687wvwbcqp349vwo876uc3q..."
}
§ Commit Strategies
Some interface methods may be bound to, or allow for choice between, the data modification algorithms detailed below. Interfaces methods that are bound to one or more of these strategies will indicate it within their interface definitions under the Interfaces section.
§ Last-Write Wins
Last-Write Wins is the most basic Commit Strategy that allows for the traditional experience of posting an update to a file that fully replaces the data.
§ JSON Merge Patch
Detail JSON Merge Patch as a commit strategy option.
§ Hub Configurations
While it is strongly encouraged to implement the full set of Identity Hub features and Interfaces, not all devices and providers may be capable of doing so. To allow for maximum reach and proliferation in the ecosystem, the following are well-recognized configurations of Identity Hub feature sets that tend to serve different purposes.
§ Open Data Publication
This Hub configuration is ideal for implementers who seek to expose intentionally public data via the Identity Hub semantic data discovery Interfaces. This implementation is lightweight does not require the implementer to support any of the authentication, permissioning, or ingest mechanisms that other features and Interfaces do.
{
"type": "FeatureDetection",
"interfaces": {
"collections": {
"CollectionsQuery": true
}
}
}
§ Normative References
- RFC4122
- A Universally Unique IDentifier (UUID) URN Namespace. P. Leach; M. Mealling; R. Salz; 2005-07. Status: Proposed Standard.
- RFC7515
- JSON Web Signature (JWS). M. Jones; J. Bradley; N. Sakimura; 2015-05. Status: Proposed Standard.
- RFC7516
- JSON Web Encryption (JWE). M. Jones; J. Hildebrand; 2015-05. Status: Proposed Standard.
- RFC7519
- JSON Web Token (JWT). M. Jones; J. Bradley; N. Sakimura; 2015-05. Status: Proposed Standard.