-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
w3-accounts #12
w3-accounts #12
Changes from 4 commits
a7bae92
aefa4f4
12af294
533d84e
b2b99bf
9e2840a
7ca4f8b
94ce498
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
# User Accounts | ||
|
||
![status:wip](https://img.shields.io/badge/status-wip-orange.svg?style=flat-square) | ||
[![hackmd-github-sync-badge](https://hackmd.io/8NywALT8Qp-cf0MSugZMDw/badge)](https://hackmd.io/8NywALT8Qp-cf0MSugZMDw) | ||
|
||
## Editors | ||
|
||
- [Irakli Gozalishvili](https://github.com/Gozala), [DAG House](https://dag.house/) | ||
|
||
## Authors | ||
|
||
- [Irakli Gozalishvili](https://github.com/Gozala), [DAG House](https://dag.house/) | ||
|
||
|
||
# Abstract | ||
|
||
|
||
In web3.storage we describe concept of an account as convenience for aggregating and managing capabilities across various user spaces under same identity, simplifying recovery and authorization flows. | ||
|
||
## Language | ||
|
||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119](https://datatracker.ietf.org/doc/html/rfc2119). | ||
|
||
|
||
# Introduction | ||
|
||
## Motivation | ||
|
||
In web3.storage users MAY create number of user spaces simply by generating asymmetric key pair. They MAY be delegated capabilities for other user spaces. Managing these delegations and keypairs across multiple spaces, agents and devices can get complicated. | ||
|
||
To address this we propose a concept of an account, which is a [principal][] that can be delegated all relevant capabilities across various user spaces. | ||
|
||
We also propose account authorization flow that would allowing allow authorized agent to act on behalf of the account [principal][]. | ||
|
||
|
||
# Terminology | ||
|
||
## Account | ||
|
||
User account is a [principal][] identified by [`did:mailto`][] (listed in a UCAN's `iss` or `aud` field). | ||
|
||
When user agent creates a new space, it MAY delegate full or subset of the capabilities to user account so they could be reclaimed by a user with another agent. | ||
|
||
> Example shows all capabilities to `did:key:zAlice` space been delegated to the user account `alice@web.mail` | ||
|
||
```ts! | ||
{ | ||
iss: "did:key:zAlice", | ||
aud: "did:mailto:alice@web.mail", | ||
att: [{ with: "did:key:zAlice", can: "*" }], | ||
exp: null, | ||
sig: "..." | ||
} | ||
``` | ||
|
||
## Delegations | ||
|
||
Agent MAY publish account delegations to a serivce so that they can be persisted and retrieved later with a different agent. | ||
|
||
> Invokes `access/delegate` asking web3.storage to record delegation from `did:key:zAlice` space to the `alice@web.mail` account. | ||
|
||
```ts | ||
{ | ||
iss: "did:key:zAgent", | ||
aud: "did:dns:web3.storage", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I seem to recall somewhere you were deciding between whether to use One tradeoff that comes to mind is that updates to Another tradeoff though is So for my edification: Why did you choose did:dns and not did:web? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. General idea is agnostic of choice between |
||
att: [{ | ||
with: "did:key:zAgent", | ||
can: "access/delegate", | ||
nb: { | ||
access: Link<{ | ||
iss: "did:key:zAlice", | ||
aud: "did:mailto:alice@web.mail", | ||
att: [{ with: "did:key:zAlice", can: "*" }], | ||
exp: null, | ||
sig: "..." | ||
}> | ||
} | ||
} | ||
}], | ||
sig: "..." | ||
} | ||
``` | ||
|
||
:::warning | ||
[Recipient validation][] requires wrapping actual delegation into `access/delegate` invocation, but in the future we may find a way to remove this requirement. | ||
::: | ||
|
||
## Authorization | ||
|
||
User MAY authorize an agent to represent their account by invoking `ucan/issue` capability with an audience where authorization is to be considered valid | ||
|
||
|
||
> Agent requests authorization to represent `alice@web.mail` with `did:key:zAgent` in the context of `web3.storage` | ||
|
||
```ts | ||
{ | ||
iss: "did:key:zAgent", | ||
aud: "did:dns:web3.storage", | ||
att: [{ | ||
with: "did:key:zAgent", | ||
can: "ucan/issue", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could it be like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's more like |
||
nb: { as: "did:mailto:alice@web.mail" } | ||
}] | ||
} | ||
``` | ||
|
||
### issue `with` | ||
|
||
Resource MUST be a [`did:key`][] URI. It represents a public key that user wishes to use for signing UCANs issued by DID in the [`nb.as`][issue `as`] field. | ||
|
||
### issue `as` | ||
|
||
Account MUST be a [`did:mailto`][] principal. It is an account that user wishes to be represented by [`did:key`][] in the [`with`][issue `with`] field. | ||
Gozala marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
## Verification | ||
|
||
Service MUST perform out of bound user verification e.g. send a link to the mailbox of the account by clicking which user would authorize agent to represent the account. | ||
Gozala marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
On succesful verification service MUST delegate corresponding `ucan/sign` capability to the [`did:key`][] it was requested [`with`][issue `with`]. | ||
|
||
Delegation represents authorization to issue [UCAN][]s with [`did:mailto`] account prinicipal which MAY be signed with [`did:key`] of the agent. | ||
|
||
|
||
```ts | ||
{ | ||
iss: "did:dns:web3.storage", | ||
aud: "did:mailto:alice@web.mail", | ||
att: [{ | ||
with: "did:dns:web3.storage", | ||
can: "ucan/sign", | ||
nb: { as: "did:key:zAgent" } | ||
}], | ||
exp: null | ||
sig: "..." | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Example below illustrates {
iss: "did:dns:web3.storage",
aud: "did:key:someone",
// Delegates some capability to the did:dns:web3.storage resource.
// Capability is not really important, it's just that it CAN delegate capability for `did:dns:web3.storage`
att: [{ can: "inbox/add", with: "did:dns:web3.storage" }],
sig: "..." // <- signed with did:key:zJune because proof above
// 👇 proof that did:key:zJune could issue ucan on behalf of did:dns:web3.storage
prf: [{
iss: "did:dns:web3.storage", // <- Maybe this should be did:key:root here
aud: "did:dns:web3.storage", // <- delegating to did:dns:web3.storage to align principals
// Says that UCAN's issued by `did:dns:web3.storage` may be signed by
// did:key:zJune.
// This basically says that did:key:zJune is a session key which expires in july
att: [{
with: "did:dns:web3.storage",
can: "ucan/sign",
nb: { as: "did:key:zJune" }
}],
exp: july,
sig: "..." // <- Must be signed by the key did:dns:web3.storage resolves to
}],
exp: hour
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @expede can you please provide feedback on this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Gozala wrt There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah just ignore this, I was sketching this while speaking to @expede over the call so it's pretty sloppy and out of the context here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hey @expede have you had a chance to consider this ? In our call, I believe you said you were ok with general idea, yet wanted to ponder more about actual representation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry for the post-merge feedback @Gozala !
@gobengo I've been thinking about this in a UCAN "standard library" as
I continue to find 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: {
iss: "did:key:june",
aud: "did:key:carol",
att: [{ can: "thing/doSomthing", with: "resource://example.com" }],
sig: "...",
prf: [
{
iss: "did:key:zBob",
aud: "did:dns:web3.storage",
att: [{
with: "resource://exmaple.com",
can: "thing/doSomething"
}],
exp: august2022,
sig: "..."
},
{
iss: "did:dns:web3.storage",
aud: "did:key:june",
att: [{
with: "did:dns:web3.storage",
can: "ucan/forward_all" // we can come up with a better label
}],
exp: november2022,
sig: "..."
}
]
} |
||
``` | ||
|
||
### sign `with` | ||
|
||
Authorization context, implying that this authorization MUST be considered valid by this recipient (`aud` matches this `with`). | ||
|
||
Other recipients MAY also recognize authorizations issued by trusted principals. | ||
|
||
|
||
### sign `aud` | ||
|
||
Audience of the [UCAN][] MUST be [`did:mailto`][] identifier of the account principal. This ensures that [principal alignment] requirement can be met when authorization is used as proof by an account. | ||
|
||
|
||
### sign `as` | ||
|
||
MUST be a [`did:key`][] of the principal which MAY sign [UCAN][]s issued by an account principal in [`aud`](#sign-aud). | ||
|
||
|
||
## Utilization | ||
|
||
Authorized agents MAY issue UCANs using account [`did:mailto`][] identifier, sign it with agent private key and add authorization to `prf` as proofs that it was authorized by recepient to do so. | ||
|
||
```ts! | ||
{ | ||
// UCAN issued by the account DID | ||
iss: "did:mailto:alice@web.mail", | ||
aud: "did:dns:web3.storage", | ||
// list stored data in did:key:zAlice space | ||
att: [{ | ||
with: "did:key:zAlice", | ||
can: "store/list" | ||
}], | ||
prf: [ | ||
// Proof that did:key:zAgent MAY sign UCANs issued | ||
// by did:mailto:alice@web.mail | ||
{ | ||
iss: "did:dns:web3.storage", | ||
aud: "did:mailto:alice@web.mail", | ||
att: [{ | ||
with: "did:dns:web3.storage", | ||
can: "ucan/sign", | ||
nb: { as: "did:key:zAgent" } | ||
}], | ||
exp: null | ||
sig: "..." | ||
}, | ||
// Proof that did:mailto:alice@web.mail has capability | ||
// to list stored data in did:key:zAlice space | ||
{ | ||
iss: "did:key:zAlice", | ||
aud: "did:mailto:alice@web.mail", | ||
att: [{ | ||
with: "did:key:zAlice", | ||
can: "*" | ||
}], | ||
exp: null, | ||
sig: "..." | ||
} | ||
] | ||
} | ||
``` | ||
|
||
|
||
# Limitations | ||
|
||
Using delegation from specific authority as an authorization proof limits it to the contexts where it is trusted. It is reasonable compromise when issued UCAN receipent is the same authority, but problematic in wider contexts. | ||
|
||
Long term we would like to upgrade this specification to [UCAN mailto][] so that authorization may be verifiable and not require trusting third-party that performed [verification][]. | ||
|
||
# Related Notes | ||
|
||
## Free provider | ||
|
||
web3.storage offers one "free provider" per account. It will be denied if `consumer` space is not specified or is the one that already has it. | ||
|
||
Note that adding "free provider" to the space is more than once has no effect _(even when obtained through different accounts)_, because space has set of providers, and "free provider" is either in that set or it is not. | ||
|
||
[UCAN mailto]:https://github.com/ucan-wg/ucan-mailto/ | ||
[`did:mailto`]:https://github.com/ucan-wg/did-mailto/ | ||
[principal]:https://github.com/ucan-wg/spec/blob/main/README.md#321-principals | ||
[recipient validation]:https://github.com/ucan-wg/spec/blob/main/README.md#621-recipient-validation | ||
[`did:key`]:https://w3c-ccg.github.io/did-method-key/ | ||
[issue `as`]:#issue-as | ||
[issue `with`]:#issue-with | ||
[UCAN]:https://github.com/ucan-wg/spec/ | ||
[principal alignment]:https://github.com/ucan-wg/spec/blob/main/README.md#62-principal-alignment | ||
[verification]:#Verification |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why have this be
did:mailto:
and notmailto:
?The former begs the question of how that did method works, i.e. how to create, read (resolve to did doc), update, and delete dids using that method. The spec for that seems to be a placeholder atm. Understandable, but still I'm struggling to imagine how exactly the read/resolve would work for a
did:mailto
.Using just
mailto:
URIs would sidestep needing to define the did method, and in this spec or ucans, we could define processing rules however we want, all without needing to shoehorn in did semantics.If we do really want to define/use a
did:mailto
, how would did resolution work (e.g. here is howdid:dns
resolution works)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because principals in UCAN spec are DIDs, if they were arbitrary URIs than using just
mailto:
URI would have made a lot more sense. Perhaps we can work towards allowing UCANs to use arbitrary URIs in principals, but I would pursue that separately and then update to justmailto:
as opposed to getting blocked on that.My plan had been do spec that out here https://github.com/ucan-wg/did-mailto, but I don't have bandwidth for that right now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In nutshell, resolution schema is you send them an email asking what's their DID document and they respond you back with did:key corresponding to their document