Skip to content

Commit

Permalink
feat: account revamp (#103)
Browse files Browse the repository at this point in the history
Based on #102

---------

Co-authored-by: Alan Shaw <alan.shaw@protocol.ai>
Co-authored-by: Benjamin Goering <171782+gobengo@users.noreply.github.com>
  • Loading branch information
3 people authored Jan 22, 2024
1 parent 29397d8 commit 4f08972
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 48 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/words-to-ignore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,7 @@ publicness
NameDescriptionPrincipalThe
fieldIssuerPrincipal
fieldAudiencePrincipal
verifier
verifier
fieldAccountPrincipal
installationIssuerPrincipal
iteratively
141 changes: 96 additions & 45 deletions w3-account.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Account
# W3 Account

![status:wip](https://img.shields.io/badge/status-wip-orange.svg?style=flat-square)

Expand All @@ -12,61 +12,93 @@

# Abstract

The w3 family of open protocols defines user interactions with self-certified [PKI] based namespaces. These namespaces can be accessed through delegated [UCAN] capabilities that must be synchronized across multiple user agents on multiple devices. Since this is an open and decentralized system, there are unique challenges in providing a user-friendly experience, which is addressed through the concept of an **account** as described in this specification.
The W3 protocol governs user interactions within self-certified Public Key Infrastructure (PKI)-based namespaces. Access control to these namespaces, for simplicity referred to as spaces, is managed through delegated capabilities in [UCAN] format.

Users access their spaces across various user agents operating on multiple devices. Here we introduce an [account] primitive designed to enable synchronization of access across authorized user agents with a user-friendly experience.

## 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

In w3 family of protocols, a namespace is identified by a [`did:key`] identifier, which means that the owner of that namespace _(private key holder)_ has absolute authority over it. They can delegate some or all of the capabilities for the resources under that namespace to any other [principal]. However, managing these delegations across multiple user agents on multiple devices presents several user experience challenges:
In the W3 protocol, a namespace, or space for short, corresponds to an asymmetric keypair and is identified by a [`did:key`] URI. The private key holder, is the [owner] of that namespace and has absolute authority over it. They can delegate limited or absolute authority over the namespace to any other [principal]. However, managing delegations across multiple user agents on multiple devices presents several user experience challenges:

1. To synchronizing namespace access across user agents they need to discover their [`did:key`] identifiers and level of access granted to them.
2. Recovering access in the case when all devices are lost becomes impossible.

To address these issues, we propose the concept of an account. An account SHOULD have a human-meaningful identifier such as email address. We propose use of email addresses as account identifiers so that derived [`did:mailto`] can act as the [principal] in the [UCAN] delegation chain. This creates [principal] that can be used to aggregate capabilities and manage them.

1. Synchronizing delegations to namespaces across multiple user agents on multiple devices is difficult because of the use of non-memorable [`did:key`] identifiers.
2. Recovering access if the user loses access to all devices is also a challenge.
Account can be used to solve both discovery and recovery problems:

To address these issues, we propose the concept of an account as a way to aggregate and manage capabilities under a human-meaningful identifier such as an email address.
1. Instead of user agents trying to discover each other in order to delegate capabilities, all capabilities get delegated to an account which is then used to re-delegate them as necessary to individual agents.
2. Recovery is possible even if all devices have been lost as long as the user retains control of their email, because an account can always delegate capabilities to new agents.

Specifically, we propose deriving an account identifier from a user-controlled email address in the form of a [`did:mailto`] identifier, which can act as the [principal] in [UCAN] delegation chains.
Agent authorization can use familiar email-based authorization flows providing a smooth onboarding experience and hide complexity of the underlying [PKI]. This approach also better reflects user intuition: they have ambient authority over owned spaces and can authorize user agents (think apps) giving them necessary level of access.

Using an account identifier based on a memorable email address solves the discovery problem, and email-based authorization flows provide a smoother onboarding experience by hiding the complexity of [PKI]. With this approach, users can aggregate all of their delegations under a single account identifier and re-delegate desired capabilities to other agents.
> ℹ️ This specification mainly focuses on [`did:mailto`] identifiers, but implementations are free to extend it to various other [DID methods].
>
> Also, note that [account] is defined as non [`did:key`] identifier because [`did:key`] identifiers can aggregate and re-delegate capabilities natively with [UCAN]s. [Account]s simply bring human-meaningful identifiers that users can type in on every agent. Use of out of bound authorization also frees users from key management.
> ℹ️ This specification mainly focuses on [`did:mailto`] identifiers, but it can be extended to various other types of identifiers.
## Serialization

# High-Level Concepts
[UCAN]s MUST be encoded with some [IPLD] codec. [DAG-CBOR] is RECOMMENDED.

## Concepts

## Roles

There are several distinct roles that [principals] may assume in described specification:

| Name | Description |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| Principal | The general class of entities that interact with a UCAN. Listed in the `iss` or `aud` field |
| Account | [Principal] identified by memorable identifier like [`did:mailto`]. |
| Agent | [Principal] identified by [`did:key`] identifier, representing a user in some application installation |
| Issuer | Principal sharing access. It is the signer of the [UCAN]. Listed in the `iss` field |
| Audience | Principal access is shared with. Listed in the `aud` field |

### Space

Namespace, or space for short, is an owned resource that can be shared. It corresponds to the asymmetric keypair and is identified by the [`did:key`] URI.

A space DID is always listed in the `with` field of the [UCAN] capability.

### Owner

The [owner] of the [space] is the holder of its private key. The space owner can share limited or full access to their owned space via a [UCAN] delegation issued by the [space] [`did:key`] and signed with the [space]'s private key.

### Account

An _account_ is a principal that is identified by a memorable identifier such as [`did:mailto`]. It can be used for the convenience of aggregating and managing capabilities across various user [agent]s. Additionally, an account can facilitate familiar user authorization and recovery flows.
An _account_ is a principal identified by a memorable identifier such as [`did:mailto`]. It is a principal that aggregates access to user spaces and that manages access of various user [agent]s.

An account enables familiar authorization and recovery email flows.

### Agent

An _agent_ is a [principal] that is identified by a [`did:key`] identifier. Users interact with a system through different _agents_ across multiple devices and applications. It is strongly RECOMMENDED that _agents_ use [non-extractable keys] when possible.
An _agent_ is a principal identified by a [`did:key`] identifier. Users interact with a system through different _agents_ across multiple devices and applications. _Agents_ SHOULD use [non-extractable keys] where possible.

> ℹ️ Note that _agents_ are meant to be ephemeral, implying that they could be disposed of or created on demand.
> ℹ️ Note that _agents_ are meant to be ephemeral, which means that they could be disposed of or created on demand.
### Authority

Authority is a trusted [DID] identifier. For example various subsystems may recognize signatures from a global service authority.

Various services run by different entities MAY also recognize each others authority and choose to trust their signatures as opposed to performing verification work.

# Protocol

## Overview

### Aggregating capabilities

Any [agent] identified by a [`did:key`] CAN delegate or re-delegate capabilities to an [account] identified by a [`did:mailto`] according to the [UCAN] specification. This CAN be used to delegate complete authority over a created namespace at the time of creation.
Any principal CAN delegate capabilities to an [account] identified by a [`did:mailto`] according to the [UCAN] specification. It is RECOMMENDED to delegate full authority over created namespace to the user [account] at creation to offer access recovery mechanism.

```mermaid
sequenceDiagram
actor Alice
participant App as 💻<br/><br/>w3up #32;
participant Space as 📦<br/><br/>did:key:z6Mkk…sxALi
participant Space as 📦<br/><br/>did:key:z7Gf…xSpace
participant Email as 📫 alice@web.mail
Expand All @@ -76,68 +108,78 @@ Alice -->> App: alice@web.mail
App->>Space:🔑 Create namespace
Space ->> Email: 🎫 Delegate capabilities
note over Space,Email:can:*<br/>with: ucan:*
note over Space,Email:can:*<br/>with: did:key:z7Gf…xSpace
```

> During the first run, a new namespace is generated and complete authority is delegated to the user account. Illustration leaves out steps in which application attempts to claim capabilities before deciding to create a new space.
> On first run, an application creates a new namespace and delegates full authority to the user account. For simplicity we omit steps where the application first requests access from an account before deciding to create a new space.
### Delegating capabilities

Any user CAN delegate or re-delegate capabilities to their peer by delegating to their [account] identified by a [`did:mailto`] _(which can be derived from their email address)_. It's worth noting that no setup is required from the delegate until they decide to invoke the delegated capability.
[Account] CAN authorize user agents by re-delegating a set of capabilities.

```mermaid
sequenceDiagram
participant Alice as 👩‍💻<br/><br/>did:key:z6Mkk…sxALi
participant Email as 📫 bob@gmail.com
participant Bob as 👨🏽‍💻 <br/><br/>did:key:z6Mkr…jnz2z
Alice ->> Email: 🎫 Delegate capabilities
note over Alice,Bob:<br/>with: space://z6Mkr…jnz2z<br/>can:store/add
note over Alice,Bob:<br/>with: did:key:z6Mkk…sxALi<br/>can:store/add
Email ->> Bob: 🎫 Delegate capabilities
```

> **Alice** delegates the `store/add` capability to **Bob**, who later creates an agent and re-delegates the capability to it.
> **Alice** delegates the `store/add` capability to **Bob**s [account]. Later **Bob**s user agent gets re-delegated the capability from the [account].
### Delegating capabilities
### Authorization

Delegating capabilities from an [account] identified by a [`did:mailto`] to an [agent] is less straightforward because the signing key is not self-evident from the delegation.
Delegations issued by a [`did:key`] principal are authorized by signing the payload with their private key. Delegations issued by a [`did:mailto`] principal are not authorized by signing over the payload as there is no private key associated with [`did:mailto`] to sign it with. Instead, such delegations are authorized through an interactive email flow in which the [account] holder is able to review and approve the requested authorization through an action.

To address this issue, we propose an extension to the [UCAN] specification that allows signing and verification of delegations issued by [`did:mailto`] without requiring a [`did:mailto`] key resolution.
Since there is no private key to sign the [UCAN] payload, we define an extension to the [UCAN] specification that introduces two new signature types that can be used in delegations issued by [`did:mailto`] principals.

We define two alternative signature types that have different trade-offs, and protocol implementers MAY choose to support either or both signature types.
We also define a verification mechanism for these signature types.

> ℹ️ The signatures for [account]s identified by other DID methods are not defined.
> ℹ️ The signatures for [account]s identified by other [DID methods] are not defined.
#### DomainKeys Identified Mail (DKIM) Signature
## Signature Types

An [account] identified with the [`did:mailto`] identifier MAY issue a delegation that is signed using a DomainKeys Identified Mail ([DKIM]) signature.
### DomainKeys Identified Mail (DKIM) Signature

The signature MUST be generated by sending a message from the email address of the [account] with a `Subject` header set to an [authorization payload].
> ⚠️ [w3up] implementation currently does not support this signature type.
The signer MUST derive the "DKIM payload" from the received message according to the [RFC6376] specification and encode it in UTF-8 encoding. The resulting bytes MUST be encoded as a [Nonstandard `VarSig` signature] with the `alg` parameter set to `"DKIM"`.
The [`did:mailto`] principal MAY issue a delegation signed using a DomainKeys Identified Mail ([DKIM]) signature.

##### Authorization Payload
This signature MUST be generated by sending a message from the [account] email address corresponding to the issuer [`did:mailto`] with the `Subject` header set to the [authorization payload].

> ℹ️ Note that the UCAN standard signing payload would results in large signatures. Therefore, we propose an alternative payload format.
The signer MUST derive the "DKIM payload" from the received message according to the [RFC6376] specification and encode it in UTF-8 encoding. Resulting bytes MUST be encoded as a [Nonstandard `VarSig` signature] with the `alg` parameter set to `"DKIM"`.

The UCAN data model MUST follow the structure specified in the [UCAN-IPLD Schema], but the `s` field should be omitted. The IPLD [link] of the data model must be derived and formatted according to the [ABNF] definition below, where `cid` refers to the derived link:
#### Authorization Payload

The [UCAN] data model for the desired delegation issued by [`did:mailto`] MUST be structured per [UCAN-IPLD Schema] specification, except for the `s` field, which MUST be omitted.

The IPLD [link] of constructed data model MUST be derived and used the `cid` when formatting according payload according to the following [ABNF] definition.

```abnf
auth := "I am signing ipfs://" cid "to grant access to this account"
cid := z[a-km-zA-HJ-NP-Z1-9]+
```

#### Authorization Session Signature
### Attestation Signature

Delegation MAY be authorized through an interactive email flow where the [account] holder is emailed a request to approve an authorization that gives an agent access to specific set of capabilities. If the user approves by clicking the embedded link, a signed [attestation] is issued that confirms that the delegation has been authorized through the interactive flow.

In this scenario a delegation issued by the [`did:mailto`] identifier MAY be signed using the _attestation signature_ type. This signature alone MUST NOT be considered as a valid authorization. A delegation signed with an _attestation signature_ MUST be accompanied with a [UCAN attestation] issued by the trusted [authority].

If delegation is signed with an _attestation signature_, but is not accompanied with a [UCAN attestation] from a trusted [authority] it MUST be considered invalid. In this scenario the implementer MAY initiate an interactive verification flow and issue the [UCAN attestation] retroactively instead of denying service.

Delegation issued by [account] identified with the [`did:mailto`] identifier MAY be
signed using _authorization session signature_. However, this signature alone does not verify that the [account] owner authorized the delegation. For this reason, the delegation MUST also have an accompanying [authorization session] issued by a trusted [authority] that confirms the authorization by the [account] owner. In situations where the [authorization session] is not present in the proof, the validator is required to obtain it through an out-of-band authorization flow upon request. Failure to carry out this authorization flow will result in the signature being considered invalid.
> When the received delegation is issued by the `did:mailto:web.mail:alice`, signed with _attestation signature_, but is not accompanied by a [UCAN attestation], the receiver could iteratively confirm authorization by sending an email to `alice@web.mail` with a confirmation link, which, when followed, issues an [attestation] from the receiver resuming the invocation.
##### Authorization Session Signature Format
#### Attestation Signature Format

The authorization session signature is denoted by a [Nonstandard `VarSig` signature] with zero (`0`) signature bytes.
The attestation signature is denoted by a [Nonstandard `VarSig` signature] with zero (`0`) signature bytes.

##### Authorization Session Signature Example
##### Attestation Signature Example

> Authorization Session Signature in [DAG-JSON] format
> Attestation Signature in [DAG-JSON] format
```jSON
{ "/": { "bytes": "gKADAA" } }
Expand Down Expand Up @@ -180,10 +222,10 @@ Examples
[Protocol Labs]:https://protocol.ai/
[Irakli Gozalishvili]:https://github.com/Gozala
[PKI]:https://en.wikipedia.org/wiki/Public_key_infrastructure
[ucan]: https://github.com/ucan-wg/spec/
[`did:mailto`]: https://github.com/ucan-wg/did-mailto/
[`did:key`]: https://w3c-ccg.github.io/did-method-key/
[principal]:https://github.com/ucan-wg/spec/#321-principals
[UCAN]:https://github.com/ucan-wg/spec/blob/692e8aab59b763a783fe1484131c3f40d997b69a/README.md
[`did:mailto`]:./did-mailto.md
[`did:key`]:https://w3c-ccg.github.io/did-method-key/
[principal]:https://github.com/ucan-wg/spec/blob/692e8aab59b763a783fe1484131c3f40d997b69a/README.md#321-principals
[non-extractable keys]:https://crypto.stackexchange.com/questions/85587/what-do-people-use-non-extractable-webcrypto-keys-for/102695#102695
[agent]:#agent
[account]:#account
Expand All @@ -194,4 +236,13 @@ Examples
[Nonstandard `VarSig` signature]:https://github.com/ucan-wg/ucan-ipld/#251-nonstandard-signatures
[ABNF]:https://en.wikipedia.org/wiki/Augmented_Backus%E2%80%93Naur_form
[DAG-JSON]:https://ipld.io/specs/codecs/dag-json/spec/
[authorization session]:./w3-session.md
[ucan attestation]:./w3-ucan.md#attestation
[IPLD]: https://ipld.io/
[DAG-CBOR]: https://ipld.io/specs/codecs/dag-cbor/spec/
[DID methods]:https://www.w3.org/TR/did-core/#methods
[w3up]:https://github.com/web3-storage/w3up
[owner]:#owner
[space]:#space
[DKIM]:https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail
[attestation]:./w3-ucan.md#attestation
[authority]:#authority
3 changes: 1 addition & 2 deletions w3-ucan.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,7 @@ In other words it is desired to have ability to grant revocation power to some a

### Proposal

We propose extension to the core [UCAN] specification and define `ucan/revoke`
capability, that can be invoked to revoke a linked [UCAN].
We propose extension to the core [UCAN] specification and define `ucan/revoke` capability, that can be invoked to revoke a linked [UCAN].

By making revocation a [UCAN] itself we allow delegating the ability to revoke to another principal, which is desired in scenario described above.

Expand Down

0 comments on commit 4f08972

Please sign in to comment.