§ DID Registration
Specification Status: Draft
Latest Draft: identity.foundation/did-registration
- Editors:
- Markus Sabadello (Danube Tech)
- Others?
- Authors:
- Markus Sabadello (Danube Tech)
- Cihan Saglam (Danube Tech)
- Ahamed Azeem (Danube Tech)
- Others?
- Participate:
- GitHub repo
- File a bug
- Commit history
§ Abstract
Each DID method specifies how to create/resolve/update/deactivate DIDs within a given verifiable data
registry. How exactly this works can be very different depending on the DID method and may involve
various steps, architectural components, and network communication. The process of resolving a DID
to a DID document is well-understood and specified in the
DID Resolution specification. This document complements
the concept of a “DID Resolver” by also defining a “DID Registrar” component that can execute the three remaining
create(), update(), deactivate() as well as a fourth execute() operations via a common interface.
This specification does NOT specify a DID method. It does NOT specify how to build a verifiable data registry, only a “DID Registrar” component that can interact with a verifiable data registry. This specification also does NOT suggest that private keys should be controlled by any other entity than the DID controller.
§ Status of This Document
DID Registration is a draft specification under development within the Decentralized Identity Foundation (DIF (DIF), and designed to incorporate the requirements and learnings from related work of the most active industry players into a shared specification that meets the collective needs of the community. This spec is regularly updated to reflect relevant changes, and we encourage active engagement on GitHub (see above) and other mediums (e.g. DIF) where this work is being done.
§ Terminology
| Term | Definition |
|---|---|
| Decentralized Identifier (DID) | A globally unique persistent identifier that does not require a centralized registration authority and is often generated and/or registered cryptographically. |
| DID Method | A definition of how a specific DID scheme implementeds the precise operations by which DIDs are created, resolved and deactivated and DID documents are written and updated. |
| DID Document | A set of data describing the DID subject, service and verification methods, that the DID subject or a DID delegate can use to authenticate itself and prove its association with the DID. |
| DID Registrar | A software and/or hardware component that implements the DID create/update/deactivate functions. |
| DID Resolver | A software and/or hardware component that implements the DID resolution function. |
| Wallet | A software and/or hardware component that can securely store DIDs and associated private keys and other sensitive cryptographic key material. Wallets implement various interfaces for cryptographic key generation, signing, verification, and other operations. |
§ Key Management
The DID create/update/deactivate functions raise architectural questions around key management, since they typically involve the generation and use of private keys and other secrets.
With regard to key management, a DID Registrar can operate in the following modes:
§ Internal Secret Mode
In this mode, the DID Registrar is responsible for generating the DID controller keys used by DID operations. This means that the DID Registrar is considered a highly trusted component which should be fully under the control of a DID controller. If it is operated as a remotely hosted service, secure connection protocols such as TLS, DIDComm, etc. MUST be used.
This mode has two options that control how DID controller keys are handled:
storeSecrets and returnSecrets.
The storeSecrets and returnSecrets options can be enabled or disabled independently. A DID Registrar
may define default values for these options, and/or it may allow a client to set them via
the options input field.
Note that if neither option is enabled, then control over a DID may get permanently lost, since the DID Registrar operating in Internal Secret Mode will generate DID controller keys internally, but it will neither store them nor return them to a client.
If a DID Registrar is configured with options storeSecrets=false and returnSecrets=true, then a DID Registrar
with option storeSecrets=true can be simulated by building a “wrapping DID Registrar” around an
“inner DID Registrar”.
§ External Secret Mode
In this mode, the DID Registrar does not itself have access to the secrets used by DID operations, but it has a way of accessing an external wallet in order to perform cryptographic operations such as generating signatures.
The interface between the DID Registrar and an external wallet is out of scope for this specification, but could potentially use wallet or key management interfaces defined by other specifications, e.g.:
- Universal Wallet
- WebKMS
- WebCrypto API
- others…
If additional information (such as a URL, or tenant ID, or secret key, etc.) is required in order for the DID Registrar
to be able to access the external wallet, then such information could be preconfigured in the DID Registrar, or
alternatively supplied by a client in the options and/or secret input fields.
§ Client-managed Secret Mode
In this mode, the DID Registrar does not itself have access to the secrets used by DID operations, but it will ask the client to perform cryptographic operations such as generating signatures.
Explain how the did:ion use case fits in, where the client supplies the public keys / commitments during the create operation.
This mode has one option that controls how DID controller keys are handled:
clientSecretMode.
§ Operations
This section defines interfaces for the standard DID operations create(), update(), and deactivate(),
as well as a fourth execute().
The signatures of these function are to be understood as abstract interfaces for the specified DID operations, with logical named inputs and outputs. Conforming DID URL dereferencing implementations are not required to implement this function using the same names of the inputs, outputs, or of the function itself, nor do they need to implement the algorithm in any specific form, such as an explicit function call in a programming language, a software library, or a protocol endpoint.
Bindings such as the HTTP(S) binding can be used to define specific ways of implementing and exposing this function.
§ create()
create(method, operationState, options, secret, didDocument) -> didState, operationState, didRegistrationMetadata, didDocumentMetadata
This function creates a new DID and associated DID document, according to a known DID method, using various options and optionally an initial DID document.
§ update()
update(did, operationState, options, secret, didDocumentOperation, didDocument) -> didState, operationState, didRegistrationMetadata, didDocumentMetadata
This function updates the DID document associated with the DID, either by completely replacing it, or
by performing an incremental update, or in another way. The specific update operation to be executed is specified in the
didDocumentOperation input field.
§ deactivate()
deactivate(did, operationState, options, secret) -> didState, operationState, didRegistrationMetadata, didDocumentMetadata
This function deactivates the DID and associated DID document.
§ execute()
execute(did, operationState, options, secret, operation, operationData) -> didState, operationState, operationResult, didRegistrationMetadata, didDocumentMetadata
This function executes an operation that uses the DID but is not related to the standard
create/update/deactivate operations. This is essentially an extensibility feature that makes
it possible to perform operations that do not affect the DID or DID document itself, but use
them for any kind of additional functionality which uses the DID. The specific operation
to be executed is specified in the operation input field.
This operation is currently an experimental feature.
§ Input Fields
§ method
This input field indicates the DID method that should be used for the DID operation.
For the create() function, if the did input field is absent or its value is null, then
this input field MUST NOT be null, otherwise it MUST be null.
For the update() function and deactivate() function, this input field MUST be
null, since the DID method is determined by the did input field.
Possible values:
btcrsovkeyweb- … other supported DID method names …
§ did
This input field indicates the DID that is the target of the DID operation.
For the create() function:
- This input field is OPTIONAL, and its use depends on the DID method. In some DID methods, it might be possible for a client to freely choose a DID they want to create, but for other DID methods, the DID is determined by the DID method itself.
For the update() function and deactivate() function:
- This input field MUST NOT be null.
§ operationState
This input field contains data related to the current state of the DID operation. It matches the
operationState output field.
If present, this input field MUST contain either a string or a JSON object. The type and meaning of the value is DID method-specific and not further specified here.
See States for further details about how this input field is used.
§ options
This input field contains a JSON object with various options for the DID operation, such as the network where the DID should be created, or instructions that influence the DID operation. Options may be DID method-specific or may be universally applicable across all DID methods.
This specification defines several DID method-independent properties for this field that are relevant to Key Management.
{
"did": null,
"options": {
"clientSecretMode": true,
"network": "mainnet"
},
"secret": { ... },
"didDocument": { ... }
}
§ clientSecretMode
In Client-managed Secret Mode, if the clientSecretMode option is set to true, then the DID Registrar will
enable client-managed secret mode and let the client perform cryptographic operations such as generating signatures.
Example operation:
{
"did": null,
"options": {
"clientSecretMode": true
},
"secret": { ... },
"didDocument": { ... }
}
§ storeSecrets
In Internal Secret Mode, if the storeSecrets option is set to true:
- The DID Registrar maintains an internal wallet where DIDs
and DID controller keys can be stored. The DID controller keys can then be used in future DID operations. For
example, if a
create()operation is executed, then a subsequentupdate()ordeactivate()operation will be able to use existing DID controller keys stored in the DID Registrar’s internal wallet.
Example:
{
"did": null,
"options": {
"storeSecrets": true
},
"secret": { ... },
"didDocument": { ... }
}
§ returnSecrets
In Internal Secret Mode, if the returnSecrets option is set to true:
- The DID Registrar will return generated DID controller keys to the client.
See the didState.secret output field for further details.
Example:
{
"did": null,
"options": {
"returnSecrets": true
},
"secret": { ... },
"didDocument": { ... }
}
§ secret
This input field contains a JSON object with DID controller keys and other secrets.
In Internal Secret Mode, this input field MAY contain one or more of the following:
- A
verificationMethodproperty with a JSON array containing one or more Verification Method Private Data objects.
Example:
{
"did": null,
"options": { ... },
"secret": {
"verificationMethod": [{
"type": "JsonWebKey2020",
"controller": "did:example:123",
"purpose": ["authentication", "assertionMethod", "capabilityDelegation", "capabilityInvocation"],
"privateKeyJwk": {
"kty": "EC",
"d": "-s-PwFdfgcdBPTDbJwZuiAFHCuI8r9vR13OGHo14--4",
"crv": "secp256k1",
"x": "htusHse5FMBnT_4266kn9T2yMmjDllwWvVSc_I2-WZ0",
"y": "RjE_GjsRMELYJ6XuNSFDu3mCbyJnCQ26X_YtmyM9Bfo"
}
}]
},
"didDocument": { ... }
}
In Client-managed Secret Mode, this input field MAY contain one or more of the following:
- A
verificationMethodproperty with a JSON array containing one or more Verification Method Public Data objects. - A
signingResponseproperty with a Signing Response Set data structure as a response to a Signing Request Set from the DID Registrar. - A
decryptionResponseproperty with a Decryption Response Set data structure as a response to a Decryption Request Set from the DID Registrar.
Example:
{
"did": null,
"options": { ... },
"secret": {
"verificationMethod": [{
"type": "JsonWebKey2020",
"controller": "did:example:123",
"purpose": ["authentication", "assertionMethod", "capabilityDelegation", "capabilityInvocation"],
"publicKeyJwk": {
"kty": "EC",
"crv": "secp256k1",
"x": "htusHse5FMBnT_4266kn9T2yMmjDllwWvVSc_I2-WZ0",
"y": "RjE_GjsRMELYJ6XuNSFDu3mCbyJnCQ26X_YtmyM9Bfo"
}
}]
},
"didDocument": { ... }
}
Example:
{
"did": null,
"operationState": "155eae21-45e5-4e71-bb22-fef51cda5bf7",
"options": { ... },
"secret": {
"signingResponse": {
"signingRequest1": {
"signature": "<-- base64 encoded -->",
"kid": "did:example:123#key-0",
"alg": "EdDSA"
}
}
},
"didDocument": { ... }
}
Example:
{
"did": null,
"operationState": "155eae21-45e5-4e71-bb22-fef51cda5bf7",
"options": { ... },
"secret": {
"decryptionResponse": {
"decryptionRequest1": {
"decryptedPayload": "<-- base64 encoded -->"
}
}
},
"didDocument": { ... }
}
§ didDocumentOperation
This input field indicates which update operation(s) should be applied to a DID’s associated DID document.
For the create() function, this input field MUST be absent, and is implied to have a single value of setDidDocument.
For the update() function, this input field is OPTIONAL. If present, it MUST contain a JSON array of string
values to indicate one or more DID document operations that should be performed.
Each entry in this JSON array corresponds to a matching entry at the same index in the didDocument input field.
If it is absent, it is implied to have a single value of "setDidDocument".
For the deactivate() function, this input field MUST be absent.
This specification defines several standard values for this operation. Individual DID methods MAY specify other
ways of executing an update() function.
Possible values:
"setDidDocument": The corresponding entry in thedidDocumentinput field contains the new DID document of the DID after the DID operation is executed."addToDidDocument": The corresponding entry in thedidDocumentinput field contains properties to be added to the current DID document of the DID after the DID operation is executed."removeFromDidDocument": The corresponding entry in thedidDocumentinput field contains properties to be removed from the current DID document of the DID after the DID operation is executed.- … other DID method-specific DID document operations …
Example:
{
"did": "did:example:123",
"options": { ... },
"secret": { ... },
"didDocumentOperation": ["setDidDocument"],
"didDocument": [{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/jws-2020/v1"
],
"id": "did:example:123",
"verificationMethod": [{
"id": "did:example:123#key-1",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"publicKeyJwk": {
"kty": "OKP",
"crv": "Ed25519",
"x": "VCpo2LMLhn6iWku8MKvSLg2ZAoC-nlOyPVQaO3FxVeQ"
}
}]
}]
}
Example:
{
"did": "did:example:123",
"options": { ... },
"secret": { ... },
"didDocumentOperation": ["removeFromDidDocument", "addToDidDocument"],
"didDocument": [{
"verificationMethod": [{
"id": "did:example:123#key-1"
}]
},
{
"verificationMethod": [{
"id": "did:example:123#key-2",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"publicKeyJwk": {
"kty": "OKP",
"crv": "Ed25519",
"x": "eylT8wroHZUY8Qv6tlMYQWFe88U0Mi5_lI8eud9xgPg"
}
}]
}
]
}
Note that some of the above update operations can be internally transformed into others, e.g.:
- If the update operation is
"setDidDocument", then it may be transformed into a combination of"addToDidDocument"and"removeFromDidDocument", by first resolving the current DID document, and then calculating incremental changes (diffs) between the resolved DID document and the value of thedidDocumentinput field. - If the update operation is either
"addToDidDocument"or"removeFromDidDocument", then it may be transformed into"setDidDocument", by first resolving the current DID document, and then calculating the updated complete DID document after applying the incremental changes (diffs) in thedidDocumentinput field.
A DID Registrar may or may not support certain update operations, and it may or may not support internal transformation between them.
§ didDocument
This input field contains either a complete DID document, or incremental changes in a DID document,
depending on the value of the didDocumentOperation input field.
For the create() function, this input field is OPTIONAL. If present, it MUST contain a single JSON object value.
For the update() function, this input field is OPTIONAL. If present, it MUST contain a JSON array of JSON object values.
Each entry in this JSON array corresponds to a matching entry at the same index in the didDocumentOperation input field.
For the deactivate() function, this input field MUST be absent.
For the execute() function, this input field MUST be absent.
§ operation
This input field indicates which operation(s) should be executed when the execute() function function is used to
execute an operation that does not affect the DID or DID document itself.
For the create() function, update() function, and deactivate() function this
input field MUST be absent.
For the execute() function, this input field is REQUIRED and MUST contain a JSON array of string
values to indicate one or more operations that should be executed.
This specification does not define any concrete operation. It is expected that such operations will often be DID method-specific, although it is also possible that method-independent operations could be defined in the future by other specifications.
Example:
{
"options": {
"network": "mainnet"
},
"operation": ["addToTrustRegistry"],
"operationData": [{
"trustRegistryUrl": "https://example.com/registry"
}]
}
§ operationData
This input field contains additional data when the execute() function function is used to
execute an operation that does not affect the DID or DID document itself.
For the create() function, update() function, and deactivate() function this
input field MUST be absent.
For the execute() function, this input field is REQUIRED and MUST contain a JSON array of JSON object values.
§ Output Fields
§ didState
This output field contains a JSON object with the following fields, which contain information about the current state of the DID:
didState.state: The current state of DID operations.didState.did: The DID at the end of the DID operation.didState.secret: An object with DID controller keys and other secrets.didState.didDocument: The DID document after the DID operation has been successfully executed.
In Client-managed Secret Mode, this output field MAY contain one or more of the following:
- A
verificationMethodTemplateproperty with a JSON array containing one or more Verification Method Template objects. - A
signingRequestproperty with a Signing Request Set. - A
decryptionRequestproperty with a Decryption Request Set.
See States for further details about how this output field is used.
§ didState.state
This output field contains the current state of the DID. It is used to indicate if a DID operation is finished, failed, or if a longer-running process has been created that requires additional steps.
This specification defines four well-known values for this property: finished, failed, action, wait.
§ didState.did
This output field contains the DID that is the target of the operation.
For the create() function:
- If the value of the
didState.stateoutput field is"finished", the value of this output field MUST NOT be null and MUST contain the final DID that has been created. - Otherwise, the value of this output field may or may not contain the DID, depending on the DID method.
For the update() function and deactivate() function:
- This output field MUST NOT be null, and its value MUST match the
didinput field that was used when executing the function.
§ didState.secret
This output field contains a JSON object with DID controller keys and other secrets.
In Internal Secret Mode, if the returnSecrets option is set to true:
- This output field MAY contain a
verificationMethodproperty with a JSON array containing one or more Verification Method Private Data objects.
Example:
{
"didState": {
"state": "finished",
"did": "did:key:z6MknhhUUtbXCLRmUVhYG7LPPWN4CTKWXTLsygHMD6Ah5uDN",
"secret": {
"verificationMethod": [{
"type": "JsonWebKey2020",
"controller": "did:example:123",
"purpose": ["authentication", "assertionMethod", "capabilityDelegation", "capabilityInvocation"],
"privateKeyJwk": {
"kty": "EC",
"d": "-s-PwFdfgcdBPTDbJwZuiAFHCuI8r9vR13OGHo14--4",
"crv": "secp256k1",
"x": "htusHse5FMBnT_4266kn9T2yMmjDllwWvVSc_I2-WZ0",
"y": "RjE_GjsRMELYJ6XuNSFDu3mCbyJnCQ26X_YtmyM9Bfo"
}
}]
},
"didDocument": { ... }
},
"operationState": null,
"didRegistrationMetadata": { ... },
"didDocumentMetadata": { ... }
}
In Client-managed Secret Mode:
- This output field MAY contain a
verificationMethodproperty with a JSON array containing one or more Verification Method Public Data objects.
Example:
{
"didState": {
"state": "finished",
"did": "did:key:z6MknhhUUtbXCLRmUVhYG7LPPWN4CTKWXTLsygHMD6Ah5uDN",
"secret": {
"verificationMethod": [{
"type": "JsonWebKey2020",
"controller": "did:example:123",
"purpose": ["authentication", "assertionMethod", "capabilityDelegation", "capabilityInvocation"],
"publicKeyJwk": {
"kty": "EC",
"crv": "secp256k1",
"x": "htusHse5FMBnT_4266kn9T2yMmjDllwWvVSc_I2-WZ0",
"y": "RjE_GjsRMELYJ6XuNSFDu3mCbyJnCQ26X_YtmyM9Bfo"
}
}]
},
"didDocument": { ... }
},
"operationState": null,
"didRegistrationMetadata": { ... },
"didDocumentMetadata": { ... }
}
This output field MAY contain additional properties that are considered secrets, such as seeds, passwords, etc.
§ didState.didDocument
This output field contains the DID document after the DID operation has been successfully executed.
This output field is OPTIONAL.
Example:
{
"didState": {
"state": "finished",
"did": "did:key:z6MknhhUUtbXCLRmUVhYG7LPPWN4CTKWXTLsygHMD6Ah5uDN",
"secret": { ... },
"didDocument": {
"@context": [
"https://www.w3.org/ns/did/v1"
],
"id": "did:example:123",
"verificationMethod": [{
"type": "Ed25519VerificationKey2018",
"id": "did:example:123#key-1",
"publicKeyBase58": "EqRvGzVX3aoLYwZSdKhNd2q5Ez7EVbdPA4DVZW3ngn1U"
}],
"authentication": ["did:example:123#key-1"],
"assertionMethod": ["did:example:123#key-1"]
}
},
"operationState": null,
"didRegistrationMetadata": { ... },
"didDocumentMetadata": { ... }
}
§ operationState
This output field contains data related to the current state of the DID operation. It matches the
operationState input field.
If present, this output field MUST contain either a string or a JSON object. The type and meaning of the value is DID method-specific and not further specified here.
If the value of the didState.state output field is either finished or failed:
- This output field MUST be absent or have a
nullvalue.
See States for further details about how this output field is used.
Example:
{
"didState": { ... },
"operationState": "155eae21-45e5-4e71-bb22-fef51cda5bf7",
"didRegistrationMetadata": { ... },
"didDocumentMetadata": { ... }
}
Example:
{
"didState": { ... },
"operationState": {
"currentStep": 3,
"someData": { ... }
},
"didRegistrationMetadata": { ... },
"didDocumentMetadata": { ... }
}
§ didRegistrationMetadata
This output field contains metadata about the registration process itself.
Possible uses of the didRegistrationMetadata output field:
- Duration of the DID registration process.
- Various URLs, IP addresses or other network information that was used during the DID registration process.
- Current balance or other information about tokens or cryptocurrencies that were used during the DID registration process.
- Information about third parties that were involved in the DID registration process, such as trust anchors, onboarding services, transaction endorsers, etc.
- Proofs added by a DID registrar (e.g. to establish trusted registration).
§ didDocumentMetadata
This output field contains metadata about the DID’s associated DID document.
Possible uses of the didDocumentMetadata output field:
- Hash values, smart contract addresses, blockchain heights, transaction numbers, etc.
- Proofs added by a DID controller (e.g. to establish control authority).
§ operationResult
This output field contains the result when the execute() function function is used to
execute an operation that does not affect the DID or DID document itself.
For the create() function, update() function, and deactivate() function this
output field MUST be absent.
For the execute() function, this output field is REQUIRED and MUST contain a JSON array of JSON object values.
Example:
{
"didState": { ... },
"operationState": null,
"operationResult": [{
"myResult": "myResultValue"
}],
"didRegistrationMetadata": { ... },
"didDocumentMetadata": { ... }
}
§ States
When executing the create(), update(), deactivate(), and execute() DID operations, an operation can sometimes turn into a
longer-running process potentially consisting of multiple steps. In each step,
additional information such as public key material or signatures may be required, and the DID operation’s state
might change.
The didState output field is used by the DID Registrar to indicate to the client the current state of
this process, and how to proceed to a next step if needed.
The operationState input field and operationState output field contain
DID-method specific information that is used internally by the DID Registrar to keep track of the ongoing process. They
fulfill a similar function as a cookie in web architecture and allow a DID Registrar to correlate multiple invocations
by the client and maintain state between them.
The following diagram illustrates possible states while executing a create() DID operation.

