-
Notifications
You must be signed in to change notification settings - Fork 45
Inconsistent ABNF and related definitions #170
Comments
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 = 1*methodchar
methodchar = %x61-7A / DIGIT
method-specific-idstring = idstring *( ":" idstring )
idstring = 1*idchar
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 ***@***.***> 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
<#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*methodcharmethodchar = %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
<#170>, or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADLkTbUV_O9fURrWcMOBiRrZEoVaLh3gks5vOH8VgaJpZM4a_ODO>
.
|
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
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:
Then this URL would be called a URL, as would
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.
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
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
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.
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.
And if we are in the DID Document associated with that DID, then the absolute DID
and the relative DID
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
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. 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. |
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? |
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 ***@***.***> wrote:
What @jandrieu <https://github.com/jandrieu> mentions about the logical
inconsistency of absolute DID references vs. relative ones is discussed in
Issue #97 <#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
<#170 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADLkTZkgf8JVOluVd9ZJDXu8Gry_LEk-ks5vO0RSgaJpZM4a_ODO>
.
|
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. |
OK, so let's start with your fundamental objection:
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.
I would echo @dhh1128 in saying -- that is correct, and on purpose. So for example, So similarly, But I'm'a pause here - does this make sense so far? |
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 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. |
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.
No, it would not. The wallet would only use that string in an API call that expected a key URI.
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. 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 Can we agree that those are three different things?
|
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) 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, 2) 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) 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 4) 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 This is different from a service URI with a path, see below. 5) 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) This is a URI with the semantics "fetch the DID Doc, find a 7) This is a URI with the semantics "fetch the DID Doc, find a |
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 So if |
@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. |
On Tue, Feb 19, 2019 at 12:53 PM Joe Andrieu ***@***.***> 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 = 1*methodchar
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
|
@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 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:
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:
Then how does this query/path/fragment stuff work? If I then try to dereference a DID URI like 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, 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? |
@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:
Yeahhh that's a fine question. I'm not quite sure... Let me get back to you on this :) |
@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. |
@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
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 Because otherwise, like you say, aggregating the paths/queries/fragments would result in madness and broken URLs. |
@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. |
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 ***@***.***> 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
<#170 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADLkTXUJOX38VwvWeAYv_eqAAaqtOJ6Gks5vPLdSgaJpZM4a_ODO>
.
|
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@:
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. |
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 = 1*methodchar
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 ***@***.***> 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 ***@***.***>
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
> <#170 (comment)>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/ADLkTXUJOX38VwvWeAYv_eqAAaqtOJ6Gks5vPLdSgaJpZM4a_ODO>
> .
>
|
@talltree Oh! :) I just meant formatting on a github markdown level. But thank you for running it through a validator! |
@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 |
Aha, ok. So this is actually also on purpose, part of the design. The But anyways, so the mechanism is supposed to work like:
And then the service reference uri will look like Does that make sense? |
@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. |
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 |
@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. |
@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 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:
or
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. |
@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. |
@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. |
@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. |
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:
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. |
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. |
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. |
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 |
On Wed, Feb 20, 2019 at 7:17 AM Dmitri Zagidulin ***@***.***> 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 = 1*methodchar
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 Wed, Feb 20, 2019 at 7:35 AM Joe Andrieu ***@***.***> 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!)
|
On Wed, Feb 20, 2019 at 7:45 AM Joe Andrieu ***@***.***> 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
<#170 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADLkTSoUFlnswzvJKhTE01p9Bxe_OtN7ks5vPW1_gaJpZM4a_ODO>
.
|
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 |
On Fri, Feb 22, 2019 at 5:31 AM Michael Herman (Toronto) < ***@***.***> 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.
|
@talltree said
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. |
On Sat, Feb 23, 2019 at 5:20 PM Joe Andrieu ***@***.***> 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.
|
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. |
@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? |
On Sun, Feb 24, 2019 at 6:53 PM Michael Herman (Toronto) < ***@***.***> 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.
|
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 |
In EXAMPLE 16 (reproduced below):
EXAMPLE 16: Advanced DID Document example
|
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) < ***@***.***> 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
{
***@***.***": "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
<#170 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADLkTQfblleIPdMbNkBSarVDt4tHNbMEks5vQ4TtgaJpZM4a_ODO>
.
|
@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...
Example B: Another use case 1a example: In the following snippet from EXAMPLE 16...
Example C: Use case 1b from above: In the following snippet from EXAMPLE 16...
Example D: Use case 1c "Other scenarios": If I added the following hypothetical extension to EXAMPLE 16:
|
On Mon, Feb 25, 2019 at 6:15 AM Michael Herman (Toronto) < ***@***.***> 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:
{
***@***.***": "https://example.org/example-method/v1",
"id": "did:example:123456789abcdefghi",
"authentication": [ ... ],
"service": [ ... ],
"thingamajig": [{
***@***.***": "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)?
{
***@***.***": "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
<#170 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADLkTbQnGM3dFl96UhJ5PrCxQuCLVvfWks5vQ_ANgaJpZM4a_ODO>
.
|
So, why not just use If I understand the ABNF, after the DID URl would be separated from the In the IPID DID method, we are reserving the According to https://www.ietf.org/rfc/rfc3986.txt:
|
@jonnycrunch Can you provide some examples? ....perhaps related to the use cases in w3c/did-resolution#32? |
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
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:
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:
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
However, this seems inconsistent with the last statement in that paragraph:
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:
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:
However, this is significantly different from the generic URI syntax (RFC3986)
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.
A URI-reference is either a URI, or a relative-ref and a relative-ref has the following syntax:
If we attempt to follow that pattern more closely (yet combining the query & fragment parts to remove redundancy), I propose:
[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
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:
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
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:
which, in the PR is changed to
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 bedid: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
Which would refer to the openid service endpoint declaration in the DID Document and, based on my proposal,
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:
My comments therefore are in two parts:
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
My apologies this is so long.
I'd like @burnburn and @ChristopherA to comment on this.
The text was updated successfully, but these errors were encountered: