w3c-ccg / did-spec

Please see README.md for latest version being developed by W3C DID WG.
https://w3c.github.io/did-core/
Other
124 stars 45 forks source link

Inconsistent ABNF and related definitions #170

Closed jandrieu closed 5 years ago

jandrieu commented 5 years ago

TLDR: The ABNF and related logical elements of a DID are inconsistently defined.

The current pull request refactoring the ABNF rules does not address the issue I'm raising here. https://github.com/w3c-ccg/did-spec/pull/168

My first point is that the charter isn't about defining a DID reference. It's about defining a DID. The current spec defines a DID as merely a component in a DID reference.

My second point is that a DID should include the entirety of the string that is presented, just like a URL includes the query part and and fragment part. https://tools.ietf.org/html/rfc3986 The current spec, with its definition of a DID as a component in a did-reference, a URI of the following form would NOT be a DID per the spec:

did:example:123456789abcdefghi#keys-1

Per the current spec (and the PR) this would be a DID-reference, not a DID. Only the first part is a DID. This is stated explicitly:

The generic DID scheme is a URI scheme conformant with [RFC3986]. It consists of a DID followed by an optional path and/or fragment. The term DID refers only to the identifier conforming to the did rule in the ABNF below; when used alone, it does not include a path or fragment. A DID that may optionally include a path and/or fragment is called a DID reference.

Even if one would prefer to follow the notion that the DID is "only the identifier", then this statement might be correct if rewritten as

The generic DID-reference scheme is a URI scheme conformant with [RFC3986]. It consists of a DID followed by an optional path and/or fragment.

However, this seems inconsistent with the last statement in that paragraph:

A DID that may optionally include a path and/or fragment is called a DID reference.

This sentence is logically impossible. A "DID" that includes a path or fragment is NOT a DID. It is a did-reference. It is that, not that it is called that. Further, by the previous statements, DIDs may not optionally include a path and/or fragment.

This is also out of sync with current consensus in the way we speak of DIDs. As illustrated in the last paragraph, we consistently refer to did-references as DIDs. From Section 4.3:

It is desirable that we enable tree-based processing of DIDs that include DID fragments (which resolve directly within the DID document) to locate metadata contained directly in the DID document or the service resource given by the target URL without needing to rely on graph-based processing.

Again, if "DIDs" can contain DID fragments, then by the above (problematic) language and the ABNF, that "DID" is actually a DID reference which by definition can't be true given the current ABNF.

My third point is that the did-reference spec looks like the URI spec, but is fundamentally different. From the current spec:

did-reference      = did [ "/" did-path ] [ "#" did-fragment ]
did                = "did:" method ":" specific-idstring

However, this is significantly different from the generic URI syntax (RFC3986)

URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

And further breaks with this URI-reference spec in RFC3986. It makes DID-references something other than URI-references, which makes DIDs something other than URIs.

URI-reference = URI / relative-ref

A URI-reference is either a URI, or a relative-ref and a relative-ref has the following syntax:

      relative-ref  = relative-part [ "?" query ] [ "#" fragment ]

      relative-part = "//" authority path-abempty
                    / path-absolute
                    / path-noscheme
                    / path-empty

If we attempt to follow that pattern more closely (yet combining the query & fragment parts to remove redundancy), I propose:

did = "did:" method specific-idstring relative-part 
method             = 1*methodchar
methodchar         = %x61-7A / DIGIT
specific-idstring  = idstring *( ":" idstring )
idstring           = 1*idchar
idchar             = ALPHA / DIGIT / "." / "-"
relative-part = path-part [ "?" query] [ "#" fragment ]
path-part = / path-absolute
                    / path-empty
did-reference = DID / relative-part

[Yes, this is incomplete. I leave query and fragment as an exercise for the editors. Pull them in from the RFC3986]

With this definition, a DID-reference is a URI-reference where the query term is the name of a service used for endpoint discovery by the user-agent. It is aligned with how URI-references are used. This implies that fragments should NOT be used to indicate dereferencing a DID to the resource at the end of a service endpoint, but rather to refer to the element itself (within the DID Document). Only the query term is interpreted as implying the further dereference.

Unfortunately, if service (from did-spec) is reasonably replaced with query (from the URI spec), then we still have the question of what the path part does. The current spec says

A DID path SHOULD be used to address resources available via a DID service endpoint.

If I follow the ideas of Sam Smith and DADs, then the path part would allow hierarchical indexing to provide resolution to an subset of a DID Document rather than the root of the DID Document. This would be a distinct from the query/service component which is for discovering the named service endpoint for a given DID id/path reference. Which is to say, I think this remains a point of significant ambiguity in the feature space (what is the path part)--and not just a grammatical error. I'm not sure I have a recommendation in this area. I don't know of any implementations that use such hierarchies other than what I recall from DADs--and I believe those may be addresses on a method-specific basis with colon ":" delimited identifiers.

Additionally, the section on fragments has this gem:

It is desirable that we enable tree-based processing of DIDs that include DID fragments (which resolve directly within the DID document) to locate metadata contained directly in the DID document or the service resource given by the target URL without needing to rely on graph-based processing.

This paragraph is ambiguous as to whether or not a fragment is a reference within the context of the document, as suggested by " (which resolve directly within the DID document)" or if it can reference something within the service endpoint, as suggested by "to locate metadata contained directly in the DID document or the service resource". I take this to mean that if the DID-reference (aka DID) contains a service (aka query), then any fragment reference is to be appended to the service endpoint for dereferencing in the context of that service endpoint. I can see the appeal of this. However, it presumes a certain understanding and stability of the structure of the named endpoint and could easily result in an invalid URI if the service endpoint already has a fragment. Further, it is doubly ambiguous when a fragment is used to refer to a service endpoint, as seems to be the proposal in the PR.

Rather, I would use the query part to look up the service, and when dereferencing the service endpoint, and then applying the fragment in the context of the dereferenced endpoint at lease uses a valid URL (just one fragment).

For example, using Example 8 from the spec https://w3c-ccg.github.io/did-spec/#example-8-various-service-endpoints

"service": [{
    "id": "did:example:123456789abcdefghi;openid",
    "type": "OpenIdConnectVersion1.0Service",
    "serviceEndpoint": "https://openid.example.com/"
  },

A relative part (query and fragment) of ?did:example:123456789abcdefghi;openid would dereference to the open id endpoint.

This is different from both the current spec--with its ambiguity around what the ";" is for (it is in the service section but not in the ABNF). And the PR mentioned above, which creates some new elements, which IMO are unnecessary and confusing as well as using fragments to refer to services.

Further, the current spec and proposed PR both use absolute URIs for service endpoint ids, but the PR says "the service path [is] a URI path and MUST conform to the ABNF of the path-rootless ABNF rule in [[RFC3986]]" Unfortunately, this is logically impossible. It is either a URI path (which can be a path-abempty, path-absolute, path-noscheme, path-rootless, or path-empty), or it is a path-rootless.

I may have mis-parsed the ABNF, but the current use of the service endpoints is inconsistent with how fragments work in other URIs, especially in URLs. For the sake of this example, let's revisit the above example (from Section 8. Examples) and just focus on the id of the first service endpoint:

"id": "did:example:123456789abcdefghi;openid"

which, in the PR is changed to

"id": "did:example:123456789abcdefghi#openid"

If we were to use a standard URL to refer to an element with that id in an HTML page (http://example.com), we would use either the absolute URL http://example.com#did:example:123456789abcdefghi;openid from the spec, or http://example.com#did:example:123456789abcdefghi#openid from the PR.

If we apply that pattern to a service identifier in the DID Document resolved by did:example:123456789abcdefghi, then the analogous URL would be did:example:123456789abcdefghi#did:example:123456789abcdefghi;openid for the original spec and did:example:123456789abcdefghi#did:example:123456789abcdefghi#openid for the PR.

Unfortunately, these PR URIs are invalid, because they contain two fragments, and all four are unnecessarily redundant.

In contrast, what I believe is the desired original DID is something like

did:example:123456789abcdefghi#openid

Which would refer to the openid service endpoint declaration in the DID Document and, based on my proposal,

did:example:123456789abcdefghi?openid

Would actually dereference the service at the endpoint.

This is not only a valid URI, it's concise and straightforward. In order to have that URI be consistent with how other URI fragments map to the ids in a document, the service endpoint should in the example 8 should be:

"service": [{
    "id": "openid",
    "type": "OpenIdConnectVersion1.0Service",
    "serviceEndpoint": "https://openid.example.com/"
  },

My comments therefore are in two parts:

  1. The grammar of the current ABNF is inconsistent with itself, with URIs, and with how we talk about DIDs. This lack of rigor is especially problematic in ABNF which is there precisely to be rigorous because the rest of the document suffers from the inherent ambiguity in human language.
  2. The logic of the current DID components are inconsistent with their similarly named parts in the URI spec. I propose that "path", "query", and "fragment" are better terms if they have slightly different definitions: a. path: like a URI path, a hierarchical index into the DID document b. query: the name of a service endpoint for discovery (and eventual dereferencing) c. fragment: a named index into the DID document, hierarchically constrained by the path
  3. Seems like a the query part should follow RFC3986 def of queries, not path-rootless.

My apologies this is so long.

I'd like @burnburn and @ChristopherA to comment on this.

talltree commented 5 years ago

Joe,

It is ironic that just before I read your message (I was at IBM Think all last week so tonight was going through my backlog of CCG email from oldest to newest), I had read Dmitri's proposed revisions to the ABNF and posted that I liked it.

I don't have time now to answer every point in your post, but let me at least address your top-level point about the parallelism (or lack thereof) between the DID ABNF and the URI ABNF. Specifically, in RFC 3986, you are referring to these rules:

URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

URI-reference = URI / relative-ref

relative-ref = relative-part [ "?" query ] [ "#" fragment ]

relative-part = "//" authority path-abempty / path-absolute / path-noscheme / path-empty

The reason for the separation of "URI" and "URI-reference" is that in a spec you are required to use the URI rule if you need absolute URI (one that is fully qualified and not relative to another root URI), but if your spec allows either an absolute or relative URI, you can use to the URI-reference rule.

When we were writing the first DID spec two years ago, we definitely wanted this new class of identifier to be a valid URI scheme, and thus conformant to the URI spec. And, per your suggestion, we wanted to re-use (and thus not redefine) as many RFC 3986 ABNF rules as possible.

What we realized was that with DIDs, the only part of the URI spec that we needed to constrain was the hier-part rule. So we focused on just that, and defined *a DID as a URI that has the scheme "did:" plus the *hier-part defined in the DID ABNF.

Then we took the short cut of defining everything else you could base on a DID (i.e., the addition of a path, query or fragment—OR the use of those relative to a DID) as a did-reference.

I have since realized that it was a mistake to call "everything else" a DID-reference because, as you point out, it breaks the parallelism with the URI spec, where URI-reference only refers to either an absolute or relative URI.

So we need to fix that. But I would propose that the solution is not to rename what we have been calling a "DID" (I think there are a boatload of reasons to keep that as the precise term for what is currently defined in the ABNF), but to rename we have been calling "did-reference" to re-establish the parallels with RFC 3986.

Here's what I propose (the first six lines are identical to Dmitri's):

did = "did:" method ":" method-specific-idstring method = 1methodchar methodchar = %x61-7A / DIGIT method-specific-idstring = idstring ( ":" idstring ) idstring = 1idchar idchar = ALPHA / DIGIT / "." / "-"*

absolute-did = did [ did-relative-ref ]

did-relative-ref = did-fragment-ref / did-service-ref

did-fragment-ref = did "#" fragment

did-service-ref = did [ ";" service-id ] [ path-abemtpy ] [ "?" query ] [ "#" fragment ]

service-id = ( ALPHA / DIGIT / "." / "-" / "_" )*

did-reference = absolute-did / did-relative-ref

Note that it's shorter than Dimitri's because, as you suggest, it re-uses all the rule names from RFC 3986 https://www.ietf.org/rfc/rfc3986.txt (any rule not defined above is from the ABNF in RFC 3986 Appendix A). That also reinforces that a DID is identical to all other URIs except for the hier-part.

My final point is that the treatment of DID service URLs (did-service-ref in the ABNF above) is very carefully designed not to interfere with the use of a normal path, query, or fragment on a URL—that's why we specify the service-id component to be part of the hier-part rule. It forces percent-encoding of the service ID string in a DID document (if that string is a URL) so that it doesn't contain any character not allowed in a hier-part—that's what avoids double queries or double fragments.

=Drummond

On Sat, Feb 16, 2019 at 1:58 PM Joe Andrieu notifications@github.com wrote:

TLDR: The ABNF and related logical elements of a DID are inconsistently defined.

The current pull request refactoring the ABNF rules does not address the issue I'm raising here. #168 https://github.com/w3c-ccg/did-spec/pull/168

My first point is that the charter isn't about defining a DID reference. It's about defining a DID. The current spec defines a DID as merely a component in a DID reference.

My second point is that a DID should include the entirety of the string that is presented, just like a URL includes the query part and and fragment part. https://tools.ietf.org/html/rfc3986 The current spec, with its definition of a DID as a component in a did-reference, a URI of the following form would NOT be a DID per the spec:

did:example:123456789abcdefghi#keys-1

Per the current spec (and the PR) this would be a DID-reference, not a DID. Only the first part is a DID. This is stated explicitly:

The generic DID scheme is a URI scheme conformant with [RFC3986]. It consists of a DID followed by an optional path and/or fragment. The term DID refers only to the identifier conforming to the did rule in the ABNF below; when used alone, it does not include a path or fragment. A DID that may optionally include a path and/or fragment is called a DID reference.

Even if one would prefer to follow the notion that the DID is "only the identifier", then this statement might be correct if rewritten as

The generic DID-reference scheme is a URI scheme conformant with [RFC3986]. It consists of a DID followed by an optional path and/or fragment.

However, this seems inconsistent with the last statement in that paragraph:

A DID that may optionally include a path and/or fragment is called a DID reference.

This sentence is logically impossible. A "DID" that includes a path or fragment is NOT a DID. It is a did-reference. It is that, not that it is called that. Further, by the previous statements, DIDs may not optionally include a path and/or fragment.

This is also out of sync with current consensus in the way we speak of DIDs. As illustrated in the last paragraph, we consistently refer to did-references as DIDs. From Section 4.3:

It is desirable that we enable tree-based processing of DIDs that include DID fragments (which resolve directly within the DID document) to locate metadata contained directly in the DID document or the service resource given by the target URL without needing to rely on graph-based processing.

Again, if "DIDs" can contain DID fragments, then by the above (problematic) language and the ABNF, that "DID" is actually a DID reference which by definition can't be true given the current ABNF.

My third point is that the did-reference spec looks like the URI spec, but is fundamentally different. From the current spec:

did-reference = did [ "/" did-path ] [ "#" did-fragment ]did = "did:" method ":" specific-idstring

However, this is significantly different from the generic URI syntax (RFC3986)

URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

And further breaks with this URI-reference spec in RFC3986. It makes DID-references something other than URI-references, which makes DIDs something other than URIs.

URI-reference = URI / relative-ref

A URI-reference is either a URI, or a relative-ref and a relative-ref has the following syntax:

  relative-ref  = relative-part [ "?" query ] [ "#" fragment ]

  relative-part = "//" authority path-abempty
                / path-absolute
                / path-noscheme
                / path-empty

If we attempt to follow that pattern more closely (yet combining the query & fragment parts to remove redundancy), I propose:

did = "did:" method specific-idstring relative-part method = 1methodcharmethodchar = %x61-7A / DIGITspecific-idstring = idstring ( ":" idstring )idstring = 1*idcharidchar = ALPHA / DIGIT / "." / "-"relative-part = path-part [ "?" query] [ "#" fragment ]path-part = / path-absolute / path-emptydid-reference = DID / relative-part

[Yes, this is incomplete. I leave query and fragment as an exercise for the editors. Pull them in from the RFC3986]

With this definition, a DID-reference is a URI-reference where the query term is the name of a service used for endpoint discovery by the user-agent. It is aligned with how URI-references are used. This implies that fragments should NOT be used to indicate dereferencing a DID to the resource at the end of a service endpoint, but rather to refer to the element itself (within the DID Document). Only the query term is interpreted as implying the further dereference.

Unfortunately, if service (from did-spec) is reasonably replaced with query (from the URI spec), then we still have the question of what the path part does. The current spec says

A DID path SHOULD be used to address resources available via a DID service endpoint.

If I follow the ideas of Sam Smith and DADs, then the path part would allow hierarchical indexing to provide resolution to an subset of a DID Document rather than the root of the DID Document. This would be a distinct from the query/service component which is for discovering the named service endpoint for a given DID id/path reference. Which is to say, I think this remains a point of significant ambiguity in the feature space (what is the path part)--and not just a grammatical error. I'm not sure I have a recommendation in this area. I don't know of any implementations that use such hierarchies other than what I recall from DADs--and I believe those may be addresses on a method-specific basis with colon ":" delimited identifiers.

Additionally, the section on fragments has this gem:

It is desirable that we enable tree-based processing of DIDs that include DID fragments (which resolve directly within the DID document) to locate metadata contained directly in the DID document or the service resource given by the target URL without needing to rely on graph-based processing.

This paragraph is ambiguous as to whether or not a fragment is a reference within the context of the document, as suggested by " (which resolve directly within the DID document)" or if it can reference something within the service endpoint, as suggested by "to locate metadata contained directly in the DID document or the service resource". I take this to mean that if the DID-reference (aka DID) contains a service (aka query), then any fragment reference is to be appended to the service endpoint for dereferencing in the context of that service endpoint. I can see the appeal of this. However, it presumes a certain understanding and stability of the structure of the named endpoint and could easily result in an invalid URI if the service endpoint already has a fragment. Further, it is doubly ambiguous when a fragment is used to refer to a service endpoint, as seems to be the proposal in the PR.

Rather, I would use the query part to look up the service, and when dereferencing the service endpoint, and then applying the fragment in the context of the dereferenced endpoint at lease uses a valid URL (just one fragment).

For example, using Example 8 from the spec https://w3c-ccg.github.io/did-spec/#example-8-various-service-endpoints

"service": [{ "id": "did:example:123456789abcdefghi;openid", "type": "OpenIdConnectVersion1.0Service", "serviceEndpoint": "https://openid.example.com/" },

A relative part (query and fragment) of ?did:example:123456789abcdefghi;openid#type

Would refer to "OpenIdConnectVersion1.0Service" While ?did:example:123456789abcdefghi;openid would dereference to the open id endpoint.

This is completely different from both the current spec--with its ambiguity around what the ";" is for (it is in the service section but not in the ABNF). And the PR mentioned above, which creates some new elements, which IMO are unnecessary and confusing as well as using fragments to refer to services.

Further, the current spec and proposed PR both use absolute URIs for service endpoint ids, but the PR says "the service path [is] a URI path and MUST conform to the ABNF of the path-rootless ABNF rule in [[RFC3986]]" Unfortunately, this is logically impossible. It is either a URI path (which can be a path-abempty, path-absolute, path-noscheme, path-rootless, or path-empty), or it is a path-rootless.

I may have mis-parsed the ABNF, but the current use of the service endpoints is inconsistent with how fragments work in other URIs, especially in URLs. For the sake of this example, let's revisit the above example (from Section 8. Examples) and just focus on the id of the first service endpoint:

"id": "did:example:123456789abcdefghi;openid"

which, in the PR is changed to

"id": "did:example:123456789abcdefghi#openid"

If we were to use a standard URL to refer to an element with that id in an HTML page (http://example.com), we would use either the absolute URL http://example.com#did:example:123456789abcdefghi;openid from the spec, or http://example.com#did:example:123456789abcdefghi#openid from the PR.

If we apply that pattern to a service identifier in the DID Document resolved by did:example:123456789abcdefghi, then the analogous URL would be did:example:123456789abcdefghi#did:example:123456789abcdefghi;openid for the original spec and did:example:123456789abcdefghi#did:example:123456789abcdefghi#openid for the PR.

Unfortunately, these PR URIs are invalid, because they contain two fragments, and all four are unnecessarily redundant.

In contrast, what I believe is the desired original DID is something like

did:example:123456789abcdefghi#openid

Which would refer to the openid service endpoint declaration in the DID Document and, based on my proposal,

did:example:123456789abcdefghi?openid

Would actually dereference the service at the endpoint.

This is not only a valid URI, it's concise and straightforward. In order to have that URI be consistent with how other URI fragments map to the ids in a document, the service endpoint should in the example 8 should be:

"service": [{ "id": "openid", "type": "OpenIdConnectVersion1.0Service", "serviceEndpoint": "https://openid.example.com/" },

My comments therefore are in two parts:

  1. The grammar of the current ABNF is inconsistent with itself, with URIs, and with how we talk about DIDs. This lack of rigor is especially problematic in ABNF which is there precisely to be rigorous because the rest of the document suffers from the inherent ambiguity in human language.
  2. The logic of the current DID components are inconsistent with their similarly named parts in the URI spec. I propose that "path", "query", and "fragment" are better terms if they have slightly different definitions: a. path: like a URI path, a hierarchical index into the DID document b. query: the name of a service endpoint for discovery (and eventual dereferencing) c. fragment: a named index into the DID document, hierarchically constrained by the path
  3. Seems like a the query part should follow RFC3986 def of queries, not path-rootless.

My apologies this is so long.

I'd like @burnburn https://github.com/burnburn and @ChristopherA https://github.com/ChristopherA to comment on this.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/w3c-ccg/did-spec/issues/170, or mute the thread https://github.com/notifications/unsubscribe-auth/ADLkTbUV_O9fURrWcMOBiRrZEoVaLh3gks5vOH8VgaJpZM4a_ODO .

jandrieu commented 5 years ago

A few questions, as I want to understand the motivation for the extra complexity I'm seeing.

First, you didn't respond to my surprise that

did:example:123456789abcdefghi#keys-1

Is, in fact, not a DID by your definition. This is extremely strange to me and I'm struggling to understand the motivation.

If this were transposed to be a url:

http://example.com/123456789abcdefghi#keys-1

Then this URL would be called a URL, as would

http://example.com/123456789abcdefghi

The URL is the entire string, including the query and fragment part. This is also true of the generic URI definition, and especially relevant in the context of assertions that DIDs are URIs, URLs, and sometimes act like URNs.

Why break that pattern?

To me the DID has always been the whole thing. Maybe that's because I've been focused on the user side of things and not reading the spec clearly, but I think we'll run into a lot of confusion across the W3C if the syntax for DIDs is so different from URIs and URLs.

Second is that I don't understand what you are trying to do with the query & fragment parts.

My final point is that the treatment of DID service URLs (did-service-ref in the ABNF above) is very carefully designed not to interfere with the use of a normal path, query, or fragment on a URL—that's why we specify the service-id component to be part of the hier-part rule. It forces percent-encoding of the service ID string in a DID document (if that string is a URL) so that it doesn't contain any character not allowed in a hier-part—that's what avoids double queries or double fragments.

By my understanding (and current re-read of the relevant sections of 3986), both query parts and fragment parts are percent-encoded with the exception of "/" and "?".

Could you help me understand what you're trying for here? After a few readings, it seems like you want to somehow embed a URL in the DID, when there really isn't any need to do that (there's no need for service ids to be URLs, especially when there is a service type, and a service endpoint, which probably is a URL). And if you really want it to be a URL, you can escape it.

Both the did-service-ref and did-fragment ref can contain fragments, but did-fragments can't contain queries, which seems odd. And by the above definition, I'm fairly sure the did-fragment-ref is not a valid uri-reference because it excluded queries. In fact, the did-relative-ref still includes the DID, making it not very relative at all.

In my attempt to map DIDs to URIs, using the same structure you started with

URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

I agree, all we need to do is customize the hier-part. But your proposal sticks the fragment part into the hier-part asymmetrically in two newly defined terms (did-service-ref and did-fragment-ref), one with a query part and one without, so I'm not seeing the continuity with URIs.

Note that the URI hier-part is

      hier-part   = "//" authority path-abempty
                  / path-absolute
                  / path-rootless
                  / path-empty

Consider the following ABNF, I believe you get good DIDs with the single quirk of how I would like to propose we handle service differently.

did = "did:" hier-part [ "?" query ] [ "#" fragment ]
hier-part   = authority path
path = path-abempty / path-absolute  / path-rootless  / path-empty
authority = method ":" method-specific-idstring 
method = 1*methodchar 
methodchar = %x61-7A / DIGIT 
method-specific-idstring = idstring *( ":" idstring ) 
idstring = 1*idchar idchar = ALPHA / DIGIT / "." / "-"*

the following are to be included from RFC3986

In short, the authority is just the method and the id string, and we use the query for dereferencing services, and with one additional exception, is URI compatible. What's not handled in this ABNF (and handled incorrectly, I believe, in yours) is the relative-ref.

It shouldn't be too hard, but we might do well to sync up on what a relative DID looks like. I think we agree the following is an absolute DID (or did-reference or something)

did:example:123456789abcdefghi

And if we are in the DID Document associated with that DID, then the absolute DID

did:example:123456789abcdefghi#openid

and the relative DID

#openid

would refer to the same element, correct? If so, then we need a relative definition that supports that. Neither yours nor mine does that.

I guess the only trick is to know that relative URIs within a DID Document are presumed to be relative DIDs, not relative URIs. I think this is mostly a non-issue for relative fragments, but for relative paths, it's gets trickier, depending on the semantic meaning of a path wrt the DID Document. (A relative URL in an html page is likely to trigger another GET unless you have a client-side router in a single-page app.)

The quirk of my proposal--which is new to the community so I doubt anyone else has thought of it this way--is simply to use the query part to specify the service id and to dereference DIDs that have a query by dereferencing the service endpoint, while all other dereferencing returns the DID Document (or a portion thereof depending on what paths are supposed to be used for).

Fragments should still work as normal, so if we have the following two DIDs

did:example:123456789abcdefghi#openid
did:example:123456789abcdefghi?openid

Then the first returns the JSON of the service endpoint. Or more likely, the user-agent dereferences http://example.com/123456789abcdefghi and then returns/displays/focuses/scrolls to the service endpoint definition. The second dereferences the openid service endpoint directly. In short, use fragments to refer to an element with an "id" property, and use a query to activate a service endpoint.

It seems to me updating the authority part as above and interpreting the query part as described, we have a much simpler ABNF that has all the features we need in a DID with MUCH greater alignment with URIs.

Further questions to help me understand the semantics:

A final note: it seems there are a few too many * asterisks in your ABNF. I wasn't quite sure what you were trying to do there unless you meant to trigger markdown formatting.

dhh1128 commented 5 years ago

FWIW, I am astonished that anybody would think did:xyz:abc123#key-1 IS a DID. I always thought it was a reference to something in a DID doc, but only the part before # was the DID. The DID method specs that I have studied only contemplate the part before the fragment as a DID--with the fragment part being defined separately. Or are we saying that every method spec can define fragment semantics as well?

dhh1128 commented 5 years ago

What @jandrieu mentions about the logical inconsistency of absolute DID references vs. relative ones is discussed in Issue #97 as well. I don't feel like that issue has ever been resolved.

talltree commented 5 years ago

This strikes me as a deep and complex enough topic that it's best left for RWOT even though not everyone on the list will be there. The other option is to restart dedicated DID spec calls, which is how we made so much progress last spring (although some of it is still stuck in PRs).

But my suggestion is let's just form a group to dive into it in Barcelona, and then see where we are after that.

On Mon, Feb 18, 2019 at 4:24 PM Daniel Hardman notifications@github.com wrote:

What @jandrieu https://github.com/jandrieu mentions about the logical inconsistency of absolute DID references vs. relative ones is discussed in Issue #97 https://github.com/w3c-ccg/did-spec/issues/97 as well. I don't feel like that issue has ever been resolved.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/w3c-ccg/did-spec/issues/170#issuecomment-464930865, or mute the thread https://github.com/notifications/unsubscribe-auth/ADLkTZkgf8JVOluVd9ZJDXu8Gry_LEk-ks5vO0RSgaJpZM4a_ODO .

dmitrizagidulin commented 5 years ago

Ok, this issue brings up a lot of excellent points. Let me see if I can address them, in the context of that pending PR.

dmitrizagidulin commented 5 years ago

OK, so let's start with your fundamental objection:

@jandrieu : My first point is that the charter isn't about defining a DID reference. It's about defining a DID. The current spec defines a DID as merely a component in a DID reference.

Yes, that's true. The charter is about defining a DID. But in order for the spec to be at all useful, we also need to talk about the two main things that DIDs are for.

To put it another way: DIDs resolve to DID Docs, which are containers for two main things. 1) cryptographic material (such as keys or other stuff for proofs), and 2) Service endpoints. So we kind of have to at least mention ways to refer to those keys, and to refer to those endpoints. And that's what DID References are.

To put it another way: yes, we could move any and all discussion (including the ABNF rules) for DID Reference URLs to the DID Resolution spec. But I strongly believe that doing so would be a disservice to implementers.

The current spec, with its definition of a DID as a component in a did-reference, a URI of the following form would NOT be a DID per the spec: did:example:123456789abcdefghi#keys-1

I would echo @dhh1128 in saying -- that is correct, and on purpose.

So for example, https://example.com/page.html is a URI for a web page. And https://example.com/page.html#Contact is a URI for a section of that page. (But not the page itself.) So, both of those things are URIs. But one is a URI for a page, and the other is for a section.

So similarly, did:example:123456789abcdefghi is a URI for a DID.

But did:example:123456789abcdefghi#keys-1 is a URI for a key, that happens to live inside that DID. So again, both things are URIs. But the second thing is not a DID URI.

I'm'a pause here - does this make sense so far?

jandrieu commented 5 years ago

FWIW, I am astonished that anybody would think did:xyz:abc123#key-1 IS a DID. Indeed. I appear to be in a minority, but I think my perspective is what most tech-savvy newbies-to-DIDs are going to have when DIDs are presented as URIs or URLs.

If there were a field on a web page where you enter a DID, would you be able to enter did:xyz:abc123#key-1? Or would that be rejected as improper syntax? (It would by the current ABNF, but I don't think it should be).

Even in the background, if an API had a parameter that is a DID, would your wallet put did:xyz:abc123#key-1 into that parameter?

Possibly not with fragments. For URLs, fragmets are managed by the user-agent and not sent to the server, so you might need to distinguish the interaction to answer that question.

However, if the that DID had a path or a query part instead of a fragment e.g., did:xyz:abc123?openid, wouldn't the wallet provide that entire string to the API?

Or more to the point, if I have a business card with a DID as with my secure email endpoint did:xyz:abc123?smail, isn't the entire string what someone would, ideally, be able to put into a DID compatible browser and have it just work?

I'll speak to the query thing in a separate note.

My strong sense is that it is the branded name, "DID" that we want the most leverage from. If we want people to thing of that as a URI, then it should almost certainly include the entire string. If, instead, we want the most important thing to be NOT like a URI, but be limited to just the method and id-string, then we should definitely stop talking about it as a URI.

To wit, at the December W3C workshop on strong authentication and identity, a colleague challenged me that DIDs are NOT URLs. We had a polite back and forth and pulled up RFC3986 and there was some reasonable debate. This will continue to happen if we talk about just the hier-part as that is the DID, while ascribing to it all the benefits of a DID-URL. That will confuse people to no end, especially those who have literally spent years debating and teasing out exactly what URIs and URLs and URNs actually are.

dmitrizagidulin commented 5 years ago

If there were a field on a web page where you enter a DID, would you be able to enter did:xyz:abc123#key-1?

Depends on if that particular client (on that web page) supported it. If it did, what you would get back is NOT a DID document, but a key object.

Even in the background, if an API had a parameter that is a DID, would your wallet put did:xyz:abc123#key-1 into that parameter?

No, it would not. The wallet would only use that string in an API call that expected a key URI.

My strong sense is that it is the branded name, "DID" that we want the most leverage from.

Sure, I totally agree and get that -- branding and naming is important. We should definitely continue the discussion on what we're gonna name things. I just want to start with an overall consensus that we're talking about two different things (in fact, at least 3 different things).

Thing one: A URI that resolves to a DID document. What should that be named? #168 calls it a "DID", or a DID URI.

Things two: A URI that refers to sections inside the DID document, such as keys. What should we call that? (#168 currently calls it a "DID Fragment Reference".

Thing three: A URI of the form <did>;<service id>/service-path?service=query#service-fragment, which resolves the service endpoint URL from the did document, then passes service-path, service-query and service-fragment to that resolved endpoint. The PR currently calls this a "DID Service Reference".

Can we agree that those are three different things?

did:xyz:abc123#key-1 <- this resolves to a key.

did:xyz:abc123;smail/messages/1#title <- this resolves to whatever lives in the service endpoint that has the id smail, the service path /messages/1, service fragment title.

dmitrizagidulin commented 5 years ago

In fact, for completeness, let's throw in resolvers into there, as well. Here's our complete bestiary of URIs that we're talking about on CCG calls.

1) https://resolver.example.com/v0?get_did=did:xyz:abc123&gzip=true#alfjalkfjaljd

This is a plain HTTPS URI that is passed to a resolver. Not a DID URI in any way, even though it happens to resolve to a DID Document. There are two query params, get_did and gzip, that are passed to the resolver service. Additionally, to refer to what @jonnycrunch mentioned about IPFS URIs, the uri fragment alfjalkfjaljd is used on the client-side to decrypt the results.

2) did:xyz:abc123

This is a DID URI, conforming to the ABNF rule from the did spec. It resolves to a DID Document. Now, a resolver library might translate it to a resolver URI above, or might be able to fetch it directly.

3) did:xyz:abc123#zopqrs

This is a URI that resolves to a key object. The semantics are "fetch the DID document. then find a linked data node with the id did:xyz:abv123#zopqrs", which will most likely be a key, so return that.

4) did:xyz:abc123/some/path

No-op. This is a URI that has no semantics, at the moment (though @msporny is arguing that it should be included in the ABNF, for future use). It means "fetch the DID document, then pass the path /some/path to it, but since there's no server on the other end and no semantics defined for this, nothing happens."

This is different from a service URI with a path, see below.

5) did:xyz:abc123?query_key=value

No-op. This is also a URI that has no semantics at the moment (same as 4). Again, different from a service reference uri that has a query fragment.

6) did:xyz:abc123;smail

This is a URI with the semantics "fetch the DID Doc, find a serviceEndpoint referenced by did:xyz:abc123#smail, and then pass along the empty service-path to it, /, see what happens.

7) did:xyz:abc123;smail/messages/1?summary=true#title

This is a URI with the semantics "fetch the DID Doc, find a serviceEndpoint referenced by did:xyz:abc123#smail, then make a call to it with the following parameters: service-path of /messages/1, service query summary=true, and then also feel free to use the service fragment title on the client side.

ChristopherA commented 5 years ago

If there were a field on a web page where you enter a DID, would you be able to enter did:xyz:abc123#key-1?

My problem with this example is that a parallel web browser comparison is that the browser gets the entire contents of the web page dereferenced at http://xyz.abc123 but then IT is responsible for displaying #key-1 if it can, and there are a number of browsers and webapps that do not support that and it is perfectly fine for them to do so.

So if key-1 is a fundamental operation that should dereference to a key, it should not use #. If it is the apps responsibility to parse the DID Document and itself use the hint of key#1 to find it, then # is appropriate.

jandrieu commented 5 years ago

@ChristopherA yes. that's right, but in the widget that you enter the DID, you include the fragment.

My point is that anywhere someone expects to be able to put a DID, they are going to expect to also put whatever query, path, and fragment parts their use case requires.

Whatever the current implementers and editors think a DID should be, if its discussed as a new kind of URL--which we have said at the beginning of every presentation I've seen--then people are going to include all of those parts in their idea of what a DID is.

talltree commented 5 years ago

On Tue, Feb 19, 2019 at 12:53 PM Joe Andrieu notifications@github.com wrote:

To wit, at the December W3C workshop on strong authentication and identity, a colleague challenged me that DIDs are NOT URLs. We had a polite back and forth and pulled up RFC3986 and there was some reasonable debate. This will continue to happen if we talk about just the hier-part as that is the DID, while ascribing to it all the benefits of a DID-URL. That will confuse people to no end, especially those who have literally spent years debating and teasing out exactly what URIs and URLs and URNs actually are.

To be very precise here (which is what we have to be when talking about ABNF), what most of us (with the exception of Joe) have been calling a "DID" (in human semantics) corresponds directly to the "did" rule (in the ABNF), which is:

did = "did:" method ":" method-specific-idstring

This rule does not correspond to "just the hier-part" in the ABNF of RFC 3986 https://www.ietf.org/rfc/rfc3986.txt. That ABNF says:

URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

The ABNF for a DID includes the scheme "did:". My point is that the colleague who challenged Joe was dead wrong when he said that a DID was not a URL (which technically is one form of a URI). The ABNF for a DID given above is a completely valid URI (which has always, from Day 1, been a design requirement for the ABNF for DIDs). It includes the scheme AND the hier-part. There is no requirement for a URI or a URL to include anything more.

Furthermore, a DID resolves to a DID document (even if it is a "virtual DID document" as has been discussed), which means it does function as the locator of a resource, which is what URL (Uniform Resource Locator) does.

So, once more, every valid DID is a valid URL. Full stop.

What I explained on the CCG call today is that when Markus and I discussed it last night, we realized we could introduce the term "DID URL" both in our human semantics and in the ABNF and kill two birds with one stone:

  1. We would have a clear term to use when we actually mean to say what Joe has thought the term "DID" always stood for, which is a DID URL, without changing the meaning of the term "DID" that the rest of us have been using (and which the ABNF has supported from the very first version), which is only the identifier that resolves to a DID document.
  2. We would have ABNF that exactly matches the human semantics.

Here is that full ABNF, by the way, so that hopefully Dmitri can begin to match it up with what he has:

did = "did:" method ":" method-specific-idstring method = 1methodchar methodchar = %x61-7A / DIGIT method-specific-idstring = idstring ( ":" idstring ) idstring = 1*idchar idchar = ALPHA / DIGIT / "." / "-"

did-url = did [ did-relative-ref ] did-relative-ref = did-fragment-ref / did-service-ref did-fragment-ref = "#" fragment did-service-ref = ( ";" service-id ) [ path-abemtpy ] [ "?" query ] [ "#" fragment ] service-id = 1( ALPHA / DIGIT / "." / "-" / "_" / pct-encoded )

did-reference = did-url / did-relative-ref Note that, thanks to Joe's eagle eye, this ABNF has been revised to bring it back into parallel with the RFC 3986 definition of a URI-reference, which is:

URI-reference = URI / relative-ref

jandrieu commented 5 years ago

@dmitrizagidulin Thanks for the detailed response. The examples you give help considerably.

However, there are some core misconceptions in some of your points.

First, all DID resolve to the DID Document. That's the first step in dereferencing. Not all dereferencing returns the DID Document. So, your three things above are not consistent with the meaning of the terms as defined in RFC3986. If you mean that some DIDs dereference to the DID Document while others dereference to a service endpoint, I'm in agreement. How paths and fragment affect that is another matter. Paths should, arguably, affect the scope of the resource returned, while fragments generally are sent to neither the resolver nor the resource store upon dereferencing, but rather applied to the resource after dereferencing.

Second, URIs are not defined by what they return. We don't have jpeg URIs or html URIs or key URIs. Rather, they are defined by the protocol used for resolving and dereferencing. We do have http URIs and telnet URIs. In fact, it is impossible to know with HTTP URIs what type of resource will be returned. There is a negotiation step in the headers where user-agents indicate their preference for various return types, e.g., asking for JSON or HTML or txt. The server may or may not pay any attention to that header.

And now we have a DID URI. Which, barring the name conflation that's been proposed, is just a DID, which is a URI. There is no such thing as a DID Document URI or a key URI. That's a category error.

http://example.com is an URI for HTTP did:example:xyz is a URI for a DID http://example.com?q=bob#definition is a URI for HTTP and, I argue, did:example:xyz?q=bob#definition should also be a URI for a DID

The introduction of a "DID URI" as the fully expressed DID with path, query, and fragment parts is a weird misnomer that is inconsistent with other URIs, like HTTP URIs, FTP URIs, etc. Those specs don't defined "HTTP URIs" or "FTP URIs" they define URIs for http and for ftp. And what we are defining is a URI for DIDs. That's a single thing, a single spec, not a DID and separately a DID URI.

No one is going to understand us if we try to tell them differently. As I pointed out above, there are numerous examples in the spec where it says things like "DIDs with optional fragments", clearly referring to did:example:xys#definition as a DID.

You could argue that the right fix is to update the spec to be more rigorous. Yes. We should do that. We should also be like water and flow with the usage that people in this community have already internalized. Clearly, even some of those who hold on to the ABNF notion that the DID is just the scheme, method, and id string, have documented, in the spec, usage that runs contrary to that. In your own PR, you have the text "DIDs that include DID fragments". By your own voice, @dmitrizagidulin, DIDs clearly include the fragment part if specified. You can't have it both ways.

Another problem with the spec and in our conversations, is the extremely uneven and inconsistent treatment of fragments, queries, and paths. To wit, the definitions section says the following:

DID Fragment The portion of a DID reference that follows the first hash sign character ("#"). A DID fragment uses the same syntax as a URI fragment. See section 5.5. Note that a DID fragment MUST immediately follow a DID. If a DID reference includes a DID path followed by a fragment, that fragment is NOT a DID fragment. DID Path The portion of a DID reference that follows the first forward slash character. A DID path uses the identical syntax as a URI path. See section 5.4. Note that if a DID path is followed by a fragment, that fragment is NOT a DID fragment.

None of the current ABNFs support that, nor do anyone's arguments to date support it. Clearly, there is much still to be teased out in this thing about fragments and paths and queries.

This suggests to me that we ran to an ABNF without clearly documenting the requirements and usage that the ABNF should support. As a result, we're arguing syntax when we still have question of semantics.

For example, one thing that came out on the call today is a hidden requirement that DIDs MUST be able to pass through the path, query, and fragment components to the service endpoint. Your comment above stated that clearly, but nowhere has that been communicated as a fundamental purpose of DIDs.

If there's agreement on that, great. I can support it. But it is currently not explained as a primary requirement. Instead it comes up in minor sections, which because of the overall inconsistency like the definitions I quote above, not only rarely get seen, they aren't understood.

As for the feature itself, it seems extremely problematic.

Without inspecting the DID document, one can't even know what kind of resource is expected at the end of that service endpoint, much less whether or not the service endpoint ALREADY has a query, path, or fragment term.

Given a DID did:ex:xyz and a service endpoint like the following in the DID Document:

"service": [{
    "id": "secretmsg",
    "type": "blindedservice",
    "serviceEndpoint": "https://blinded.example.com/974634?src=did%3Aexample%3Axyz%23secretmsg"
  },

Then how does this query/path/fragment stuff work?

If I then try to dereference a DID URI like did:ex:xyz;secretmsg/94156?src=did%3fake%3did

Then what do you do?

Do you just clobber the path? Override the query term? Include both query terms?

The service endpoint can be ANY valid URI, and as such can include paths and queries and fragments. Attempting to allow DID URI paths, queries, and fragments to "pass through" to the service endpoint is inviting collisions.

This is not how URIs work.

You will break the web.

I'm beginning to see some of the backstory of where previous identity architectures failed to reach consensus at W3C. This magic aggregation is almost certainly a bad idea.

Consider two use cases.

First, the app running on the other side of the request (in a browser, in server side code, etc.) just wants to retrieve the resource specified by the service endpoint. So, with the example above, did:ex:xyz;secretmsg directly derefrences https://blinded.example.com/974634?src=did%3Aexample%3Axyz%23secretmsg

The caller doesn't know what type it is, what additional parameters there are, or what path there might be. They just want to get to the resource declared in the service endpoint.

In this direct dereference, it would be unwise to encourage additional paths, queries, and fragments because, fundamentally, the caller never sees the details and can't predict how applying such parts to the service endpoint may or may not work. In fact, the exact same DID URI can point to different service endpoints over its lifetime, perhaps switching from facebook to mastodon or from a non-secured http service to an https. It is fundamental to the DID design that these endpoints are going to change even when specified by the same id.

IMO, the semantics of this should be no different than an http redirect. You start with a did with a service component, then you end up with the resource at the specified service endpoint. No merging, no passing the queries or paths or fragments along.

For the second use case, consider an app that is directly driving the resolution and dereferencing. This might be the user-agent, it might be an in-browser app, it might be native code running on a mobile or on a server. In this case, the app is going to dereference the DID to the DID Document because it is looking for a compatible service endpoint. It knows what service endpoint types it prefers and it knows how to structure method calls against those endpoints.

In this case, the app will use the type information to "intelligently" do whatever aggregation, substitution, packaging it needs to. There could be SOAP based service endpoints and REST based end points and everything in-between. The point here is that, in this case, the caller is NOT dereferencing the service endpoint immediately. It is resolving the DID Document, then applying its own business rules to that service endpoint which it then dereferences itself.

In neither of these cases do paths and queries and fragments pass blindly from the caller to the service endpoint.

Are you suggesting that service endpoints MUST NOT have paths or queries or fragments? That's not in the spec and I've never heard it suggested.

If you accept that they can, in fact have those components, is there actually a use case where it makes sense to mix those elements from the DID's URI into the service endpoints?

dmitrizagidulin commented 5 years ago

@jandrieu - as usual, lots of excellent points and questions. I can address a couple of them in a bit, but I just wanted to skip to the important one real quick:

Are you suggesting that service endpoints MUST NOT have paths or queries or fragments?

If you accept that they can, in fact have those components, is there actually a use case where it makes sense to mix those elements from the DID's URI into the service endpoints?

Yeahhh that's a fine question. I'm not quite sure... Let me get back to you on this :)

jandrieu commented 5 years ago

@dmitrizagidulin Yeah. I think that's the big question: to pass through/aggregate URI components or not. The rest of the issues are "just" syntax.

dmitrizagidulin commented 5 years ago

@jandrieu Sooo.. yeah, I think you're absolutely right about the implications.

Given that the ability to "pass through" the path, query and fragment to the serviceEndpoint is one of the two main value propositions of DIDs (and I agree, this part is BARELY documented, if at all :) ).

And given that the serviceEndpoint value could be any sort of valid URI, including having its own path & query & fragment, as in your example:

"serviceEndpoint": "https://blinded.example.com/974634?src=did%3Aexample%3Axyz%23secretmsg"

thennnn... the only reasonable implication is... TO FLIP THE TABLE AND DISBAND THE COMMUNITY GROUP :)

No, wait! That's not it, I always get it confused with that.

No, honestly, the only reasonable implication is the following:

a) (in the Data Model spec) We explicitly restrict the value of serviceEndpoints to be bare origins, with no paths / query fragments / hash fragments. b) AND ALSO (because people will ignore a)), require that the resolution algorithm MUST strip off any existing path, query fragment and hash fragment, that it finds as the serviceEndpoint value, before applying the service reference path, query and fragment. (Yes, this will have to be specified in the DID Resolution spec.)

Because otherwise, like you say, aggregating the paths/queries/fragments would result in madness and broken URLs.

dmitrizagidulin commented 5 years ago

@talltree I want to also address what you said a few comments above, but I want to ask first - are those ABNF rules formatted right? I'm having a bit of trouble parsing them.

talltree commented 5 years ago

Dmitri, my apologies, I've done so much ABNF over the years that I've been doing it by hand and not checking it via a parser (which I always do before committing it to a spec).

I just checked and the online ABNF syntax validator I used for years is no longer online. Do you have one you use?

On Tue, Feb 19, 2019 at 6:47 PM Dmitri Zagidulin notifications@github.com wrote:

@talltree https://github.com/talltree I want to also address what you said a few comments above, but I want to ask first - are those ABNF rules formatted right? I'm having a bit of trouble parsing them.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/w3c-ccg/did-spec/issues/170#issuecomment-465398609, or mute the thread https://github.com/notifications/unsubscribe-auth/ADLkTXUJOX38VwvWeAYv_eqAAaqtOJ6Gks5vPLdSgaJpZM4a_ODO .

jandrieu commented 5 years ago

a) (in the Data Model spec) We explicitly restrict the value of serviceEndpoints to be bare origins, with no paths / query fragments / hash fragments. b) AND ALSO (because people will ignore a)), require that the resolution algorithm MUST strip off any existing path, query fragment and hash fragment, that it finds as the serviceEndpoint value, before applying the service reference path, query and fragment. (Yes, this will have to be specified in the DID Resolution spec.)

Because otherwise, like you say, aggregating the paths/queries/fragments would result in madness and broken URLs.

And yet, if we restrict service endpoints like that, one can only use the authority part to identify the associated account. Yes, you can do that with old school user@:

authority = [ userinfo "@" ] host [ ":" port ]

Or with custom host names like http://rwot8.eventbrite.com

But, realistically, most user ids in current services are either path or query terms. You literally would not be able to use my github, Twitter, or Facebook accounts as service endpoints.

In short, if you try to pass through these components, you're gonna break the web.

Perhaps more importantly, I expect the TAG, and others, will have a hard time approving such a technique.

I think you have to dereference without substitution by default, and clients that handle their own dereferencing can construct customized endpoints for those they understand. In either case the starting DID can't contain path or query parts that pass through to the service endpoints. Fragments are probably the reverse; they should never be passed to anyone, and may be applied to the resource returned by referencing the service endpoint. They don't pass through as much as get applied after the resource is retrieved.

If that's the case, then path and query parts are free to be used for semantics like restricting the context within a did document with a path to refer to an element structurally, or as I proposed with queries for indicating service dereferencing and the id of the service.

talltree commented 5 years ago

Dmitri, Markus did me a favor (thanks Markus!) and ran a parser on the ABNF below and it worked fine for him except he caught one typo (in the word "abempty"—I had transposed the last two letters when I typed it). So the following should be clean. Also note that it includes the rule from RFC 3986 which we forgot in the previous spec—it's needed to be able to do percent-encoding of URLs used as service-ids).

did = "did:" method ":" method-specific-idstring method = 1methodchar methodchar = %x61-7A / DIGIT method-specific-idstring = idstring ( ":" idstring ) idstring = 1*idchar idchar = ALPHA / DIGIT / "." / "-"

did-url = did [ did-relative-ref ]

did-relative-ref = did-fragment-ref / did-service-ref

did-fragment-ref = "#" fragment

did-service-ref = *( ";" service-id ) [ path-abempty ] [ "?" query ] [ "#" fragment ]

service-id = 1*( ALPHA / DIGIT / "." / "-" / "_" / pct-encoded )

did-reference = did-url / did-relative-ref

On Tue, Feb 19, 2019 at 10:43 PM =Drummond Reed drummond@connect.me wrote:

Dmitri, my apologies, I've done so much ABNF over the years that I've been doing it by hand and not checking it via a parser (which I always do before committing it to a spec).

I just checked and the online ABNF syntax validator I used for years is no longer online. Do you have one you use?

On Tue, Feb 19, 2019 at 6:47 PM Dmitri Zagidulin notifications@github.com wrote:

@talltree https://github.com/talltree I want to also address what you said a few comments above, but I want to ask first - are those ABNF rules formatted right? I'm having a bit of trouble parsing them.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/w3c-ccg/did-spec/issues/170#issuecomment-465398609, or mute the thread https://github.com/notifications/unsubscribe-auth/ADLkTXUJOX38VwvWeAYv_eqAAaqtOJ6Gks5vPLdSgaJpZM4a_ODO .

dmitrizagidulin commented 5 years ago

@talltree Oh! :) I just meant formatting on a github markdown level. But thank you for running it through a validator!

mwherman2000 commented 5 years ago

if I have a business card with a DID as with my secure email endpoint did:xyz:abc123?smail, isn't the entire string what someone would, ideally, be able to put into a DID compatible browser and have it just work?

@jandrieu @ChristopherA I believe you're making a bunch of assumptions about how end-users will actually use DIDs and the end-user usability of DID identifiers. All of these examples are way too technical to reach any critical level of adoption. At most, people will somehow figure out how to copy and paste a plain old DID into some sort of contact object that will be passed around. For your scenarios, I predict there will have to be well known/common names for fragments like "emailAddress", "publicKey", etc. No one has really begun to talk about actual end-user UX scenarios until today.

Are we heading back to something that was worse that UUCP "bang path" email addresses from the '60s and 70's? #noway image

dmitrizagidulin commented 5 years ago

@jandrieu

But, realistically, most user ids in current services are either path or query terms. You literally would not be able to use my github, Twitter, or Facebook accounts as service endpoints.

Aha, ok. So this is actually also on purpose, part of the design. The serviceEndpoint values absolutely should not have any sort of user id or any other identifiers in them. For one, that defeats the whole "no PII / least correlateability" privacy-preserving purpose of DIDs. Now, obviously, if somebody uses their own personal domain as a service endpoint, that completely defeats the privacy purpose, but there's nothing we can do about that, on a domain level.

But anyways, so the mechanism is supposed to work like:

service: [
  {
    id: 'hub',  serviceEndpoint: 'https://facebook.com'
  }
]

And then the service reference uri will look like did:xyz:1234;hub/pictures/userpic.png. The important thing to note here is that regardless of who will be using that service URI (which will resolve to facebook.com), they're going to be using their own out-of-band user info when interacting with it. Like, if I'm using it, I'll log in to FB as myself. If the link is for other people to use, they're going to be using their own login status and permissions and so on.

Does that make sense?

jandrieu commented 5 years ago

@mwherman2000 That's exactly my point. End users won't distinguish between DIDs and DID URIs as defined in the current ABNF. They are all DIDs. Btw, I recommend you read up on my work on Joram and Amira in the RWOT archives. Quite a lot more work has gone into UX than you're giving credit for.

I'm also not sure what the bang path thing is about. No one has recommended that. In fact, I'm trying to simplify the ABNF because (1) we can't safely pass all paths and queries to service endpoints and (2) instead let's use the query part for the service is instead of jamming it onto the hier part with a semicolon.

dmitrizagidulin commented 5 years ago

instead let's use the query part for the service is instead of jamming it onto the hier part with a semicolon.

So, that's an option that has been brought up multiple times, and rejected. For one, as @talltree and @peacekeeper have mentioned, they've tried that with previous architectures and ran into serious troubles.

Moreover, this approach goes against the URI spec. Query parameters (see Section 3.4 of the URI spec) are scoped to a particular scheme and naming authority. In other words, query parameters are only meaningful to a given server, and have no universal meaning across different URIs (even within the same URI scheme). Similarly, with hash fragments: fragment's format and resolution is dependent on the media type and Fragment identifier semantics are independent of the URI scheme and thus cannot be redefined by scheme specifications. Which means it's not possible (within the spirit of the spec) to "reserve" a service query parameter, in the way that you're thinking.

mwherman2000 commented 5 years ago

End users won't distinguish between DIDs and DID URIs as defined in the current ABNF. They are all DIDs.

@jandrieu This point-of-view continues to be a fundamental problem. Not all DID URIs are "DID"s ...re-read the grammar. I'm not going to say anything more on this.

CC: @talltree @peacekeeper @dmitrizagidulin

jandrieu commented 5 years ago

@dmitrizagidulin That's a non-starter. While you might try to get folks to avoid PII in the DID Document, you can't prevent it, which means it WILL happen.

But also, this doesn't make sense:

The important thing to note here is that regardless of who will be using that service URI (which will resolve to facebook.com), they're going to be using their own out-of-band user info when interacting with it. Like, if I'm using it, I'll log in to FB as myself. If the link is for other people to use, they're going to be using their own login status and permissions and so on.

The point is that the DID controller is saying you can reach me here, which needs an identifier.

If I stick that facebook endpoint into my DID Document--without any identifier of my account there--you WILL NOT be able to reach me or my Facebook account without already knowing some other detail and knowing how to format those details to get Facebook to direct you to my profile. In short, that's a useless endpoint.

The future of service endpoints is to use the DID identifier as the identifier at the service endpoint to find me. THAT's the PII appropriate way to do that. Just put the DID id in the service endpoint, with whatever formatting it requires. We can do that RIGHT NOW with a service endpoint like:

service: [
  {
    id: "hub",  type: "DidSocial1_0_0", serviceEndpoint: "https://facebook.com/did%3Aex%3Axyz"
  }
]

or

service: [
  {
    id: "hub",  type: "DidSocial1_0_0", serviceEndpoint: "https://example.com/user=%3Aex%3Axyz"
  }
]

This is what endpoints should look like. And the current pass-through feature can't handle that.

And yet, it will be a long time before that happens universally. Instead, people will put both insecure and legacy service endpoints. If the spec can't handle the transition from current to best practices, it'll never make it through TAG review.

jandrieu commented 5 years ago

@mwherman2000 That's my point. The grammar is wrong. Despite @talltree and @dmitrizagidulin's assertions to the contrary, their own language in the spec consistently refers to DIDs with fragments. The idea that DIDs are only the scheme, method, and id-string is a figment of ABNF fantasy.

dmitrizagidulin commented 5 years ago

@jandrieu heh, ignore the language in the spec :) That was cobbled together from many PRs by different people. Let's focus on the underlying issues here -- that we need URIs for a handful of different things, and we need to figure out what to call them / brand them as. We'll make the language consistent, and fix the ABNF, once we have consensus on the core idea.

jandrieu commented 5 years ago

@dmitrizagidulin And yet, that's the best example, in the spec editors own voice, of exactly how the term is and will be used, both how we have been speaking of them and how others will be speaking of them, pretty much no matter what we say to the contrary.

As long as we say DIDs are URIs or URLs, people will expect that the entire string is the DID. Because that is how all other URIs work. The URI is the whole string, full stop. The syntax varies, the semantics vary, but one doesn't refer to just the hier-part of a URL as the URL while the combined string is the URL URI. NOBODY does that.

The only way out of that would be to shift the language dramatically to make it clear that what we are standardizing is not just the DID, but something else, name TBD. And that that thing is a URI. DIDs are just a part of that. But, I would bet my co-chair of this committee that you aren't going to get that by the consensus. It's too powerful and too resonant to say DIDs are a new URI. THAT has become canon and will be nearly impossible to change.

jandrieu commented 5 years ago

Moreover, this approach goes against the URI spec. Query parameters (see Section 3.4 of the URI spec) are scoped to a particular scheme and naming authority. In other words, query parameters are only meaningful to a given server, and have no universal meaning across different URIs (even within the same URI scheme). Similarly, with hash fragments: fragment's format and resolution is dependent on the media type and _Fragment identifier semantics are independent of the URI scheme and thus cannot be redefined by scheme specifications._ Which means it's not possible (within the spirit of the spec) to "reserve" a service query parameter, in the way that you're thinking.

Hmmm. I read that with exactly the opposite conclusion. Query parameters are scoped to the scheme, aka "did" and naming authority aka the method and the id string. If you review my mapping of the URI generic scheme, the authority part is the method:id-string part. Which means queries are scoped to the DID Document, meaning any DID Document can define its own query terms.

Just because URL authority parts usually resolve to servers doesn't mean that authority === server. Quite the contrary, from 3986 section 3.2:

The generic syntax provides a common means for distinguishing an authority based on a registered name or server address, along with optional port and user information.

Yes. We use the authority part to distinguish based on a registered name (instead of a server address). That name is registered within a namespace defined by the method. Together, method+id-string fully meet the non-server expectations of an authority.

You may note that the authority part used to be called the server part. That's deprecated, but I can see where your expectation comes from. However, it's clear that the authority part was clarified to mean exactly how we use it: to specify the scope of the namespace for an identifier.

dmitrizagidulin commented 5 years ago

Ok, so, maybe a call or an in-person discussion might be higher bandwidth, at this point. (I apologize for dragging out the discussion on this GH issue) :) My main aim was to use the fact that github displays code snippets nicely (so I could list the various URIs that we'll need to name and put into the ABNF), so we don't have to draw them on a whiteboard or whatever.

jandrieu commented 5 years ago

Indeed. RWOT is right around the corner.

FWIW, no need to apologize for "dragging out the discussion" here. That's what issues are for. Although I do apologize for other readers. It's hard to sync up with the back-and-forth.

ChristopherA commented 5 years ago

I believe you're making a bunch of assumptions about how end-users will actually use DIDs and the end-user usability of DID identifiers. All of these examples are way too technical to reach any critical level of adoption.

a) my hope is that we get to the point that end-users rarely if ever see DIDs, just as they today don't see IP addresses in URLs. Instead, the work from previous #RebootingWebOfTrust on the topic of local names / pet names / etc. will advance. I personally believe for DIDs it will largely work the way phone numbers work for younger generation today — they never see them, they just save on first use and name them to an address book, or pass them on to someone else as an attachment. At best, they memorize their own (which my experience with younger generation they don't even remember their own phone number, they have to look it up on their phone).

b) Our audience isn't end-users, its developers. Almost all of these advanced features will rarely be used for end-user DIDs, but to allow apps to communicate with apps about more specific thing they need, the way that phone numbers today can use * and # that the larger system understands as well as + as a shortcut for international , for pause and ; for break that most phones understand. The best conferencing services now use these extra symbols for logging on to a meeting. It will be similar for DIDs, end-users will use them or bookmark them, but don't need to understand them.

talltree commented 5 years ago

On Wed, Feb 20, 2019 at 7:17 AM Dmitri Zagidulin notifications@github.com wrote:

@jandrieu https://github.com/jandrieu

But, realistically, most user ids in current services are either path or query terms. You literally would not be able to use my github, Twitter, or Facebook accounts as service endpoints.

Aha, ok. So this is actually also on purpose, part of the design. The serviceEndpoint values absolutely should not have any sort of user id or any other identifiers in them. For one, that defeats the whole "no PII / least correlateability" privacy-preserving purpose of DIDs. Now, obviously, if somebody uses their own personal domain as a service endpoint, that completely defeats the privacy purpose, but there's nothing we can do about that, on a domain level.

But anyways, so the mechanism is supposed to work like:

service: [ { id: 'hub', serviceEndpoint: 'https://facebook.com' } ]

And then the service reference uri will look like did:xyz:1234;hub/pictures/userpic.png. The important thing to note here is that regardless of who will be using that service URI (which will resolve to facebook.com), they're going to be using their own out-of-band user info when interacting with it. Like, if I'm using it, I'll log in to FB as myself. If the link is for other people to use, they're going to be using their own login status and permissions and so on.

Does that make sense?

Dmitri, love it, that's the whole idea of exactly how DID service URLs are supposed to work. One point, however: I have never seen the restriction that a service endpoint URL needs to be "bare", i.e., just an URI "hier-part".

I've never heard any justification for that (obviously I must have missed some past dialog).

All the other discovery specs I've worked on (XRDS, XRD, XDI) have followed the same algorithm of simply attending the non-DID portion of a DID URL (minus the service-id) to the service endpoint URL. To be precise, this set of steps:

  1. Use the service-id (see the ABNF below) to select the matching service.
  2. Select the value of the service endpoint property. Call this the service base URL.
  3. From the DID URL, remove the DID and the service-id component. The result is the service-relative-ref.
  4. Append the service relative ref directly to the service base URL.
  5. The resulting URL—the service composite URL—is what the DID resolver would either return to the developer (or actually dereference, if that's in the scope of the DID resolver).

This way you allow the developer (DID controller) to control the exact formatting of the service base URL without any restriction. They can then build their back-end systems knowing that the calls coming from DID service URLs are always going to be the service base URL plus the service-relative-ref.

Make sense?

did = "did:" method ":" method-specific-idstring method = 1methodchar methodchar = %x61-7A / DIGIT method-specific-idstring = idstring ( ":" idstring ) idstring = 1*idchar idchar = ALPHA / DIGIT / "." / "-"

did-url = did [ did-relative-ref ]

did-relative-ref = did-fragment-ref / did-service-ref

did-fragment-ref = "#" fragment

did-service-ref = *( ";" service-id ) [ path-abempty ] [ "?" query ] [ "#" fragment ]

service-id = 1*( ALPHA / DIGIT / "." / "-" / "_" / pct-encoded )

did-reference = did-url / did-relative-ref

talltree commented 5 years ago

On Wed, Feb 20, 2019 at 7:35 AM Joe Andrieu notifications@github.com wrote:

@mwherman2000 https://github.com/mwherman2000 That's my point. The grammar is wrong. Despite @talltree https://github.com/talltree and @dmitrizagidulin https://github.com/dmitrizagidulin's assertions to the contrary, their own language in the spec consistently refers to DIDs with fragments. The idea that DIDs are only the scheme, method, and id-string is a figment of ABNF fantasy.

Joe, if there is any language in the current spec that refers to "DID" and is intended to mean more than just did:method:id-string, then it's a mistake. If I wrote that text, mea culpa, I'll fix it (in real time in Barcelona—can't wait!)

talltree commented 5 years ago

On Wed, Feb 20, 2019 at 7:45 AM Joe Andrieu notifications@github.com wrote:

@dmitrizagidulin https://github.com/dmitrizagidulin And yet, that's the best example, in the spec editors own voice, of exactly how the term is and will be used, both how we have been speaking of them and how others will be speaking of them, pretty much no matter what we say to the contrary.

As long as we say DIDs are URIs or URLs, people will expect that the entire string is the DID.

Not only do I disagree, but it's the whole reason that Markus and I have proposed the term "DID URL". If we consistently use the term "DID URL" 100% of the time we are referring to a "string that begins with a DID but could also contain the rest of the components of a URL" (which technically is a URI), then when someone says "DID" instead of "DID URL", they will understand you are talking about just one component of a DID URL.

Because that is how all other URIs work. The URI is the whole string, full stop. The syntax varies, the semantics vary, but one doesn't refer to just the hier-part of a URL as the URL while the combined string is the URL URI. NOBODY does that.

See the above. A second reason to start calling them DID URLs is that it reinforces the fact that every DID is in fact a type of URL. They are 100% compatible with RFC 3986 https://www.ietf.org/rfc/rfc3986.txt.

The only way out of that would be to shift the language dramatically to make it clear that what we are standardizing is not just the DID, but something else, name TBD.

Name = DID URL. Which matches just what we call other types of URLs. HTTP URL. HTTPS URL. Mailto URL. etc.

And that that thing is a URI.

Yes it is. All URLs are URIs.

DIDs are just a part of that.

Yes.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/w3c-ccg/did-spec/issues/170#issuecomment-465632208, or mute the thread https://github.com/notifications/unsubscribe-auth/ADLkTSoUFlnswzvJKhTE01p9Bxe_OtN7ks5vPW1_gaJpZM4a_ODO .

mwherman2000 commented 5 years ago
did-fragment-ref = "#" fragment 
did-service-ref = *( ";" service-id ) [ path-abempty ] [ "?" query ] [ "#" fragment ]

Can someone clarify/simmarize what a "fragment" is in the context of a DID Document ? ...that is, a more detailed explanation beyond a fragment is something that is dereferencible.

For example, if you have did:xyz:1234#foo, how does a DID resolver know if it is supposed to dereference a key vs. an service endpoint vs. something else in the DID Document? ...perhaps, using https://w3c-ccg.github.io/did-spec/#real-world-example as a context for the explanation.

talltree commented 5 years ago

On Fri, Feb 22, 2019 at 5:31 AM Michael Herman (Toronto) < notifications@github.com> wrote:

did-fragment-ref = "#" fragment did-service-ref = *( ";" service-id ) [ path-abempty ] [ "?" query ] [ "#" fragment ]

Can someone clarify what a "fragment" is in the context of a DID Document ? ...that is, a more detailed explanation beyond a fragment is something that is dereferencible.

As a starting point—and again to emphasize how closely we want to base DIDs and DID URLs on the URI spec (RFC 3986 https://www.ietf.org/rfc/rfc3986.txt), the first rule with DID fragments is that they follow the same rules as URI fragments. To quote from section 3.5 of RFC 3986:

The fragment identifier component of a URI allows indirect identification of a secondary resource by reference to a primary resource and additional identifying information. The identified secondary resource may be some portion or subset of the primary resource, some view on representations of the primary resource, or some other resource defined or described by those representations. A fragment identifier component is indicated by the presence of a number sign ("#") character and terminated by the end of the URI.

  fragment    = *( pchar / "/" / "?" )

The semantics of a fragment identifier are defined by the set of representations that might result from a retrieval action on the primary resource. The fragment's format and resolution is therefore dependent on the media type [RFC2046] of a potentially retrieved representation, even though such a retrieval is only performed if the URI is dereferenced. If no such representation exists, then the semantics of the fragment are considered unknown and are effectively unconstrained. Fragment identifier semantics are independent of the URI scheme and thus cannot be redefined by scheme specifications.

Individual media types may define their own restrictions on or structures within the fragment identifier syntax for specifying different types of subsets, views, or external references that are identifiable as secondary resources by that media type. If the primary resource has multiple representations, as is often the case for resources whose representation is selected based on attributes of the retrieval request (a.k.a., content negotiation), then whatever is identified by the fragment should be consistent across all of those representations. Each representation should either define the fragment so that it corresponds to the same secondary resource, regardless of how it is represented, or should leave the fragment undefined (i.e., not found).

When you apply that DID documents, the use of a DID fragment is "the identification of a secondary resource" within the DID document. Thus what the DID spec needs to specify is exactly how that secondary resource identification works.

That's what section 4.3 of the current DID spec https://w3c-ccg.github.io/did-spec/ is for. It says:

A generic DID fragment https://w3c-ccg.github.io/did-spec/#dfn-did-fragment (the did-fragment rule in Section § 4.1 The Generic DID Scheme https://w3c-ccg.github.io/did-spec/#the-generic-did-scheme) is identical to a URI fragment and MUST conform to the ABNF of the fragment ABNF rule in [RFC3986 https://w3c-ccg.github.io/did-spec/#bib-rfc3986]. A DID fragment MUST be used only as a method-independent pointer into the DID Document to identify a unique key description or other DID Document component. To resolve this pointer, the complete DID reference including the DID fragment MUST be used as the value of the id key for the target JSON object.

Mike, I know you've already suggested clearer wording for that last sentence, and I think we can make sure we get to full clarity in Barcelona.

For example, if you have did:xyz:1234#foo, how does a DID resolver know if

it supposed to dereference a key vs. an service endpoint vs. something else in the DID Document?

Thankfully, that's taken care of by the JSON-LD spec. And "id key" MUST be unique in an entire JSON-LD document. So all the DID resolver needs to do is find the JSON-LD element whose id property value matches the fragment and return that. Done.

jandrieu commented 5 years ago

@talltree said

When you apply that DID documents, the use of a DID fragment is "the identification of a secondary resource" within the DID document.

This is not true if there is a service endpoint in the DID. In that case, the fragment applies to the resource returned by the endpoint bout the DID document.

The fragment applies within whatever resource is retrieved by dereferencing, NOT by resolving. Others have expressed confusion over this point as well.

I think the conflation of dereferencing and resolving is at the heart of much confusion and error in the spec. I recommend restricting resolving to return the entire DID Document, and allow the user agent to apply the fragment reference. The fragment is not designed to be passed upstream.

talltree commented 5 years ago

On Sat, Feb 23, 2019 at 5:20 PM Joe Andrieu notifications@github.com wrote:

@talltree https://github.com/talltree said

When you apply that DID documents, the use of a DID fragment is "the identification of a secondary resource" within the DID document.

This is not true if there is a service endpoint in the DID. In that case, the fragment applies to the resource returned by the endpoint bout the DID document.

Sorry if I wasn't clear; the example that Mike had been asking about had the fragment directly on a naked DID, in which case it doesn't get passed to a service endpoint, but gets dereferenced against the DID document itself.

The fragment applies within whatever resource is retrieved by

dereferencing, NOT by resolving. Others have expressed confusion over this point as well.

Correct.

I think the conflation of dereferencing and resolving is at the heart of much confusion and error in the spec. I recommend restricting resolving to return the entire DID Document, and allow the user agent to apply the fragment reference. The fragment is not designed to be passed upstream.

The DID Resolution group had a great discussion about on their call last week, and I think we are well on our way to getting it clear.

jandrieu commented 5 years ago

My point is that you were unclear, so if you think you got it figured out on the call, you need to try again.

The answer to @mwherman2000 is that if there is a service reference, the fragment applies to the resource retrieved by the service endpoint. Otherwise, it will be applied to the DID Document.

mwherman2000 commented 5 years ago

The answer to @mwherman2000 is that if there is a service reference, the fragment applies to the resource retrieved by the service endpoint. Otherwise, it will be applied to the DID Document.

@jandrieu How do you dereference a component of a DID Document when there is a service endpoint? ...for example, how do you dereference the URI/URL of the service endpoint itself?

talltree commented 5 years ago

On Sun, Feb 24, 2019 at 6:53 PM Michael Herman (Toronto) < notifications@github.com> wrote:

The answer to @mwherman2000 https://github.com/mwherman2000 is that if there is a service reference, the fragment applies to the resource retrieved by the service endpoint. Otherwise, it will be applied to the DID Document.

@jandrieu https://github.com/jandrieu How do you dereference a component of a DID Document when there is a service endpoint? ...for example, how do you dereference the URI/URL of the service endpoint itself?

Michael, there's a full PR written against that process which I don't have the time to hunt down right now (Mike Lodder filed it), but this document https://docs.google.com/document/d/1t-AsCPjvERBZq9l-iXn2xffJwlNfFoQhktfIaMFjN-c/edit?usp=sharing goes through the process for a particular use case which is easy to generalize from.

mwherman2000 commented 5 years ago

This is not true if there is a service endpoint in the DID.

My apologies for forgetting to not respond to any further abuses of the term "DID".

Further, the name of the token that follows a ";" is a service-id (at least that is what it is called in both @talltree and @dmitrizagidulin 's recent versions of the DID ABNF grammar). More importantly, it's not a service endpoint ...in addition to it not being part of a DID.

mwherman2000 commented 5 years ago

In EXAMPLE 16 (reproduced below):

  1. How and where can dereferencable "anchors" be placed inside a DID document? (this question has nothing to do with the DID ABNF ...just the structure of a DID Document): a. for locating public keys? for example, is it anywhere there is a #foo construct in a publicKey id attribute? b. for locating service endpoints? for example, is it anywhere there is a ;bar construct in a service id attribute? c. are there any other scenarios? ...any other delimiters in addition to # and ;?

EXAMPLE 16: Advanced DID Document example

{
  "@context": "https://w3id.org/future-method/v1",
  "id": "did:example:123456789abcdefghi",

  "publicKey": [{
    "id": "did:example:123456789abcdefghi#keys-1",
    "type": "RsaVerificationKey2018",
    "controller": "did:example:123456789abcdefghi",
    "publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n"
  }, {
    "id": "did:example:123456789abcdefghi#keys-3",
    "type": "Ieee2410VerificationKey2018",
    "controller": "did:example:123456789abcdefghi",
    "publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n"
  }],

  "authentication": [
    // this mechanism can be used to authenticate as did:...fghi
    "did:example:123456789abcdefghi#keys-1",
    // this mechanism can be used to biometrically authenticate as did:...fghi
    "did:example:123456789abcdefghi#keys-3",
    // this mechanism is *only* authorized for authentication, it may not
    // be used for any other proof purpose, so its full description is
    // embedded here rather than using only a reference
    {
      "id": "did:example:123456789abcdefghi#keys-2",
      "type": "Ed25519VerificationKey2018",
      "controller": "did:example:123456789abcdefghi",
      "publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
    }
  ],

  "service": [{
    "type": "OpenIdConnectVersion1.0Service",
    "serviceEndpoint": "https://openid.example.com/"
  }, {
    "type": "CredentialRepositoryService",
    "serviceEndpoint": "https://repository.example.com/service/8377464"
  }, {
    "type": "XdiService",
    "serviceEndpoint": "https://xdi.example.com/8377464"
  }, {
    "type": "HubService",
    "serviceEndpoint": "https://hub.example.com/.identity/did:example:0123456789abcdef/"
  }, {
    "type": "MessagingService",
    "serviceEndpoint": "https://example.com/messages/8377464"
  }, {
    "type": "SocialWebInboxService",
    "serviceEndpoint": "https://social.example.com/83hfh37dj",
    "description": "My public social inbox",
    "spamCost": {
      "amount": "0.50",
      "currency": "USD"
    }
  }, {
    "type": "DidAuthPushModeVersion1",
    "serviceEndpoint": "http://auth.example.com/did:example:123456789abcdefghi"
  }, {
    "id": "did:example:123456789abcdefghi;bops",
    "type": "BopsService",
    "serviceEndpoint": "https://bops.example.com/enterprise/"
  }]
}
talltree commented 5 years ago

Michael, the "anchors" are always "id" properties on any JSON-LD object. So any JSON-LD object that needs matching needs an "id" property (as standard property in JSON-LD), and then it is matched by EITHER:

  1. A DID URL fragment that is directly on the DID (i.e., no path or query), OR
  2. A service-id, which is the string that follows the first semicolon following the DID.

On Sun, Feb 24, 2019 at 10:38 PM Michael Herman (Toronto) < notifications@github.com> wrote:

In EXAMPLE 16 (reproduced below):

  1. How and where can dereferencable "anchors" be placed inside a DID document? (this question has nothing to do with the DID ABNF ...just the structure of a DID Document): a. for locating public keys? for example, is it anywhere there is a

    foo construct in a publicKey id attribute?

    b. for locating service endpoints? for example, is it anywhere there is a ;bar construct in a service id attribute?

EXAMPLE 16: Advanced DID Document example

{ "@context": "https://w3id.org/future-method/v1", "id": "did:example:123456789abcdefghi",

"publicKey": [{ "id": "did:example:123456789abcdefghi#keys-1", "type": "RsaVerificationKey2018", "controller": "did:example:123456789abcdefghi", "publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n" }, { "id": "did:example:123456789abcdefghi#keys-3", "type": "Ieee2410VerificationKey2018", "controller": "did:example:123456789abcdefghi", "publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n" }],

"authentication": [ // this mechanism can be used to authenticate as did:...fghi "did:example:123456789abcdefghi#keys-1", // this mechanism can be used to biometrically authenticate as did:...fghi "did:example:123456789abcdefghi#keys-3", // this mechanism is only authorized for authentication, it may not // be used for any other proof purpose, so its full description is // embedded here rather than using only a reference { "id": "did:example:123456789abcdefghi#keys-2", "type": "Ed25519VerificationKey2018", "controller": "did:example:123456789abcdefghi", "publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV" } ],

"service": [{ "type": "OpenIdConnectVersion1.0Service", "serviceEndpoint": "https://openid.example.com/" }, { "type": "CredentialRepositoryService", "serviceEndpoint": "https://repository.example.com/service/8377464" }, { "type": "XdiService", "serviceEndpoint": "https://xdi.example.com/8377464" }, { "type": "HubService", "serviceEndpoint": "https://hub.example.com/.identity/did:example:0123456789abcdef/" }, { "type": "MessagingService", "serviceEndpoint": "https://example.com/messages/8377464" }, { "type": "SocialWebInboxService", "serviceEndpoint": "https://social.example.com/83hfh37dj", "description": "My public social inbox", "spamCost": { "amount": "0.50", "currency": "USD" } }, { "type": "DidAuthPushModeVersion1", "serviceEndpoint": "http://auth.example.com/did:example:123456789abcdefghi" }, { "id": "did:example:123456789abcdefghi;bops", "type": "BopsService", "serviceEndpoint": "https://bops.example.com/enterprise/" }] }

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/w3c-ccg/did-spec/issues/170#issuecomment-466889668, or mute the thread https://github.com/notifications/unsubscribe-auth/ADLkTQfblleIPdMbNkBSarVDt4tHNbMEks5vQ4TtgaJpZM4a_ODO .

mwherman2000 commented 5 years ago

@talltree Based on your reply, please confirm that the following 4 examples for the 3 use cases are correct:

Example A: Use case 1a from above: In the following snippet from EXAMPLE 16...

  "publicKey": [{
    "id": "did:example:123456789abcdefghi#keys-1",
    "type": "RsaVerificationKey2018",
    "controller": "did:example:123456789abcdefghi",
    "publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n"
  }, {
    "id": "did:example:123456789abcdefghi#keys-3",
    "type": "Ieee2410VerificationKey2018",
    "controller": "did:example:123456789abcdefghi",
    "publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n"
  }]

Example B: Another use case 1a example: In the following snippet from EXAMPLE 16...

  "authentication": [
    "did:example:123456789abcdefghi#keys-1",
    "did:example:123456789abcdefghi#keys-3",
    {
      "id": "did:example:123456789abcdefghi#keys-2",
      "type": "Ed25519VerificationKey2018",
      "controller": "did:example:123456789abcdefghi",
      "publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
    }
  ],

Example C: Use case 1b from above: In the following snippet from EXAMPLE 16...

  "service": [
... 
  {
    "id": "did:example:123456789abcdefghi;bops",
    "type": "BopsService",
    "serviceEndpoint": "https://bops.example.com/enterprise/"
  }]

Example D: Use case 1c "Other scenarios": If I added the following hypothetical extension to EXAMPLE 16:

{
  "@context": "https://example.org/example-method/v1",
  "id": "did:example:123456789abcdefghi",

  "authentication": [ ... ],

  "service": [ ... ],

  "thingamajig": [{
        "@context": "did:example:things:987654321",
        "id": "did:example:123456789abcdefghi#thing-1",
        ...
  }]
}
talltree commented 5 years ago

On Mon, Feb 25, 2019 at 6:15 AM Michael Herman (Toronto) < notifications@github.com> wrote:

@talltree https://github.com/talltree Based on your reply, please confirm that the following examples for the 3 use cases are correct:

Example A: Use case 1a from above: In the following snippet from EXAMPLE 16...

"publicKey": [{ "id": "did:example:123456789abcdefghi#keys-1", "type": "RsaVerificationKey2018", "controller": "did:example:123456789abcdefghi", "publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n" }, { "id": "did:example:123456789abcdefghi#keys-3", "type": "Ieee2410VerificationKey2018", "controller": "did:example:123456789abcdefghi", "publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n" }]

  • did:example:123456789abcdefghi#keys-1 will dereference to the following specific JSON string (no less and no more)?

{ "id": "did:example:123456789abcdefghi#keys-1", "type": "RsaVerificationKey2018", "controller": "did:example:123456789abcdefghi", "publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n" }

Correct.

  • if #keys-1 was used as is (without further qualification) elsewhere inside the EXAMPLE 16 DID Document, it would dereference to the above same JSON string (NLANM)?

I don't know what "NLANM" is, but I believe the answer to your question is that it would be illegal to use the same ID string twice within the JSON-LD doc because an unqualified string would always be qualified first. But we should double check with the JSON-LD experts on the list.

Example B: Another use case 1a example: In the following snippet from EXAMPLE 16...

"authentication": [ "did:example:123456789abcdefghi#keys-1", "did:example:123456789abcdefghi#keys-3", { "id": "did:example:123456789abcdefghi#keys-2", "type": "Ed25519VerificationKey2018", "controller": "did:example:123456789abcdefghi", "publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV" } ],

  • did:example:123456789abcdefghi#keys-2 will dereference to the following specific JSON string (no less and no more)?

    { "id": "did:example:123456789abcdefghi#keys-2", "type": "Ed25519VerificationKey2018", "controller": "did:example:123456789abcdefghi", "publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV" }

Yes.

  • if #keys-2 was used as is (without further qualification) elsewhere inside the EXAMPLE 16 DID Document, it would dereference to the above same JSON string (NLANM)?

Same answer as above.

Example C: Use case 1b from above: In the following snippet from EXAMPLE 16...

"service": [ ... { "id": "did:example:123456789abcdefghi;bops", "type": "BopsService", "serviceEndpoint": "https://bops.example.com/enterprise/" }]

  • did:example:123456789abcdefghi;bops will dereference to the following specific JSON string (no less and no more)?

    { "id": "did:example:123456789abcdefghi;bops", "type": "BopsService", "serviceEndpoint": "https://bops.example.com/enterprise/" }

Yes.

  • if ;bops was used as is (without further qualification) elsewhere inside the EXAMPLE 16 DID Document, it would dereference to the above same JSON string (NLANM)?

Same answer as above.

Example D: Use case 1c "Other scenarios": If I added the following hypothetical extension https://w3c-ccg.github.io/did-spec/#extensibility to EXAMPLE 16:

{ "@context": "https://example.org/example-method/v1", "id": "did:example:123456789abcdefghi",

"authentication": [ ... ],

"service": [ ... ],

"thingamajig": [{ "@context": "did:example:things:987654321", "id": "did:example:123456789abcdefghi#thing-1", ... }] }

  • did:example:123456789abcdefghi#thing-1 will dereference to the following specific JSON string (no less and no more)?

{ "@context": "did:example:things:987654321", "id": "did:example:123456789abcdefghi#thing-1", ... }

Yes.

  • if #thing-1 was used as is (without further qualification) elsewhere inside the extended EXAMPLE 16 DID Document, it would dereference to the above same JSON string (NLANM)?

That same darned answer as above :-)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/w3c-ccg/did-spec/issues/170#issuecomment-467026610, or mute the thread https://github.com/notifications/unsubscribe-auth/ADLkTbQnGM3dFl96UhJ5PrCxQuCLVvfWks5vQ_ANgaJpZM4a_ODO .