Closed Gozala closed 1 year ago
Thanks for the feedback @expede and you are right my example there is better served by using forwarding than trying to shoe horn ucan/sign
thing there. I did however conflated two different use cases and solutions.
Let me try and explain this other use case, which is what PR was about:
did:key:zSpace --[can:* with:did:key:zSpace]--> did:mailto:alice@web.mail
did:mailto:alice@web.mail -- [can:*, with:*] --> did:key:zAgent
Assuming we implement the forwarding Alice would be able to do thin on a new device:
did:key:zSpace --[can:* with:did:key:zSpace]--> did:mailto:alice@web.mail --
|
----------------------------------------------------------------------------
|
-> did:mailto:alice@web.mail -- [can:*, with:*] --> did:key:zAgent --
|
---------------------------------------------------------------------
|
-> did:key:zAgent -- [can:upload/list, with:did:key:zSpace] --> did:dns:web3.storage
However we still need to somehow create this delegation
did:mailto:alice@web.mail -- [can:*, with:*] --> did:key:zAgent
One option would be to:
did:mailto:alice@web.mail
did:mailto
documentsdid:mailto:alice@web.mail
to did:key:zAgent
While above option is certainly possible, I think it has ton of tradeoffs and requires out of the bound state sync and checks. I think we can do better by doing following:
{ can: "ucan/sign", with: did:key:authority, nb: { as: "did:key:zAgent" } }
capability after verifying that request is from Alice.
did:mailto:alice@web.mail
has key did:key:zAgent
(unless delegation has expired or has been revoked)All in all did:mailto:alice@web.mail -- [can:*, with:*] --> did:key:zAgent
this would look as a following UCAN
{
iss: "did:mailto:alice@web.mail",
aud: "did:key:zAgent",
att: [{ can: "*", with: "*" }],
prf: [{
iss: "did:dns:web3.storage",
aud: "did:mailto@alice@web.mail",
att: [{ can: "ucan/sign", with: "did:dns:web3.storage", nb: { as: "did:key:zAgent" } }],
exp: future,
sig: "..."
}],
exp: future,
sig: "..."
}
If did:dns:web3.storage
encounters βοΈ proof somewhere in the chain, it can resolve key for did:mailto:alice@web.mail
from the proof it issued to did:key:zAgent
and if signatures match, and non of it was revoked or expired it can consider this delegation valid.
It is worth pointing out that this is not tied to did:mailto, I think it can be used across all the DIDs that require some resolution scheme, it simply allows resolutions state to be captured inside the UCAN. It also means that even if keys in DID document got rotated there is a proof that some key was in there at the time when authority performed resolution.
It is true that DID document may update keys sooner than embedded snapshot expires. It is by design eventually consistent and authority is free to choose time window where drifts could be tolerated. Authority may also choose to perform DID resolution even if it is the snapshot is in the proofs, this merely offers a way to operate under conditions where actual resolution may be impractical.
Alternatively authority could delegate (or rather invoke) capability for updating local execution state. In the context of specific UCAN validation below proof would update local DID documents state, specifically merging keys into state.documents["did:mailto@alice@web.mail"]
{
iss: "did:dns:web3.storage",
aud: "did:mailto@alice@web.mail",
att: [{
can: "did/update", // <-- instruction to update local state of DID doc with id corresponding to `aud`.
with: "did:dns:web3.storage", // <-- authorization scope
nb: {
// basically stuff from https://www.w3.org/TR/did-core/#verification-method-properties
"keys-1": { // <- key id
"type": "Ed25519VerificationKey2020",
"controller": "did:example:pqrstuvwxyz0987654321",
"publicKeyMultibase": "zH3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
}
}
}],
exp: future,
sig: "..."
}
It recently occurred to me that this did key association is essentially equivalent to authentication cookies in browsers.
On login server sets some cookies which agent will send with every request allowing server to identify a user keep and keep them logged in.
Conceptually we do basically the same but with PKI. User authenticates with user DID + agent did:key. Authority (that performed verification) hands back signed delegation which just like cookie has expiry and when transmitted back can recognize user agent and keep them logged in.
As mdn puts it about cookies
It remembers stateful information for the stateless HTTP protocol.
It is exactly that stores stateful information inside UCAN to make them stateless & consequently offline friendly.
This framing clarifies some things that I had hard time articulating:
In last iteration of this idea I have changed it to look like:
{
iss: "did:web:web3.storage",
aud: "did:mailto@alice@web.mail",
att: [{
can: "did/update", // <-- instruction to update local state of DID doc with id corresponding to `aud`.
with: "did:web:web3.storage", // <-- authorization scope
nb: {
// keys to add remove to the identifier
"did:key:zH3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV": true
}
}],
exp: future,
sig: "..."
}
I have also started to realize that DIDs are really getting in the way here. In fact we don't need DIDs here we need petnames and ucan delegations basically create edge names
Specifically "did:web:web3.storage" says I assign did:key:zH3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV
petname "did:mailto@alice@web.mail". It's ok to assign other keys same petnames just like it's ok for same contact in my address book to have several phone numbers and email addresses.
Partner service could even use edge names to refer to them by surfacing relation that "web3.storage" calls this key a "alice@web.mail"
@gobengo I'm starting to think that maybe indeed not using did's in ucan principals would be more beneficial than trying to map local state onto DIDs which seem to imply that all the keys must be canonically resolvable
@Gozala it seems like just using petnames would mean that whenever we need to rotate our root key (even if it is rare), all the clients would have to also update their petname registry to know about the new key. If we use a canonically resolvable DID, then clients could re-resolve our did to know about the new intended keys. That way we can rotate our root key and all clients can run the same software/config as before, they just re-resolve our did.
@Gozala it seems like just using petnames would mean that whenever we need to rotate our root key (even if it is rare), all the clients would have to also update their petname registry to know about the new key.
I'm not sure I understand the problem here. Yes if we rotated our key and did:web:web3.storage
no longer contains key that signed the petname assignment you can no longer trust it because someone may have impersonated us.
If we use a canonically resolvable DID, then clients could re-resolve our did to know about the new intended keys. That way we can rotate our root key and all clients can run the same software/config as before, they just re-resolve our did.
I'm not sure I understand how this relates to above thread. It's not about us using canonically resolvable id vs not, it's about do our users need to have canonically resolvable DIDs or can we just give them petnames instead ? My argument with canonically resolvable things is that it's a lot of infrastructure requirements and perhaps in many cases it's unnecessary overhead and complexity that can crumble in bad network conditions.
maybe indeed not using did's in ucan principals would be more beneficial than trying to map local state onto DIDs which seem to imply that all the keys must be canonically resolvable
Can you expand on this? Do you mean only using did:key
rather than did:dns
for your top-level key?
This framing clarifies some things that I had hard time articulating:
FWIW I like the whole comment where this appears βοΈπ―π
basically create edge names
@gobengo perhaps I can help clarify a bit, because I also found this confusing until a recent conversation with @blaine who clarified that edgenames are possibly the more interesting thing. Christine's text is very petname-centric, but if you're going from petnames "up" to the rest of the world, or rest of world "down" to petnames, you need to cross through edgenames, which are verifiable via (e.g.) DKIM, DNS, etc.
Thanks for the feedback @expede and you are right my example there is better served by using forwarding than trying to shoe horn ucan/sign thing there. I did however conflated two different use cases and solutions.
Ooooh okay I think I see how you're thinking about this now. I was reading the previous post as focused on "who" ("sign as" this DID), rather than on the "what" (capabilities flowing "though" aligned iss/aud pairs). I definitely agree with the forwarding idea, which I think is just a naming thing in the can
at this point, so while naming is important, I think we're aligned on the actual mechanism! π
I'm not sure I understand how this relates to above thread. It's not about us using canonically resolvable id vs not, it's about do our users need to have canonically resolvable DIDs or can we just give them petnames instead ? My argument with canonically resolvable things is that it's a lot of infrastructure requirements and perhaps in many cases it's unnecessary overhead and complexity that can crumble in bad network conditions.
Definitely having petnames is great, but I think they're best thought of as a convenience mechanism, not as something to rely on.
Passkeys are great, because they enable us to abstract away the username, but they're also terrible because they 100% lock the user in to Google or Apple's infrastructure. The synchronization provided by google and apple is key, because passkeys without a synchronization mechanism would be terrible for users. Without it, a new phone => "Who dis?" everywhere on the internet.
Similarly, petname <=> edgename mapping works great in a p2p context if you have a link established to transport the names and mappings, but in many cases where this is useful, we don't have those. A petname in your phonebook isn't useful without a routeable edgename to map it to (e.g., that "Barack Obama" entry in my phone's contact db isn't very useful for actually calling Obama).
So, there are two (broad) use-cases here:
One motivating use-case with direct applicability to the authn question:
Assume I have access to w3storage, enabled by the WhoCAN (I'm going to keep calling them this π ) delegation that @Gozala has described here. I've delegated to a passkey, which is great βΒ until I need to access my data from a public terminal. Now I'm stuck βΒ I don't have access to my passkeys (phone battery died, lost/stolen phone, etc), and I'm in a situation where I don't really want to configure the computer I'm using with full passkey access.
So, instead, I type in my email address into the w3storage sign-in page, which can do the following:
In most cases, because the (obvious, but almost never used) MX lookup to determine better auth options isn't obvious, we don't use it. Using passkeys alone is great, but just hides the complexity in a complicated way that is more likely to break, especially in edge cases.
There are a bunch of other use-cases; but this comment is probably already long enough! Anyhow, I've been working on a spec for what we're calling NNS, the Name Name System:
https://talk.fission.codes/t/nns-the-name-name-system/3684
I would love it if this delegation stuff would work for NNS (in fact, I depend heavily on it!) π
Pulling the thread out of https://github.com/web3-storage/specs/pull/12#discussion_r1033958400 to continue further discussion.
Pasting comment from @expede below
Sorry for the post-merge feedback @Gozala !
@gobengo I've been thinking about this in a UCAN "standard library" as
msg/send
, which cuts across email, text messaging, message passing, etc etc.I continue to find
iss == aud
deeply strange. I agree with your comment "Maybe this should bedid:key:root here
".Rather than granting the ability to sign "as" another DID, I think it's cleaner to make this a "forwarding edge", which follows much more the capabilities worldview. I think that the end result is the same, so it's just naming.
BECAUSE we can substitute a link:
This is kind of like "signing as" Carol, but it's only at the level of authority, not identity. Alice saying "you can sign as Bob" is going to get really confusing unless you want to do DID management, which IMO should be at a DID layer. I think you can manage all of this cleanly at the layer of capabilities.
This is a powerful enough feature that has enough uses that I propose that we add this as a first-class feature to UCAN at some stage. In the meantime, I propose that we call this something other than "signing as".
Here's some delegations in this model:
Here's that last one concretely: