Decentralized identifiers (DIDs) are a new type of identifier for verifiable, "self-sovereign" digital identity. DIDs are fully under the control of the DID subject, independent from any centralized registry, identity provider, or certificate authority. DIDs resolve to DID Documents — simple documents that describe how to use that specific DID.

This document specifies the algorithms and guidelines for resolving DIDs and dereferencing DID URLs.

Comments regarding this document are welcome. Please file issues directly on GitHub, or send them to public-credentials@w3.org (subscribe, archives).

Portions of the work on this specification have been funded by the United States Department of Homeland Security's Science and Technology Directorate under contracts HSHQDC-17-C-00019. The content of this specification does not necessarily reflect the position or the policy of the U.S. Government and no official endorsement should be inferred.

Work on this specification has also been supported by the Rebooting the Web of Trust community facilitated by Christopher Allen, Shannon Appelcline, Kiara Robles, Brian Weller, Betty Dhamers, Kaliya Young, Kim Hamilton Duffy, Manu Sporny, Drummond Reed, Joe Andrieu, and Heather Vescent.

Introduction

DID resolution is the process of obtaining a DID document for a given DID. This is one of four required operations that can be performed on any DID ("Read"; the other ones being "Create", "Update", and "Deactivate"). The details of these operations differ depending on the DID method. Building on top of DID resolution, DID URL dereferencing is the process of retrieving a representation of a resource for a given DID URL. Software and/or hardware that is able to execute these processes is called a DID resolver.

This specification defines common requirements, algorithms including their inputs and results, architectural options, and various considerations for the DID resolution and DID URL dereferencing processes.

Note that while this specification defines some base-level functionality for DID resolution, the actual steps required to communicate with a DID's verifiable data registry are defined by the applicable DID method specification.

The difference between "resolving" a DID and "dereferencing" a DID URL is being thoroughly discussed by the community. E.g. see this comment.

Terminology

binding
A concrete mechanism through which a client invokes a DID resolver. This could be a local binding such as a local command line tool or library API, or a remote binding such as the HTTP(S) binding. See Section .
client
Software and/or hardware that invokes a DID resolver in order to execute the DID resolution and/or DID URL dereferencing algorithms. This invocation is done via a binding. The term client does not imply any specific network topology.
decentralized identifier (DID)
As defined in [[DID-CORE]].
DID controller
As defined in [[DID-CORE]].
DID document
As defined in [[DID-CORE]].
DID fragment
As defined in [[DID-CORE]].
DID method
As defined in [[DID-CORE]].
DID path
As defined in [[DID-CORE]].
DID query
As defined in [[DID-CORE]].
DID resolution
As defined in [[DID-CORE]]. See Section .
DID resolver
As defined in [[DID-CORE]].
DID resolution result
A data structure that represents the result of the DID resolution or DID URL dereferencing algorithm. May contain a DID document or other content. See Section .
DID URL
As defined in [[DID-CORE]].
DID URL dereferencing
As defined in [[DID-CORE]]. See Section .
local binding
A binding where the client invokes a DID resolver that runs on the same network host, e.g. via a local command line tool or library API. In this case, the DID resolver is sometimes also called a "local DID resolver". See Section .
remote binding
A binding where the client invokes a DID resolver that runs on a different network host, e.g. via the HTTP(S) binding. In this case, the DID resolver is sometimes also called a "remote DID resolver". See Section .
service endpoint
As defined in [[DID-CORE]].
service endpoint construction
An algorithm that takes a DID URL and a service, and constructs a service endpoint URL See Section .
unverifiable read
A low confidence implementation of a DID method's "Read" operation between the DID resolver and the verifiable data registry, to obtain the DID document. There is no guarantee about the integrity and correctness of the result. See Section .
verifiable data registry
As defined in [[DID-CORE]].
verifiable read
A high confidence implementation of a DID method's "Read" operation between the DID resolver and the verifiable data registry, to obtain the DID document. There are guarantees about the integrity and correctness of the result to the extent possible under the applicable DID method. See Section .

Resolving a DID

This section defines an algorithm for DID resolution, based on the abstract functions resolve() and resolveRepresentation() as defined in section DID Resolution in [[DID-CORE]]:

resolve ( did, resolutionOptions )
     -> ( didResolutionMetadata, didDocument, didDocumentMetadata )

resolveRepresentation ( did, resolutionOptions )
     -> ( didResolutionMetadata, didDocumentStream, didDocumentMetadata )

Algorithm

The following DID resolution algorithm MUST be implemented by a conformant DID resolver.

  1. Validate that the input DID conforms to the `did` rule of the DID Syntax. If not, the DID resolver MUST return the following result:
    1. didResolutionMetadata: «[ "error" → "invalid-did" ]»
    2. didDocument: null
    3. didDocumentMetadata: null
  2. Determine if the DID method of the input DID is supported by the DID resolver that implements this algorithm. If not, the DID resolver MUST return the following result:
    1. didResolutionMetadata: «[ "error" → "method-not-supported" ]»
    2. didDocument: null
    3. didDocumentMetadata: null
  3. Obtain the DID document for the input DID by executing the Read operation against the input DID's verifiable data registry, as defined by the input DID method:
    1. Besides the input DID, all additional resolution options of this algorithm MUST be passed to the Read operation of the input DID method.
    2. If the input DID does not exist, return the following result:
      1. didResolutionMetadata: «[ "error" → "not-found" ]»
      2. didDocument: null
      3. didDocumentMetadata: «[ ]»
    3. If the input DID has been deactivated, return the following result:
      1. didResolutionMetadata: «[ ]»
      2. didDocument: null
      3. didDocumentMetadata: «[ "deactivated" → true ]»
    4. The result of the Read operation is called the output DID document.
  4. Validate that the output DID document conforms to a conformant representation of the DID document data model. If not, the DID resolver MUST raise an error.

There is discussion how a DID that has been deactivated should be treated during the DID resolution process.

Specify how signatures/proofs on a DID document should be verified during the DID resolution process.

Should we define functionality that enables discovery of the list of DID methods or other capabilities that are supported by a DID resolver? Or is this implementation-specific and out-of-scope for this spec? E.g. see here and here.

Dereferencing a DID URL

This section defines an algorithm for DID URL dereferencing, based on the abstract function dereference() as defined in section DID URL Dereferencing in [[DID-CORE]]:

dereference ( didUrl, dereferenceOptions )
     -> ( dereferencingMetadata, contentStream, contentMetadata )

Algorithm

