forked from DecentralizedClimateFoundation/DCIPs
331 lines
17 KiB
Markdown
331 lines
17 KiB
Markdown
---
|
|
eip: 5573
|
|
title: Sign-In with Ethereum Capabilities, ReCaps
|
|
description: Mechanism on top of Sign-In with Ethereum for informed consent to delegate capabilities with an extensible scope mechanism
|
|
author: Oliver Terbu (@awoie), Jacob Ward (@cobward), Charles Lehner (@clehner), Sam Gbafa (@skgbafa), Wayne Chang (@wyc), Charles Cunningham (@chunningham)
|
|
discussions-to: https://ethereum-magicians.org/t/eip-5573-siwe-recap
|
|
status: Draft
|
|
type: Standards Track
|
|
category: ERC
|
|
created: 2021-07-20
|
|
requires: 4361
|
|
---
|
|
|
|
## Abstract
|
|
|
|
[ERC-4361](./eip-4361.md), or Sign-In with Ethereum (SIWE), describes how Ethereum accounts authenticate with off-chain services. This proposal, known as ReCaps, describes a mechanism on top of SIWE to give informed consent to authorize a Relying Party to exercise certain scoped capabilities. How a Relying Party authenticates against the target resource is out of scope for this specification and depends on the implementation of the target resource.
|
|
|
|
## Motivation
|
|
|
|
SIWE ReCaps unlock integration of protocols and/or APIs for developers by reducing user friction, onchain state and increasing security by introducing informed consent and deterministic capability objects on top of Sign-In With Ethereum (ERC-4361).
|
|
|
|
While SIWE focuses on authenticating the Ethereum account against the service (relying party or SIWE client) initiating the SIWE flow, there is no canonical way for the authenticated Ethereum account to authorize a relying party to interact with a third-party service (resource service) on behalf of the Ethereum account. A relying party may want to interact with another service on behalf of the Ethereum account, for example a service that provides data storage for the Ethereum account. This specification introduces a mechanism that allows the service (or more generally a Relying Party) to combine authentication and authorization of such while preserving security and optimizing UX.
|
|
|
|
Note, this approach is a similar mechanism to combining OpenID Connect (SIWE auth) and OAuth2 (SIWE ReCap) where SIWE ReCap implements capabilities-based authorization on top of the authentication provided by SIWE.
|
|
|
|
## Specification
|
|
|
|
This specification has three different audiences:
|
|
|
|
- Web3 application developers that want to integrate ReCaps to authenticate with any protocols and APIs that support object capabilities.
|
|
- Protocol or API developers that want to learn how to define their own ReCaps.
|
|
- Wallet implementers that want to improve the UI for ReCaps.
|
|
|
|
### Terms and Definitions
|
|
|
|
- ReCap - A SIWE Message complying with this specification, i.e. containing at least one ReCap URI in the `Resources` section and the corresponding human-readable ReCap Statement appended to the SIWE `statement`.
|
|
- ReCap URI - A type of URI that resolves to a ReCap Details Object.
|
|
- ReCap Details Object - A JSON object describing the actions and optionally the resources associated with a ReCap Capability.
|
|
- Resource Service (RS) - The entity that is providing third-party services for the Ethereum account.
|
|
- SIWE Client (SC) - The entity initiating the authorization (SIWE authentication and ReCap flow).
|
|
- Relying Party (RP) - same as SC in the context of authorization.
|
|
|
|
### Overview
|
|
|
|
This specification defines the following:
|
|
|
|
- ReCap SIWE Extension
|
|
- ReCap Capability
|
|
- ReCap URI Scheme
|
|
- ReCap Details Object Schema
|
|
- ReCap Translation Algorithm
|
|
- ReCap Verification
|
|
|
|
### ReCap SIWE Extension
|
|
|
|
A ReCap is an ERC-4361 message following a specific format that allows an Ethereum account to delegate a set of ReCap Capabilities to a Relying Party through informed consent. ReCap Capabilities MUST be represented by the final entry in the `Resources` array of the SIWE message that MUST deterministically translate the ReCap Capability in human-readable form to the `statement` field in the SIWE message using the ReCap Translation Algorithm.
|
|
|
|
The following SIWE message fields are used to further define (or limit) the scope of all ReCap Capabilities:
|
|
|
|
- The `URI` field MUST specify the intended Relying Party, e.g., `https://example.com`, `did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK`. It is expected that the RS authenticates the Relying Party before invoking an action for the ReCap Capability.
|
|
- The `Issued At` field MUST be used to specify the issuance date of the ReCap Capabilities.
|
|
- If present, the `Expiration Time` field MUST be used as the expiration time of the ReCap Capabilities, i.e. the time at which the RS will no longer accept an invocation of the capabilities expressed in this form.
|
|
- If present, the `Not Before` field MUST be used as the time that has to expire before the RS starts accepting invocations of the capabilities expressed in the message.
|
|
|
|
The following is a non-normative example of a SIWE message with the SIWE ReCap Extension:
|
|
|
|
```text
|
|
example.com wants you to sign in with your Ethereum account:
|
|
0x0000000000000000000000000000000000000000
|
|
|
|
I further authorize the stated URI to perform the following actions on my behalf: (1) "example": "append", "read" for "https://example.com". (2) "other": "action" for "https://example.com". (3) "example": "append", "delete" for "my:resource:uri.1". (4) "example": "append" for "my:resource:uri.2". (5) "example": "append" for "my:resource:uri.3".
|
|
|
|
URI: did:key:example
|
|
Version: 1
|
|
Chain ID: 1
|
|
Nonce: mynonce1
|
|
Issued At: 2022-06-21T12:00:00.000Z
|
|
Resources:
|
|
- urn:recap:eyJhdHQiOnsiaHR0cHM6Ly9leGFtcGxlLmNvbSI6eyJleGFtcGxlL2FwcGVuZCI6W10sImV4YW1wbGUvcmVhZCI6W10sIm90aGVyL2FjdGlvbiI6W119LCJteTpyZXNvdXJjZTp1cmkuMSI6eyJleGFtcGxlL2FwcGVuZCI6W10sImV4YW1wbGUvZGVsZXRlIjpbXX0sIm15OnJlc291cmNlOnVyaS4yIjp7ImV4YW1wbGUvYXBwZW5kIjpbXX0sIm15OnJlc291cmNlOnVyaS4zIjp7ImV4YW1wbGUvYXBwZW5kIjpbXX19LCJwcmYiOltdfQ
|
|
```
|
|
|
|
#### ReCap Capability
|
|
|
|
A ReCap Capability is identified by their ReCap URI that resolves to a ReCap Details Object which defines the associated actions and optional target resources. The scope of each ReCap Capability is attenuated by common fields in the SIWE message as described in the previous chapter, e.g., `URI`, `Issued At`, `Expiration Time`, `Not Before`.
|
|
|
|
##### ReCap URI Scheme
|
|
|
|
A ReCap URI starts with `urn:recap:` followed by `:` and the unpadded base64url-encoded payload of the ReCap Details Object. Note, the term base64url is defined in RFC4648 - Base 64 Encoding with URL and Filename Safe Alphabet. If present, a Recap URI MUST occupy the final entry of the SIWE resource list.
|
|
|
|
The following is a non-normative example of a ReCap Capability:
|
|
|
|
```text
|
|
urn:recap:eyJhdHQiOnsiaHR0cHM6Ly9leGFtcGxlLmNvbS9waWN0dXJlcy8iOnsiY3J1ZC9kZWxldGUiOltdLCJjcnVkL3VwZGF0ZSI6W10sIm90aGVyL2FjdGlvbiI6W119LCJtYWlsdG86dXNlcm5hbWVAZXhhbXBsZS5jb20iOnsibXNnL3JlY2VpdmUiOlt7Im1heF9jb3VudCI6NSwidGVtcGxhdGVzIjpbIm5ld3NsZXR0ZXIiLCJtYXJrZXRpbmciXX1dLCJtc2cvc2VuZCI6W3sidG8iOiJzb21lb25lQGVtYWlsLmNvbSJ9LHsidG8iOiJqb2VAZW1haWwuY29tIn1dfX0sInByZiI6WyJiYWZ5YmVpZ2s3bHkzcG9nNnV1cHhrdTNiNmJ1YmlycjQzNGliNnRmYXltdm94NmdvdGFhYWFhYWFhYSJdfQ
|
|
```
|
|
|
|
##### Ability Strings
|
|
|
|
Ability Strings identify an action or Ability within a Namespace. They are serialized as `<namespace>/<ability>`. Namespaces and Abilities MUST contain only alphanumeric characters as well as the characters `.`, `*`, `_`, `+`, `-`, conforming to the regex `^[a-zA-Z0-9.*_+-]$`. The ability string as a whole MUST conform to `^[a-zA-Z0-9.*_+-]+\/[a-zA-z0-9.*_+-]+$`. For example, `crud/update` has an ability-namespace of `crud` and an ability-name of `update`.
|
|
|
|
##### ReCap Details Object Schema
|
|
|
|
The ReCap Details Object denotes which actions on which resources the Relying Party is authorized to invoke on behalf of the Ethereum account for the validity period defined in the SIWE message. It can also contain additional information that the RS may require to verify a capability invocation. A ReCap Details Object MUST follow the following JSON Schema:
|
|
|
|
```jsonc
|
|
{
|
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
"type": "object",
|
|
"properties": {
|
|
"att": {
|
|
"type": "object",
|
|
"propertyNames": {
|
|
"format": "uri"
|
|
},
|
|
"patternProperties": {
|
|
"^.+:.*$": {
|
|
"type": "object",
|
|
"patternProperties": {
|
|
"^[a-zA-Z0-9.*_+-]+\/[a-zA-z0-9.*_+-]+$": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object"
|
|
}
|
|
}
|
|
},
|
|
"additionalProperties": false,
|
|
"minProperties": 1
|
|
}
|
|
},
|
|
"additionalProperties": false,
|
|
"minProperties": 1
|
|
},
|
|
"prf": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string",
|
|
"format": "CID"
|
|
},
|
|
"minItems": 1
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
A ReCap Details Object defines the following properties:
|
|
|
|
- `att`: (CONDITIONAL) If present, `att` MUST be a JSON object where each key is a URI and each value is an object containing Ability Strings as keys and a corresponding value which is an array of qualifications to the action (i.e. a restriction or requirement). The keys of the object MUST be ordered lexicographically.
|
|
- `prf`: (CONDITIONAL) If present, `prf` MUST be a JSON array of string values with at least one entry where each value is a valid Base58-encoded CID which identifies a parent capability, authorizing the Ethereum account for one or more of the entries in `att` if the SIWE `address` does not identify the controller of the `att` entries.
|
|
|
|
Objects in the `att` field (including nested objects) MUST NOT contain duplicate keys and MUST have their keys ordered lexicographically with two steps:
|
|
|
|
1. Sort by byte value.
|
|
2. If a string starts with another, the shorter string comes first (e.g. `msg/send` comes before `msg/send-to`)
|
|
|
|
This is the same as the `Array.sort()` method in Javascript. In the example below, `crud/delete` must appear before `crud/update` and `other/action`, similarly `msg/receive` must appear before `msg/send`.
|
|
|
|
The following is a non-normative example of a ReCap Capability Object with `att` and `prf`:
|
|
|
|
```jsonc
|
|
{
|
|
"att":{
|
|
"https://example.com/pictures/":{
|
|
"crud/delete": [],
|
|
"crud/update": [],
|
|
"other/action": []
|
|
},
|
|
"mailto:username@example.com":{
|
|
"msg/receive": [{
|
|
"max_count": 5,
|
|
"templates": ["newsletter", "marketing"]
|
|
}],
|
|
"msg/send": [{ "to": "someone@email.com" }, { "to": "joe@email.com" }]
|
|
}
|
|
},
|
|
"prf":["bafybeigk7ly3pog6uupxku3b6bubirr434ib6tfaymvox6gotaaaaaaaaa"]
|
|
}
|
|
```
|
|
|
|
In the example above, the Relying Party is authorized to perform the actions `crud/update`, `crud/delete` and `other/action` on resource `https://example.com/pictures` without limitations for any. Additionally the Relying Party is authorized to perform actions `msg/send` and `msg/recieve` on resource `mailto:username@example.com`, where `msg/send` is limited to sending to `someone@email.com` or `joe@email.com` and `msg/recieve` is limited to a maximum of 5 and templates `newsletter` or `marketing`. Note, the Relying Party can invoke each action individually and independently from each other in the RS. Additionally the ReCap Capability Object contains some additional information that the RS will need during verification. The responsibility for defining the structure and semantics of this data lies with the RS. These action and restriction semantics are examples not intended to be universally understood.
|
|
|
|
It is expected that RS implementers define which resources they want to expose through ReCap Details Objects and which actions they want to allow users to invoke on them.
|
|
|
|
This example is expected to transform into the following `recap-transformed-statement` (for `URI` of `https://example.com`):
|
|
|
|
```text
|
|
I further authorize the stated URI to perform the following actions on my behalf: (1) "crud": "delete", "update" for "https://example.com/pictures". (2) "other": "action" for "https://example.com/pictures". (3) "msg": "recieve", "send" for "mailto:username@example.com".
|
|
```
|
|
|
|
This example is also expected to transform into the following `recap-uri`:
|
|
|
|
```text
|
|
urn:recap:eyJhdHQiOnsiaHR0cHM6Ly9leGFtcGxlLmNvbS9waWN0dXJlcy8iOnsiY3J1ZC9kZWxldGUiOltdLCJjcnVkL3VwZGF0ZSI6W10sIm90aGVyL2FjdGlvbiI6W119LCJtYWlsdG86dXNlcm5hbWVAZXhhbXBsZS5jb20iOnsibXNnL3JlY2VpdmUiOlt7Im1heF9jb3VudCI6NSwidGVtcGxhdGVzIjpbIm5ld3NsZXR0ZXIiLCJtYXJrZXRpbmciXX1dLCJtc2cvc2VuZCI6W3sidG8iOiJzb21lb25lQGVtYWlsLmNvbSJ9LHsidG8iOiJqb2VAZW1haWwuY29tIn1dfX0sInByZiI6WyJiYWZ5YmVpZ2s3bHkzcG9nNnV1cHhrdTNiNmJ1YmlycjQzNGliNnRmYXltdm94NmdvdGFhYWFhYWFhYSJdfQ
|
|
```
|
|
|
|
##### Merging Capability Objects
|
|
|
|
Any two Recap objects can be merged together by recursive concatenation of their field elements as long as the ordering rules of the field contents is followed. For example, two recap objects:
|
|
|
|
```jsonc
|
|
{
|
|
"att": {
|
|
"https://example1.com": {
|
|
"crud/read": []
|
|
}
|
|
},
|
|
"prf": ["bafyexample1"]
|
|
}
|
|
|
|
{
|
|
"att": {
|
|
"https://example1.com": {
|
|
"crud/update": [{
|
|
"max_times": 1
|
|
}]
|
|
},
|
|
"https://example2.com": {
|
|
"crud/delete": []
|
|
}
|
|
},
|
|
"prf": ["bafyexample2"]
|
|
}
|
|
```
|
|
|
|
combine into:
|
|
|
|
```jsonc
|
|
{
|
|
"att": {
|
|
"https://example1.com": {
|
|
"crud/read": [],
|
|
"crud/update": [{
|
|
"max_times": 1
|
|
}]
|
|
},
|
|
"https://example2.com": {
|
|
"crud/delete": []
|
|
}
|
|
},
|
|
"prf": ["bafyexample1", "bafyexample2"]
|
|
}
|
|
```
|
|
|
|
#### ReCap Translation Algorithm
|
|
|
|
After applying the ReCap Translation Algorithm on a given SIWE message that MAY include a pre-defined `statement`, the `recap-transformed-statement` in a ReCap SIWE message MUST conform to the following ABNF:
|
|
|
|
```text
|
|
recap-transformed-statement = statement recap-preamble 1*(" " recap-statement-entry ".")
|
|
; see ERC-4361 for definition of input-statement
|
|
recap-preamble = "I further authorize the stated URI to perform the following actions on my behalf:"
|
|
recap-statement-entry = "(" number ") " action-namespace ": "
|
|
action-name *("," action-name) "for"
|
|
recap-resource
|
|
; see RFC8259 for definition of number
|
|
ability-namespace = string
|
|
; see RFC8259 for definition of string
|
|
ability-name = string
|
|
; see RFC8259 for definition of string
|
|
recap-resource = string
|
|
; see RFC8259 for definition of string
|
|
```
|
|
|
|
The following algorithm or an algorithm that produces the same output MUST be performed to generate the SIWE ReCap Transformed Statement.
|
|
|
|
Inputs:
|
|
|
|
- Let `recap-uri` be a ReCap URI, which represents the ReCap Capabilities that are to be encoded in the SIWE message, and which contains a ReCap Details Object which conforms to the ReCap Details Object Schema.
|
|
- [Optional] Let `statement` be the statement field of the input SIWE message conforming to ERC-4361.
|
|
Algorithm:
|
|
- Let `recap-transformed-statement` be an empty string value.
|
|
- If `statement` is present, do the following:
|
|
- Append the value of the `statement` field of `siwe` to `recap-transformed-statement`.
|
|
- Append a single space character `" "` to `recap-transformed-statement`.
|
|
- Append the following string to `recap-transformed-statement`: `"I further authorize the stated URI to perform the following actions on my behalf:"`.
|
|
- Let `numbering` be an integer starting with 1.
|
|
- Let `attenuations` be the `att` field of the ReCap Details Object
|
|
- For each key and value pair in `attenuations` (starting with the first entry), perform the following:
|
|
- Let `resource` be the key and `abilities` be the value
|
|
- Group the keys of the `abilities` object by their `ability-namespace`
|
|
- For each `ability-namespace`, perform the following:
|
|
- Append the string concatenation of `" ("`, `numbering`, `")"` to `recap-transformed-statement`.
|
|
- Append the string concatenation of `"`, `ability-namespace`, `":` to `recap-transformed-statement`.
|
|
- For each `ability-name` in the `ability-namespace` group, perform the following:
|
|
- Append the string concatenation of `"`, `ability-name`, `"` to `recap-transformed-statement`
|
|
- If not the final `ability-name`, append `,` to `recap-transformed-statement`
|
|
- Append `for "`, `resource`, `".` to `recap-transformed-statement`
|
|
- Increase `numbering` by 1
|
|
- Return `recap-transformed-statement`.
|
|
|
|
#### ReCap Verification Algorithm
|
|
|
|
The following algorithm or an algorithm that produces the same output MUST be performed to verify a SIWE ReCap.
|
|
|
|
Inputs:
|
|
|
|
- Let `recap-siwe` be the input SIWE message conforming to ERC-4361 and this EIP.
|
|
- Let `siwe-signature` be the output of signing `recap-siwe`, as defined in ERC-4361.
|
|
Algorithm:
|
|
- Perform ERC-4361 signature verification with `recap-siwe` and `siwe-signature` as inputs.
|
|
- Let `uri` be the uri field of `recap-siwe`.
|
|
- Let `recap-uri` be a recap URI taken from the last entry of the resources field of `recap-siwe`.
|
|
- Let `recap-transformed-statement` be the result of performing the above `ReCap Translation Algorithm` with `uri` and `recap-uri` as input.
|
|
- Assert that the statement field of `recap-siwe` ends with `recap-transformed-statement`.
|
|
|
|
### Implementer's Guide
|
|
|
|
TBD
|
|
|
|
#### Web3 Application Implementers
|
|
|
|
TBD
|
|
|
|
#### Wallet Implementers
|
|
|
|
TBD
|
|
|
|
#### Protocol or API Implementers
|
|
|
|
TBD
|
|
|
|
## Rationale
|
|
|
|
TBD
|
|
|
|
## Security Considerations
|
|
|
|
Resource service implementer's should not consider ReCaps as bearer tokens but instead require to authenticate the Relying Party in addition. The process of authenticating the Relying Party against the resource service is out of scope of this specification and can be done in various different ways.
|
|
|
|
## Copyright
|
|
|
|
Copyright and related rights waived via [CC0](../LICENSE.md).
|