The following sections explain the possible states of a DID registration process, which are returned as values of the
didState.state output field.
§ didState.state="finished"
This state indicates that the DID operation has been completed, and that no further invocations of the DID Registrar functions are required.
Example:
{
"didState": {
"state": "finished",
"did": "did:key:z6MknhhUUtbXCLRmUVhYG7LPPWN4CTKWXTLsygHMD6Ah5uDN",
"secret": { ... },
"didDocument": { ... }
},
"operationState": null,
"didRegistrationMetadata": { ... },
"didDocumentMetadata": { ... }
}
§ didState.state="failed"
This state indicates that the DID operation has failed, and that no further invocations of the DID Registrar functions are required.
In this state, the didState output field MUST contain a reason property that indicates the reason
for the failure.
The didState output field MAY contain additional properties that are relevant to this state.
Example:
{
"didState": {
"state": "failed",
"did": "did:key:z6MknhhUUtbXCLRmUVhYG7LPPWN4CTKWXTLsygHMD6Ah5uDN",
"reason": "networkUnavailable"
},
"operationState": null,
"didRegistrationMetadata": { ... },
"didDocumentMetadata": { ... }
}
§ didState.state="action"
This state indicates that the client needs to perform an action, before the DID operation can be continued.
Possible uses for didState.state="action":
- Client needs to generate a new cryptographic key pair
- Client needs to cryptographically sign a payload
- Client needs to send cryptocurrency to fund a wallet addres
- Client needs to obtain an OAuth2 access token from an external service
- Client needs to accept the terms of a legal agreement
In this state, the didState output field MUST contain an action property that indicates the type of
action that needs to be performed.
The didState output field MAY contain additional properties that are relevant to this state.
This specification defines the following well-known values for the action property that may be used in this state:
didState.action="getVerificationMethod"- Client needs to provide a newly generated or already existing verification method.didState.action="signPayload"- Client needs to generate a signature on a payload.didState.action="decryptPayload"- Client needs to decrypt a payload.
Example:
{
"didState": {
"state": "action",
"action": "fundingRequired",
"description": "Please fund the address mzUC2F1XgXfTJEYUBZXdG6M8wWWvhgEknG."
},
"operationState": "155eae21-45e5-4e71-bb22-fef51cda5bf7",
"didRegistrationMetadata": { ... },
"didDocumentMetadata": { ... }
}
§ didState.action="getVerificationMethod"
This action indicates that the client needs to provide a newly generated or already existing verification method, before the DID operation can be continued.
This action is used in Client Managed Secret Mode.
The didState output field MUST contain a property verificationMethodTemplate with a JSON array containing one or more Verification Method Template data structures.
The didState output field MAY contain additional properties that are relevant to this action.
Example:
{
"didState": {
"state": "action",
"action": "getVerificationMethod",
"verificationMethodTemplate": [{
"id": "#key-1",
"type": "Ed25519VerificationKey2018"
}]
},
"operationState": null,
"didRegistrationMetadata": {},
"didDocumentMetadata": {}
}
Example:
{
"didState": {
"state": "action",
"action": "getVerificationMethod",
"verificationMethodTemplate": [{
"purpose": ["recovery"],
"type": "EcdsaSecp256k1VerificationKey2019"
}]
},
"operationState": null,
"didRegistrationMetadata": {},
"didDocumentMetadata": {}
}
§ didState.action="signPayload"
This action indicates that the client needs to generate a signature on a payload, before the DID operation can be continued.
This action is used in Client Managed Secret Mode.
The didState output field MUST contain a property signingRequest with a Signing Request Set data structure.
The didState output field MAY contain additional properties that are relevant to this action.
Example:
{
"didState": {
"state": "action",
"action": "signPayload",
"signingRequest": {
"signingRequest1": {
"payload": {
...
},
"serializedPayload": "<-base64->",
"kid": "did:example:123#key-0",
"alg": "EdDSA"
},
"signingRequest2": {
"serializedPayload": "<-base64->",
"alg": "ES256K",
"purpose": "authentication" // describes the purpose of the requested signature
}
}
},
"operationState": "155eae21-45e5-4e71-bb22-fef51cda5bf7",
"didRegistrationMetadata": {},
"didDocumentMetadata": {}
}
§ didState.action="decryptPayload"
This action indicates that the client needs to decrypt a payload, before the DID operation can be continued.
This action is used in Client Managed Secret Mode.
The didState output field MUST contain a property decryptionRequest with a Decryption Request Set data structure.
The didState output field MAY contain additional properties that are relevant to this action.
Example:
{
"didState": {
"state": "action",
"action": "decryptPayload",
"decryptionRequest": {
"decryptionRequest1": {
"encryptedPayload": "<-base64->",
"kid": null,
"enc": "A128GCM"
},
"decryptionRequest2": {
"encryptedPayload": "<-base64->",
"kid": null,
"enc": "A256GCM"
}
}
},
"operationState": "155eae21-45e5-4e71-bb22-fef51cda5bf7",
"didRegistrationMetadata": {},
"didDocumentMetadata": {}
}
§ didState.state="wait"
This state indicates that the client needs to wait, before the DID operation can be continued.
Possible uses for didState.state="wait":
- Client needs to wait for confirmation on chain
- Client needs to wait for approval by someone
In this state, the didState output field MUST contain a wait property, and MAY contain additional
properties, to explain the reason for the failure.
Example:
{
"didState": {
"state": "wait",
"wait": "Please wait until the transaction is complete.",
"waitTime": 3600000
},
"operationState": "155eae21-45e5-4e71-bb22-fef51cda5bf7",
"didRegistrationMetadata": { ... },
"didDocumentMetadata": { ... }
}
§ Algorithm
This section defines a State Processing Algorithm that clients can use after invoking the DID Registrar functions, in order to process the outputs including current state (see States). If the DID operation consists of multiple steps, the DID Registrar functions may have to be invoked multiple times until a DID operation is completed.
If the value of the didState.state output field is either finished or failed:
- The DID operation is complete, and no further invocations of the DID Registrar functions are required.
If the value of the didState.state output field is either action or wait:
- The client needs to perform an action, or it needs to wait for a certain period of time or until a certain event occurs.
- After that, the client prepares new inputs and invokes the DID Registrar functions again.
In the latter case, the current state is processed and new inputs are prepared. Given previousInputs and previousOutputs, the algorithm determines nextInputs for the next invocation of the DID Registrar functions.
- Initialize nextInputs by copying all input fields from previousInputs.
- If present, copy
previousOutputs.didState.didtonextInputs.did. - If present, copy
previousOutputs.didState.didDocumenttonextInputs.didDocument. - If present, copy
previousOutputs.operationStatetonextInputs.operationState. - If
didState.state="action"anddidState.action="getVerificationMethod"- For each Verification Method Template in the
didStateoutput field, generate or retrieve a key pair, and add a Verification Method Public Data to thedidDocumentinput field orsecretinput field.
- For each Verification Method Template in the
- If
didState.state="action"anddidState.action="signPayload"- From the Signing Request Set in the
didStateoutput field, sign the payload(s), and add the Signing Response Set to thesecretinput field.
- From the Signing Request Set in the
- If
didState.state="action"anddidState.action="decryptPayload"- From the Decryption Request Set in the
didStateoutput field, decrypt the payload(s), and add the Decryption Response Set to thesecretinput field.
- From the Decryption Request Set in the
Explain that the generated verification method must then be included in either “secret” or “didDocument” in next request.
§ Data Structures
This specification defines a number of data structures that appear in the input fields and output fields.
The data structures are used as follows:
The Verification Method Public Data structure is used as follows, when public data about a verification method is exchanged between the client and the DID Registrar:
- In Client-managed Secret Mode as a
verificationMethodfield inside thesecretinput field, after the client received adidState.action="getVerificationMethod"output field. - In Client-managed Secret Mode as a
verificationMethodfield inside thedidState.secretoutput field, when the DID Registrar responds to a client request.
The Verification Method Private Data structure is used as follows, when private data about a verification method is exchanged between the client and the DID Registrar:
- In Internal Secret Mode as a
verificationMethodfield inside thesecretinput field, after the client received adidState.action="getVerificationMethod"output field. - In Internal Secret Mode as a
verificationMethodfield inside thedidState.secretoutput field, when the DID Registrar sends a response.
The Verification Method Template structure is used as follows:
- In Client-managed Secret Mode as
verificationMethodTemplatefield inside thedidStateoutput field, when the DID Registrar sends adidState.action="getVerificationMethod"output field.
The Signing Request Set data structure is used as follows:
- In Client-managed Secret Mode as a
signingRequestfield inside thedidStateoutput field, when the DID Registrar sends adidState.action="signPayload"output field.
The Signing Response Set data structure is used as follows:
- In Client-managed Secret Mode as a
signingResponsefield inside thesecretinput field, after the client received adidState.action="signPayload"output field.
The Decryption Request Set data structure is used as follows:
- In Client-managed Secret Mode as a
decryptionRequestfield inside thedidStateoutput field, when the DID Registrar sends adidState.action="decryptPayload"output field.
The Decryption Response Set data structure is used as follows:
- In Client-managed Secret Mode as a
decryptionResponsefield inside thesecretinput field, after the client received adidState.action="decryptPayload"output field.
§ Verification Method Public Data
A Verification Method Public Data structure is a JSON object based on the verification method data model as defined by [DID-CORE], with the following differences:
- The
idproperty is OPTIONAL.- If it is present, its value MUST match the
idproperty of the corresponding verification method in the DID’s associated DID document. - If it is absent, the verification method does not correspond to any verification method in the DID’s associated DID document.
- If it is present, its value MUST match the
- The JSON object MAY contain a property
purpose, and the value of that property MUST be a JSON array, which contains verification relationships such asauthenticationorassertionMethod.
Example:
{
"id": "did:example:123#key-0",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"purpose": ["authentication", "assertionMethod", "capabilityDelegation", "capabilityInvocation"],
"publicKeyJwk": {
"kty": "EC",
"crv": "secp256k1",
"x": "htusHse5FMBnT_4266kn9T2yMmjDllwWvVSc_I2-WZ0",
"y": "RjE_GjsRMELYJ6XuNSFDu3mCbyJnCQ26X_YtmyM9Bfo"
}
}
Example:
{
"type": "Ed25519VerificationKey2020",
"controller": "did:example:123",
"purpose": ["recovery"],
"publicKeyMultibase": "z5TVraf9itbKXrRvt2DSS95Gw4vqU3CHAdetoufdcKazA"
}
§ Verification Method Private Data
A Verification Method Private Data structure is a JSON object based on the Verification Method Public Data structure, with the following difference:
- Instead of containing properties such as
publicKeyJwkorpublicKeyMultibasefor expressing verification material, the verification method contains corresponding private key material, using properties such asprivateKeyJwkorprivateKeyMultibase.
Example:
{
"id": "did:example:123#key-0",
"type": "JsonWebKey2020",
"controller": "did:example:123",
"purpose": [ "authentication", "assertionMethod", "capabilityDelegation", "capabilityInvocation" ],
"privateKeyJwk": {
"kty": "EC",
"d": "-s-PwFdfgcdBPTDbJwZuiAFHCuI8r9vR13OGHo14--4",
"crv": "secp256k1",
"x": "htusHse5FMBnT_4266kn9T2yMmjDllwWvVSc_I2-WZ0",
"y": "RjE_GjsRMELYJ6XuNSFDu3mCbyJnCQ26X_YtmyM9Bfo"
}
}
Example:
{
"type": "Ed25519VerificationKey2020",
"controller": "did:example:123",
"purpose": ["recovery"],
"privateKeyMultibase": "z5TVraf9itbKXrRvt2DSS95Gw4vqU3CHAdetoufdcKazA"
}
§ Verification Method Template
A Verification Method Template structure is a JSON object based on the verification method data model as defined by [DID-CORE], with the following differences:
- The
idproperty is OPTIONAL.- If it is present, its value MUST match the
idproperty of the corresponding verification method in the DID’s associated DID document. - If it is absent, then the verification method does not correspond to any verification method in the DID’s associated DID document.
- If it is present, its value MUST match the
- The
typeproperty is OPTIONAL. - The
controllerproperty is OPTIONAL. - The JSON object MAY contain a property
purpose, and the value of that property MUST be a JSON array, which contains verification relationships such asauthenticationorassertionMethod. - The JSON object MAY contain a property
publicKeyJwkfor expressing JWK claims such asktyandcrv.
Example Verification Method Template containing properties id and type:
{
"id": "#key-1",
"type": "Ed25519VerificationKey2020"
}
Example Verification Method Template containing properties id and type and publicKeyJwk:
{
"id": "#key-1",
"type": "JsonWebKey",
"publicKeyJwk": {
"kty": "EC",
"crv": "P-256"
}
}
Example Verification Method Template containing properties purpose and type:
{
"purpose": ["recovery"],
"type": "EcdsaSecp256k1VerificationKey2019"
}
§ Signing Request Set
A Signing Request Set structure is a JSON object. Each property name in that JSON object is called a signing request ID, and the corresponding property value MUST be a JSON object which is called the Signing Request.
A Signing Request contains the following properties:
payload: The payload to be signed in a JSON form for informational purposes. This property is OPTIONAL.serializedPayload: The Base64-encoded byte array that represents the serialized payload to be signed. This property is REQUIRED.kid: This property is interpreted as in [RFC7517] to indicate a specific key that should be used for signing. Example value:did:example:123#key-0. This property is OPTIONAL.alg: This property is interpreted as in [RFC7515] to indicate the cryptographic algorithm to be used to sign the payload. Example values:EdDSA,ES256K,PS256. This property is REQUIRED.purpose: This property indicates the specific intent of the signing process. Example value:authentication. This property is OPTIONAL.
Example Signing Request Set containing two Signing Requests with IDs signingRequest1 and signingRequest2:
{
"signingRequest": {
"signingRequest1": {
"payload": {
...
},
"serializedPayload": "<-base64->",
"kid": "did:example:123#key-0",
"alg": "EdDSA"
},
"signingRequest2": {
"serializedPayload": "<-base64->",
"alg": "ES256K",
"purpose": "authentication" // describes the purpose of the requested signature
}
}
}
§ Signing Response Set
A Signing Response Set structure is a JSON object. Each property name MUST match a signing request ID which was previously received by the client in a Signing Request Set. The corresponding property value MUST be a JSON object which is called the Signing Response.
A Signing Response contains the following properties:
signature: The Base64-encoded byte array that represents the signature of a payload. This property is REQUIRED.kid: This property is interpreted as in [RFC7517] to indicate a specific key that was used for signing. Example value:did:example:123#key-0. This property is OPTIONAL, but SHOULD be included if an identifier for the key is known.alg: This property is interpreted as in [RFC7515] to indicate the cryptographic algorithm that was used to sign the payload. Example values:EdDSA,ES256K,PS256. This property SHOULD be included.purpose: This property indicates the specific intent of the signing process. Example value:authentication. This property is OPTIONAL.
Example Signing Response Set containing two Signing Responses:
{
"signingResponse": {
"signingRequest1": {
"signature": "<-base64->",
"kid": "did:example:123#key-0",
"alg": "EdDSA"
},
"signingRequest2": {
"signature": "<-base64->",
"alg": "ES256K",
"purpose": "authentication" // describes the purpose of the requested signature
}
}
}
§ Decryption Request Set
A Decryption Request Set structure is a JSON object. Each property name in that JSON object is called a decryption request ID, and the corresponding property value MUST be a JSON object which is called the Decryption Request.
A Decryption Request contains the following properties:
payload: The payload to be signed in a JSON form for informational purposes. This property is OPTIONAL.encryptedPayload: The Base64-encoded byte array that represents the encrypted payload to be decrypted. This 0property is REQUIRED.kid: This property is interpreted as in [RFC7517] to indicate a specific key that should be used for decryption. Example value:did:example:123#key-1. This property is OPTIONAL.enc: This property is interpreted as in [RFC7516] to indicate the cryptographic algorithm to be used to decrypt the payload. Example values:A128GCM,A256GCM. This property is REQUIRED.purpose: This property indicates the specific intent of the decryption process. Example value:parsing. This property is OPTIONAL.
Example Decryption Request Set containing two Decryption Requests with IDs decryptionRequest1 and decryptionRequest2:
{
"decryptionRequest1": {
"encryptedPayload": "<-base64->",
"kid": null,
"enc": "A128GCM"
},
"decryptionRequest2": {
"encryptedPayload": "<-base64->",
"kid": null,
"enc": "A256GCM"
}
}
§ Decryption Response Set
A Decryption Response Set structure is a JSON object. Each property name MUST match a decryption request ID which was previously received by the client in a Decryption Request Set. The corresponding property value MUST be a JSON object which is called the Decryption Response.
A Decryption Response contains the following properties:
decryptedPayload: The Base64-encoded byte array that represents the decrypted payload. This property is REQUIRED.kid: This property is interpreted as in [RFC7517] to indicate a specific key that was used for decrypting. Example value:did:example:123#key-1. This property is OPTIONAL, but SHOULD be included if an identifier for the key is known.enc: This property is interpreted as in [RFC7515] to indicate the cryptographic algorithm that was used to decrypt the payload. Example values:A128GCM,A256GCM. This property SHOULD be included.purpose: This property indicates the specific intent of the decryption process. Example value:parsing. This property is OPTIONAL.
Example Decryption Response Set containing two Decryption Responses:
{
"decryptionRequest1": {
"decryptedPayload": "<-base64->",
"key": "did:example:123#key-1",
"enc": "A128GCM"
},
"decryptionRequest2": {
"decryptedPayload": "<-base64->",
"key": "did:example:123#key-2",
"enc": "A256GCM"
}
}
§ DID URL Operations
In addition to the DID Registrar functions defined in previous sections, this specification also defines operations on resources identified by DID URLs.
§ createResource()
createResource(did, relativeDidUrl, operationState, options, secret, content) -> didUrlState, operationState, didRegistrationMetadata, contentMetadata
This function creates a new DID URL and associated resource, according to a known DID method, using various options and optionally the initial resource data.
§ updateResource()
updateResource(did, relativeDidUrl, operationState, options, secret, contentOperation, content) -> didUrlState, operationState, didRegistrationMetadata, contentMetadata
This function updates the content of the resource associated with the DID URL, either by completely replacing it, or
by performing an incremental update, or in another way. The specific update resource operation to be executed is specified in the
contentOperation input field.
§ deactivateResource()
deactivateResource(did, relativeDidUrl, operationState, options, secret) -> didUrlState, operationState, didRegistrationMetadata, contentMetadata
This function deactivates the DID URL and associated resource.
§ Extensions
This section documents various optional extension features that can complement the main functionality of a DID Registrar to accommodate advanced use cases.
§ options.requestVerificationMethod
Normally, when creating or updating a DID, only cryptographic keys that are required by the applicable DID method itself are generated, in other words, keys that are needed for DID operations themselves. Depending on the DID method, these keys may or may not appear in the DID document.
Irrespective of DID method-specific differences with regard to keys, it may sometimes be useful to add additional keys
to a DID document. This can be done by adding a requestVerificationMethod option. If present, this option MUST contain
a JSON array containing one or more Verification Method Template data structures.
Example:
{
"did": null,
"options": {
"requestVerificationMethod": [{
"id": "#signingKey",
"type": "Ed25519VerificationKey2018",
"purpose": ["authentication", "assertionMethod"]
}]
},
"secret": { ... },
"didDocument": { ... }
}
In the above example, a client instructs a DID Registrar to add a verification method with "id": "#signingKey" and
"type": "Ed25519VerificationKey2018", even if this verification method is not required for the DID operation itself.
§ didDocumentOperation="deactivate"
The update() function uses the didDocumentOperation input field to determine
what type of update operation should be applied to a DID’s associated DID document. Deactivating a DID is normally
done by using the separate deactivate() function.
However, it is also possible to model deactivation as a special type of update operation. For this purpose, this
section defines the value deactivate for the didDocumentOperation input field. This can
be especially useful if atomic combinations of update and deactivate functions are required, since a single execution
of the update() function can include multiple entries in the
didDocumentOperation input field.
Example:
{
"did": "did:example:123",
"options": { ... },
"secret": { ... },
"didDocumentOperation": ["removeFromDidDocument", "deactivate"],
"didDocument": [{
"verificationMethod": [{
"id": "did:example:123#key-1"
}]
},
null]
}
In the above example, a client instructs a DID Registrar to first remove a verification method from a DID document, and then deactivate the DID.
§ Architecture Considerations
In order to implement a library or tool that supports the above interfaces for creating, updating, and deactivating DIDs in a method-agnostic way, we can imagine a similar architecture as is common for a DID Resolver, i.e. using a set of drivers that perform method-specific operations.
Some architectural questions that apply to a DID Resolver also apply to a DID Registrar, e.g.:
- Is the abstract interface implemented as a library that can be integrated locally into an application or service, or is the abstract interface exposed by a remote service and used via HTTP or another binding?
- How do method-specific drivers interact with the DID’s target system? For example, do they have direct access to a blockchain full node?
- What are implications of the above questions for trust and security?
§ HTTPS Binding
The abstract interfaces defined by this specification can be implemented and deployed in the form of bindings to different concrete protocols and transports. This section defines a binding based on HTTP POST operations, with inputs and outputs sent in the HTTP body, encoded as JSON.
In this binding, a secure HTTPS connection with at least TLS 1.2 MUST be used.
Each one of the four DID Registrar functions can be invoked via a separate HTTPS endpoint, for example:
https://uniregistrar.io/1.0/create
https://uniregistrar.io/1.0/update
https://uniregistrar.io/1.0/deactivate
https://uniregistrar.io/1.0/execute
The following HTTP status codes are used for the create() function:
- 200, if the request was successful, but the DID may not be fully created yet, as indicated by the
didState.stateoutput field. - 201, if the DID has been successfully created, as indicated by the
didState.stateoutput field. - 400, if a problem with the input fields has occurred.
- 500, if an internal error has occurred.
The following HTTP status codes are used for the update() function:
- 200, if request was successful, and the DID may or may not be fully updated yet, as indicated by the
didState.stateoutput field. - 400, if a problem with the input fields has occurred.
- 500, if an internal error has occurred.
The following HTTP status codes are used for the deactivate() function operation:
- 200, if request was successful, and the DID may or may not be fully deactivated yet, as indicated by the
didState.stateoutput field. - 400, if a problem with the input fields has occurred.
- 500, if an internal error has occurred.
See here for an OpenAPI definition.
§ Normative References
- DID-CORE
- Decentralized Identifiers (DIDs) v1.0. Drummond Reed; Manu Sporny; Markus Sabadello; Dave Longley; Christopher Allen; Jonathan Holt; 2020-09-07. Status: WD.
- 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.
- RFC7517
- JSON Web Key (JWK). M. Jones; 2015-05. Status: Proposed Standard.
§ Acknowledgements
Supported by NGI TRUSTCHAIN, which is made possible with financial support from the European Commission’s Next Generation Internet programme.
§ Appendix
§ Other Resources
The following projects are working on DID registration across different DID methods.