The following DID URL dereferencing algorithm MUST be implemented by a conformant DID resolver. In accordance with [[RFC3986]], it consists of the following steps: Resolving the DID, dereferencing the primary resource, and dereferencing the secondary resource (only if the input DID URL contains a DID fragment:

  1. Obtain the DID document for the input DID by executing the DID resolution algorithm as defined in . All DID parameters of the input DID URL MUST be passed as resolution options to the DID Resolution algorithm. If the input DID does not exist, return a null result. Otherwise, the result is called the resolved DID document.
  2. If present, separate the DID fragment from the input DID URL. Execute the algorithm for , with the input DID URL adjusted accordingly.
  3. If the original input DID URL contained a DID fragment, execute the algorithm for .

Dereferencing the Primary Resource

  1. If the input DID URL contains the DID parameter service and optionally the relativeRef DID parameter:
    did:example:1234?service=files&relativeRef=%2Fmyresume%2Fdoc%3Fversion%3Dlatest
    1. From the resolved DID document, select the service endpoint whose id property contains a fragment which matches the value of the service DID parameter of the input DID URL. This is called the input service endpoint.
    2. Execute the Service Endpoint Construction algorithm:
      1. Read the value of the serviceEndpoint property of the input service endpoint. This is called the input service endpoint URL.
      2. Pass the input DID URL and input service endpoint URL to the Service Endpoint Construction algorithm.
      3. The result is called the output service endpoint URL.
    3. Return the output service endpoint URL.
  2. There have been discussions whether in addition to the DID parameter service, there could also be a DID parameter service-type to select services based on their type rather than ID. See comments by Dave Longley about `service-type`.

  3. Otherwise, if the input DID URL contains no DID path and no DID query:
    did:example:1234
    1. Return the resolved DID document.
  4. Otherwise, if the input DID URL contains a DID path and/or DID query:
    did:example:1234/custom/path?customquery
    1. The applicable DID method MAY specify how to dereference the input DID URL.
    2. The client MAY be able to dereference the input DID URL in an application-specific way.
  5. If neither this algorithm, nor the applicable DID method, nor the client is able to dereference the input DID URL:
    1. Return a null result.

Dereferencing the Secondary Resource

If the input DID URL contains a DID fragment, then dereferencing of the secondary resource identified by the URL is dependent not on the URI scheme, but on the media type ([[RFC2046]]) of the primary resource, i.e. on the result of .

  1. If the result of is a resolved DID document with media type application/did+ld+json, and the input DID URL contains a DID fragment:
    did:example:1234#keys-1
    1. From the resolved DID document, select the JSON-LD object whose id property matches the input DID URL, e.g., a public key or service endpoint in the DID document. This is called the output resource. When selecting the JSON-LD object from the DID document, the absolute DID URL used to identify a graph node MUST be unique and present only once in the DID document. If the identifier of the graph node is not unique, including if a relative or base IRI mapped to an absolute IRI collides with a different graph node's absolute IRI, then an error MUST be thrown.
    2. Return the output resource.

      Mention relative IRIs and that the DID itself is considered the base IRI for the JSON-LD parser. Mention potential attack vector if @base is injected into the DID document.

      Also see this discussion on fully qualified DID URLs as the value of the id field.

      This use of the DID fragment is consistent with the definition of the fragment identifier in [[RFC3986]]. It identifies a secondary resource which is a subset of the primary resource (the DID document).

      This use of the DID fragment is furthermore consistent with the concept of Hash URIs for the Semantic Web [[COOL-URIS]].

      Perhaps we can find a good reference somewhere from RDF, JSON-LD or Solid specifications that defines clearly the ability to use the fragment for identifying a specific resource in an RDF document.

  2. Otherwise, if the result of is an output service endpoint URL, and the input DID URL contains a DID fragment:
    did:example:1234?service=files&relativeRef=%2Fmyresume%2Fdoc%3Fversion%3Dlatest#intro
    1. Append the DID fragment to the output service endpoint URL. In other words, the output service endpoint URL "inherits" the DID fragment of the input DID URL.
    2. Return the output service endpoint URL.
    3. This behavior of the DID fragment is analogous to the handling of a fragment in an HTTP URL in the case when dereferencing it returns an HTTP 3xx (Redirection) response with a Location header (see section 7.1.2 of [[RFC7231]].

  3. Otherwise, dereference the secondary resource as defined by the media type ([[RFC2046]]) of the primary resource.

Examples

Given the following input DID URL:

did:example:123456789abcdefghi#keys-1

... and the following resolved DID document:

{
	"@context": "https://www.w3.org/ns/did/v1",
	"id": "did:example:123456789abcdefghi",
	"verificationMethod": [{
		"id": "did:example:123456789abcdefghi#keys-1",
		"type": "Ed25519VerificationKey2018",
		"controller": "did:example:123456789abcdefghi",
		"publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
	}],
	"service": [{
		"id": "did:example:123456789abcdefghi#agent",
		"type": "AgentService",
		"serviceEndpoint": "https://agent.example.com/8377464"
	}, {
		"id": "did:example:123456789abcdefghi#messages",
		"type": "MessagingService",
		"serviceEndpoint": "https://example.com/messages/8377464"
	}]
}

... then the result of the algorithm is the following output resource:

{
	"@context": "https://www.w3.org/ns/did/v1",
	"id": "did:example:123456789abcdefghi#keys-1",
	"type": "Ed25519VerificationKey2018",
	"controller": "did:example:123456789abcdefghi",
	"publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
}

Given the following input DID URL and the same resolved DID document as above:

did:example:123456789abcdefghi?service=messages&relativeRef=%2Fsome%2Fpath%3Fquery#frag

... then the result of the algorithm is the following output service endpoint URL:

https://example.com/messages/8377464/some/path?query#frag
Diagram showing how a DID URL can be dereferencing to a service endpoint URL
Dereferencing a DID URL to a service endpoint URL.

Change the diagram and/or examples to make them consistent.

DID Resolution Architectures

TODO: Describe how DID resolvers are implemented and used, describe the relevance of DID methods. Explain the difference between "method architectures" and "resolver architectures".

Method Architectures

The DID resolution algorithm involves executing the Read operation on a DID according to its DID method (see ).

The mechanics of the "Read" operation can vary considerably between DID methods. In particular, no assumption should be made that:

  • ... an immutable blockchain is used as (part of) the verifiable data registry.
  • ... interaction with a remote network is required during execution of the "Read" operation.
  • ... an actual DID document is stored in plain-text on a verifiable data registry, or that the DID document can simply be retrieved via a standard protocol such as HTTP(S). While some DID methods may define their "Read" operation this way, others may define more complex multi-step processes that involve on-the-fly construction of a "virtual" DID document.

As an example, mention what it means to "resolve" peer/off-ledger/microledger/edgechain DIDs (e.g. see [[DID-PEER]] and here).

As an example, mention what it means to "resolve" DIDs that are simply wrapped public keys (e.g. see [[DID-KEY]] and here).

Depending on the exact nature of the DID method's "Read" operation, the interaction between a DID resolver and the verifiable data registry may be implemented as a verifiable read or unverifiable read:

Diagram showing a 'verifiable read' implementation of a DID method.
A verifiable read implementation of a DID method.
Diagram showing an 'unverifiable read' implementation of a DID method.
An unverifiable read implementation of a DID method.

A verifiable read maximizes confidence in the integrity and correctness of the result of the "Read" operation ‐ to the extent possible under the applicable DID method. It can be implemented in a variety of ways, for example:

An unverifiable read does not have such guarantees and is therefore less desirable, for example:

Whether or not a verifiable read is possible depends not only on a DID method itself, but also on the way how a DID resolver implements it. DID methods MAY define multiple different ways of implementing their "Read" operation(s) and SHOULD offer guidance on how to implement a verifiable read in at least one way.

The guarantees associated with a verifiable read are still always limited by the architectures, protocols, cryptography, and other aspects of the underlying verifiable data registry. The strongest forms of verifiable read implementations are considered those that do not require any interaction with a remote network at all (for example, see [[DID-KEY]]), or that minimize dependencies on specific network infrastructure and reduce the "root of trust" to proven entropy and cryptography alone (for example, see [[KERI]]).

TODO: Describe how a client can potentially verify the result of a "Read" operation independently even if it does not trust the DID resolver (e.g. using state proofs).

A DID resolver MUST support the DID resolution algorithm for at least one DID method and MAY support it for multiple DID methods:

Diagram showing a DID resolver that supports multiple DID methods.
A DID resolver that supports multiple DID methods.

In this case, the above considerations about verifiable read and unverifiable read implementations apply to each supported DID method individually.

Resolver Architectures

The algorithms for DID resolution and DID URL dereferencing are defined as abstract functions (see and ).

Those algorithms are implemented by DID resolvers. A DID resolver is invoked by a client via a binding. bindings define how the abstract functions are realized using concrete programming or communication interfaces. It is possible to distinguish between local bindings (such as a local command line tool or library API) and remote bindings (such as the HTTP(S) binding).

Diagram showing a DID resolver with a 'local binding'.
A local binding for a DID resolver.
Diagram showing a DID resolver with a 'remote binding'.
A remote binding for a DID resolver.

TODO: Describe local bindings vs. remote bindings, and implications for privacy, security and trust.

Also describe mitigations against potential downsides of remote bindings, e.g.:

TODO: Discuss DID resolution in constrained user agents such as mobile apps and browsers.

The following diagram shows how the resolve() and resolveRepresentation() functions use production and consumption rules of DID document representation can apply in an architecture that involves both a local resolver and a remote resolver.

Diagram showing a local and remote DID resolver executing the resolve() and resolveRepresentation() functions.
Production and consumption in an architecture that involves both a local and a remote DID resolver.

Proxied Resolution

A DID resolver MAY invoke another DID resolver, which serves as a proxy that executes the DID resolution algorithm as defined in .

The first DID resolver then acts as a client and chooses a suitable binding for invoking the second DID resolver. For example, a DID resolver may be invoked via a local binding (such as a command line tool), which in turn invokes another DID resolver via a remote binding (such as the HTTP(S) binding).

Diagram showing two DID resolvers, one invoked via 'local binding', the other invoked via 'remote binding'.
A client invokes a DID resolver via local binding which invokes another DID resolver via remote binding, which in turn supports resolving multiple DID methods.

This is similar to a "stub resolver" invoking a "recursive resolver" in DNS architecture, although the concepts are not entirely comparable (DNS Resolution uses a single concrete protocol, whereas DID resolution is an abstract function realized by different DID methods and different bindings).

Client-Side Dereferencing

Different parts of the DID URL dereferencing algorithm may be performed by different components of a Resolver Architecture.

Specifically, when a DID URL with a DID fragment is dereferenced, then Dereferencing the Primary Resource is done by the DID resolver, and Dereferencing the Secondary Resource is done by the client.

Example: Given the DID URL did:xyz:1234#keys-1, a DID resolver could be invoked via local binding for Dereferencing the Primary Resource (i.e. the DID document), and the client could complete the DID URL dereferencing algorithm by Dereferencing the Secondary Resource (i.e. a part of the DID document).

Diagram showing client-side dereferencing of a DID URL by a DID resolver and a client
Client-side dereferencing of a DID URL by a DID resolver and a client.

Example: Given the DID URL did:xyz:1234#keys-1, a DID resolver could be invoked via local binding which invokes another DID resolver via remote binding for Dereferencing the Primary Resource (i.e. the DID document), and the client could complete the DID URL dereferencing algorithm by Dereferencing the Secondary Resource (i.e. a part of the DID document).

Diagram showing client-side dereferencing of a DID URL by two DID resolvers and a client
Client-side dereferencing (in combination with Proxied Resolution) of a DID URL by two DID resolvers and a client.

Example: Given the DID URL did:xyz:1234?service=agent&relativeRef=%2Fsome%2Fpath%3Fquery#frag, a DID resolver could be invoked for Dereferencing the Primary Resource (i.e. a service endpoint URL), and the client could complete the DID URL dereferencing algorithm by Dereferencing the Secondary Resource (i.e. a service endpoint URL with a fragment).

Diagram showing client-side dereferencing of a DID URL by a DID resolver and a client
Client-side dereferencing of a DID URL by a DID resolver and a client.

DID Resolution Result

This section defines a data structure that represents the result of the algorithms described in and . A DID resolution result contains a DID document as well as DID resolution metadata and DID document metadata.

The media type of this data structure is defined to be `application/ld+json;profile="https://w3id.org/did-resolution"`.

Example

{
	"@context": "https://w3id.org/did-resolution/v1",
	"didDocument": {
		"@context": "https://www.w3.org/ns/did/v1",
		"id": "did:example:123456789abcdefghi",
		"authentication": [{
			"id": "did:example:123456789abcdefghi#keys-1",
			"type": "Ed25519VerificationKey2018",
			"controller": "did:example:123456789abcdefghi",
			"publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
		}],
		"service": [{
			"id":"did:example:123456789abcdefghi#vcs",
			"type": "VerifiableCredentialService",
			"serviceEndpoint": "https://example.com/vc/"
		}]
	},
	"didResolutionMetadata": {
		"contentType": "application/did+ld+json",
		"retrieved": "2024-06-01T19:73:24Z",
	},
	"didDocumentMetadata": {
		"created": "2019-03-23T06:35:22Z",
		"updated": "2023-08-10T13:40:06Z",
		"method": {
			"nymResponse": {
				"result": {
					"data": "{\"dest\":\"WRfXPg8dantKVubE3HX8pw\",\"identifier\":\"V4SGRU86Z58d6TV7PBUe6f\",\"role\":\"0\",\"seqNo\":11,\"txnTime\":1524055264,\"verkey\":\"H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV\"}",
					"type": "105",
					"txnTime": 1.524055264E9,
					"seqNo": 11.0,
					"reqId": 1.52725687080231475E18,
					"identifier": "HixkhyA4dXGz9yxmLQC4PU",
					"dest": "WRfXPg8dantKVubE3HX8pw"
				},
				"op": "REPLY"
			},
			"attrResponse": {
				"result": {
					"identifier": "HixkhyA4dXGz9yxmLQC4PU",
					"seqNo": 12.0,
					"raw": "endpoint",
					"dest": "WRfXPg8dantKVubE3HX8pw",
					"data": "{\"endpoint\":{\"xdi\":\"http://127.0.0.1:8080/xdi\"}}",
					"txnTime": 1.524055265E9,
					"type": "104",
					"reqId": 1.52725687092557056E18
				},
				"op": "REPLY"
			}
		}
	}
}

See corresponding open issue.

Need to define how this data structure works exactly, and whether it always contains a DID document or can also contain other results.

DID Document

A DID document associated with a DID. The result of .

DID Resolution Metadata

This is a metadata structure (see section Metadata Structure in [[DID-CORE]]) that contains metadata about the DID Resolution process.

This metadata typically changes between invocations of the DID Resolution functions as it represents data about the resolution process itself.

The source of this metadata is the DID resolver.

Examples of DID Resolution Metadata include:

See also section DID Resolution Metadata in [[DID-CORE]].

DID Document Metadata

This is a metadata structure (see section Metadata Structure in [[DID-CORE]]) that contains metadata about a DID Document.

This metadata typically does not change between invocations of the DID Resolution function unless the DID document changes, as it represents data about the DID document.

The sources of this metadata are the DID controller and/or the DID method.

Examples of DID Document Metadata include:

DID Document Metadata may also include method-specific metadata, e.g.:

See also section DID Document Metadata in [[DID-CORE]].

For certain data, it may be debatable whether it should be part of the DID document (i.e. data that describes the DID Subject), or whether it is metadata (i.e. data about the DID document or about the DID resolution process). For example the URL of the "Continuation DID document" in the BTCR method.

Bindings

This section defines bindings for the abstract algorithms in sections and .

HTTP(S) Binding

This section defines a DID resolver binding which exposes the DID resolution and/or DID URL dereferencing functions (including all resolution options and output data) via an HTTP(S) endpoint. See .

The HTTP(S) binding for DID resolvers requires a known HTTP(S) URL called the DID resolver HTTP(S) endpoint.

Using this binding, the DID resolution function (see ) and/or DID URL dereferencing function (see ) can be executed as follows:

  1. Initialize a request HTTP(S) URL with the DID resolver HTTP(S) endpoint.
    1. Append the input DID or input DID URL to the request HTTP(S) URL. Certain characters MUST be percent-encoded (as specified in RFC3986 Section 2.1).
    2. Encode the accept input metadata property as the Accept HTTP header in the request.
    3. Encode all other resolution options as query parameters in the request HTTP(S) URL.
  2. Execute an HTTP GET request on the request HTTP(S) URL.
  3. Dereference the input DID or input DID URL by executing the DID URL dereferencing algorithm as defined in
  4. If the output of the DID URL dereferencing function contains the did-dereferencing-metadata with the property error with value invalid-didUrl:
    1. The HTTP response status code MUST be 400.
  5. If the output of the DID URL dereferencing function contains the did-dereferencing-metadata property error with value not-found:
    1. The HTTP response status code MUST be 404.
  6. If the output of the DID URL dereferencing function contains the did-dereferencing-metadata property error with value representation-not-supported:
    1. The HTTP response status code MUST be 406.
  7. If the output of the DID URL dereferencing function contains the didDocumentMetadata property deactivated with value true:
    1. The HTTP response status code MUST be 410.
  8. If the output of the DID URL dereferencing function contains the didDocumentStream:
    1. If the value of the Accept HTTP header is absent or `application/did+ld+json` (or other media type of a conformant representation of a DID document):
      1. The HTTP response status code MUST be 200.
      2. The HTTP response MUST contain a Content-Type header. The value of this header MUST be `application/did+ld+json` (or other media type of a conformant representation of a DID document).
      3. The HTTP response body MUST contain the didDocumentStream, in the representation corresponding to the Accept HTTP header.
    2. If the value of the Accept HTTP header is `application/ld+json;profile="https://w3id.org/did-resolution"`:
      1. Produce a DID resolution result (see (see ) and populate it with the didDocumentStream, didResolutionMetadata, and didDocumentMetadata that are the output of the DID resolution function.
      2. The HTTP response status code MUST be 200.
      3. The HTTP response MUST contain a Content-Type header. The value of this header MUST be `application/ld+json;profile="https://w3id.org/did-resolution"`.
      4. The HTTP response body MUST contain the produced DID resolution result.
  9. If the output of the DID URL dereferencing function is a service endpoint URL:
    1. The HTTP response status code MUST be 303.
    2. The HTTP response MUST contain an Location header. The value of this header MUST be the output service endpoint URL.

TODO: Review HTTP(S) binding for DID resolution and DID URL dereferencing, including the following topics:

  • How are resolution options passed via HTTP(S)? Using the query string and/or HTTP headers?
  • How is the output data (DID document, DID resolution result) returned via HTTP(S)?
  • How should Accept and Content-Type HTTP headers be used? How are the resolve() and resolveRepresentation() functions called? See this issue for a discussion.
  • Are two separate HTTP(S) endpoints required/allowed for the resolve() and dereference() functions, or can/must a single HTTP(S) endpoint be used?

Example

Given the following DID resolver HTTP(S) endpoint:

https://dev.uniresolver.io/1.0/identifiers/

And given the following input DID:

did:sov:WRfXPg8dantKVubE3HX8pw

Then the request HTTP(S) URL is:

https://dev.uniresolver.io/1.0/identifiers/did:sov:WRfXPg8dantKVubE3HX8pw

The HTTP(S) binding can be invoked as follows:

curl -X GET https://uniresolver.io/1.0/identifiers/did:sov:WRfXPg8dantKVubE3HX8pw

Service Endpoint Construction

This section defines the inputs and the algorithm of Service Endpoint Construction, which returns a service endpoint URL as output. This algorithm is used when service endpoints are selected during DID URL dereferencing (see ).

In this section, path, query, and fragment are understood as defined in [[RFC3986]].

Input

The inputs of the Service Endpoint Construction algorithm are an input DID URL and an input service endpoint URL.

The requirements for the inputs of the Service Endpoint Construction algorithm are as follows:

Algorithm

  1. Initialize a string output service endpoint URL to the value of the input service endpoint URL
  2. If the output service endpoint URL has a query component, remove it.
  3. If the output service endpoint URL has a fragment component, remove it.
  4. Append the path component of the input DID URL to the output service endpoint URL.
  5. If the input service endpoint URL has a query component, append ? plus the query to the output service endpoint URL.
  6. If the input DID URL has a query component, append ? plus the query to the output service endpoint URL.
  7. If the input service endpoint URL has a fragment component, append # plus the fragment to the output service endpoint URL.
  8. If the input DID URL has a fragment component, append # plus the fragment to the output service endpoint URL.
  9. Return the output service endpoint URL.

We could potentially allow a query components on both the input DID URL and input service endpoint URL, if they both contain lists of key/value parameters that can be merged.

Details of the Service Endpoint Construction algorithm have been discussed in April 2019 on the CCG mailing list, e.g. here or here.

Instead of defining our own algorithm, we could potentially re-use the "Relative Resolution" algorithm defined in [[RFC3986]].

Example

Given the following input service endpoint URL:

https://example.com/messages/8377464

And given the following input DID URL:

did:example:123456789abcdefghi?service=messages&relativeRef=%2Fsome%2Fpath%3Fquery#frag

Then the output service endpoint URL is:

https://example.com/messages/8377464/some/path?query#frag

Errors

Do we need to define a list of error conditions, codes, etc.

Security and Privacy Considerations

Authentication/Authorization

DID resolution and DID URL dereferencing do not involve any authentication or authorization functionality. Similar to DNS resolution, anybody can perform the process, without requiring any credentials or non-public knowledge.

Explain that DIDs are not necessarily globally resolvable, such as pairwise or N-wise "peer" DIDs.

See [[RFC3339]]: URIs have a global scope and are interpreted consistently regardless of context, though the result of that interpretation may be in relation to the end-user's context.

An advanced idea is that the result of DID resolution could be contextual or depend on policies, see this comment.

A related topic is whether (parts of) DID document could be encrypted, e.g. see w3c/did-core/issues/25. Also see the use of the fragment in the IPID DID method.

Caching

A DID resolver may maintain a generic cache of DID documents. It may also maintain caches specific to certain DID methods.

The no-cache resolution option can be used to request a certain kind of caching behavior.

This resolution option is OPTIONAL.

Possible values of this property are:

Caching behavior can be controlled by configuration of the DID resolver, by the no-cache resolution option, or by contents of the DID document (e.g. a `time-to-live` field), or by a combination of these properties.

See corresponding open issue.

Perhaps we can re-use caching mechanisms of other protocols such as HTTP.

Versioning

If a versionId or versionTime DID parameter is provided, the DID resolution algorithm returns a specific version of the DID document.

The DID parameters versionId and versionTime are mutually exclusive.

The use of the versionId DID parameter is specific to the DID method. Its possible values may include sequential numbers, random UUIDs, content hashes, etc..

DID document metadata MAY contain a versionId property that changes with each Update operation that is performed on a DID document.

While most DID methods support the Update operation, there is no requirement for DID methods to keep all previous DID document versions, therefore not all DID methods support versioning.

See corresponding open issue.

Non-DID Identifiers

There is discussion on the relationship between DID resolution and resolution of non-DID identifiers such as domain names, HTTP URIs, or e-mail addresses. This includes the questions how DIDs can be discovered from non-DID identifiers, and how links between identifiers can be verifiable.

DID Method Governance

Describe which methods a DID resolver should support, and potential implications.

Future Work

This section lists additional DID URL dereferencing features that are under discussion and have not yet been incorporated into the algorithm.

Redirect

A service endpoint may have a serviceEndpoint property with a value that is itself a DID. This is interpreted as a "DID redirect" from the input DID to another. In this case, a "child" DID resolution process can be launched to get to a "final" service endpoint.

The follow-redirect resolution option can be supplied by a client as a hint to instruct whether redirects should be followed. This resolution option is OPTIONAL.

See corresponding open issue.

DID redirects could not only apply to a single service endpoint, but to an entire DID document, therefore enabling portability use cases.

{
   "id": "did:example:123456789abcdefghi#hub1",
   "type": "HubService",
   "serviceEndpoint": "did:example:xyz"
}

Proxy

A DID document may contain a "proxy" service type which would provide a mapping that needs to be followed in order to resolve to a final service URL.

{
   "id": "did:example:123456789abcdefghi",
   "type": "ProxyService",
   "serviceEndpoint": "https://mydomain.com/proxy"
}

JSON Pointer

Several ways of selecting parts of a DID document are being discussed, including the use of JSON pointer.

See corresponding PRs here and here.

DID Resolution Resources

  1. DID resolvers in DID Core specification
  2. Universal Resolver
  3. did-client
  4. uPort DID resolver