-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathreadme-template.hbs
More file actions
298 lines (223 loc) · 11.3 KB
/
readme-template.hbs
File metadata and controls
298 lines (223 loc) · 11.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# ezcap
[](https://github.com/digitalbazaar/ezcap/actions?query=workflow%3A%22Node.js+CI%22)
> An easy to use, opinionated Authorization Capabilities (zcap) client library
> for the browser and Node.js.
## Table of Contents
- [Background](#background)
- [Security](#security)
- [Install](#install)
- [Usage](#usage)
- [API Reference](#api-reference)
- [Contribute](#contribute)
- [Commercial Support](#commercial-support)
- [License](#license)
## Background
This library provides a client that browser and node.js applications can use to
interact with HTTP servers protected by zcap-based authorization. The library
is configured with secure and sensible defaults to help developers get started
quickly and ensure that their client code is production-ready.
## Security
The security characteristics of this library are largely influenced by design
decisions made by client and server software. For clients, implementers should
pay particular attention to secure private key management. For servers, security
characteristics are largely dependent on how carefully the server manages zcap
registrations, zcap invocations, and zcap delegations. Bugs or failures related
to client key management, or server zcap validity checking will lead to security
failures. It is imperative that implementers audit their implementations,
preferably via parties other than the implementer.
## Install
- Browsers and Node.js 14+ are supported.
- [Web Crypto API][] required. Older browsers and Node.js 14 must use a
polyfill.
To install from NPM:
```
npm install @digitalbazaar/ezcap
```
To install locally (for development):
```
git clone https://github.com/digitalbazaar/ezcap.git
cd ezcap
npm install
```
## Usage
* [Creating a Client](#creating-a-client)
* [Reading with a Root Capability](#reading-with-a-root-capability)
* [Writing with a Root Capability](#writing-with-a-root-capability)
* [Delegating a Capability](#delegating-a-capability)
* [Reading with a Delegated Capability](#reading-with-a-delegated-capability)
* [Writing with a Delegated Capability](#writing-with-a-delegated-capability)
* [Requesting with a Root Capability](#requesting-with-a-root-capability)
* [Requesting with a Delegated Capability](#requesting-with-a-delegated-capability)
### Creating a Client
Creating a zcap client involves generating cryptographic key material and then
using that key material to instantiate a client designed to operate on a
specific base URL.
```js
import {ZcapClient} from '@digitalbazaar/ezcap';
import * as didKey from '@digitalbazaar/did-method-key';
import {Ed25519Signature2020} from '@digitalbazaar/ed25519-signature-2020';
const didKeyDriver = didKey.driver();
// generate a DID Document and set of key pairs
const {didDocument, keyPairs} = await didKeyDriver.generate();
// create a new zcap client using the generated cryptographic material
const zcapClient = new ZcapClient({
didDocument, keyPairs, SuiteClass: Ed25519Signature2020
});
```
### Reading with a Root Capability
Reading data from a URL using a capability is performed in a way that is
very similar to using a regular HTTP client to perform an HTTP GET. Using
a root capability means that your client has been directly authorized to access
the URL, usually because it created the resource that is being accessed.
The term "root" means that your client is the "root of authority".
```js
const url = 'https://zcap.example/my-account/items';
// reading a URL using a zcap will result in an HTTP Response
const response = await zcapClient.read({url});
// retrieve the JSON data
const items = await response.json();
```
### Writing with a Root Capability
Writing data to URL using a capability is performed in a way that is
very similar to using a regular HTTP client to perform an HTTP POST. Using
a root capability means that your client has been directly authorized to
modify the resource at the URL, usually because it created the resource that is
being written to. The term "root" means that your client is the "root of
authority". In the example below, the server most likely registered the
client as being the root authority for the `/my-account` path on the server.
```js
const url = 'https://zcap.example/my-account/items';
const item = {label: 'Widget'};
// writing a URL using a zcap will result in an HTTP Response
const response = await zcapClient.write({url, json: item});
// process the response appropriately
const writtenItem = await response.json();
```
### Delegating a Capability
Delegating a capability consists of the client authorizing another entity to
use the capability. The example below uses a DID as the target for the
delegation. The returned `delegatedCapability` would need to be transmitted
to the entity identified by the delegation target so that they can use it
to access the resource.
```js
const invocationTarget = 'https://zcap.example/my-account/items';
const controller =
'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH';
const allowedActions = ['read'];
const delegatedCapability = zcapClient.delegate(
{invocationTarget, controller, allowedActions});
```
### Reading with a Delegated Capability
Reading with a delegated capability is similar to reading with a root
capability. The only difference is that the delegated capability needs to be
retrieved from somewhere using application-specific code and then passed
to the `read` method.
```js
const url = 'https://zcap.example/my-account/items/123';
// defined by your code
const capability = await getCapabilityFromDatabase({url});
// reading a URL using a zcap will result in an HTTP Response; the
// `invocationTarget` from the capability provides the URL if one is not
// specified; if a URL is specified, the capability's invocation target
// MUST be a RESTful prefix of or equivalent to the URL
const response = await zcapClient.read({capability});
// retrieve the JSON data
const items = await response.json();
```
### Writing with a Delegated Capability
Writing with a delegated capability is similar to writing with a root
capability. The only difference is that the delegated capability needs to be
retrieved from somewhere using application-specific code and then passed
to the `write` method.
```js
const item = {label: 'Widget'};
const url = 'https://zcap.example/my-account/items';
// defined by your code
const capability = await getCapabilityFromDatabase({url});
// writing a URL using a zcap will result in an HTTP Response; the
// `invocationTarget` from the capability provides the URL if one is not
// specified; if a URL is specified, the capability's invocation target
// MUST be a RESTful prefix of or equivalent to the URL
const response = await zcapClient.write({capability, json: item});
// process the response appropriately
const writtenItem = await response.json();
```
### Requesting with a Root Capability
In the event that the server API does not operate using HTTP GET and HTTP POST,
it is possible to create a zcap client request that uses other HTTP verbs. This
is done by specifying the HTTP `method` to use.
```js
const url = 'https://zcap.example/my-account/items';
const item = {count: 12};
// send a request to a URL by invoking a capability
const response = await zcapClient.request({url, method: 'patch', json: item});
// process the response appropriately
const updatedItem = await response.json();
```
### Requesting with a Delegated Capability
Performing an HTTP request with a delegated capability is similar to
doing the same with a root capability. The only difference is that the
delegated capability needs to be retrieved from somewhere using application-specific code and then passed to the `request` method.
```js
const item = {count: 12};
const url = 'https://zcap.example/my-account/items/123';
// defined by your code
const capability = await getCapabilityFromDatabase({url});
// invoking a capability against a URL will result in an HTTP Response; the
// `invocationTarget` from the capability provides the URL if one is not
// specified; if a URL is specified, the capability's invocation target
// MUST be a RESTful prefix of or equivalent to the URL
const response = await zcapClient.request(
{capability, method: 'patch', json: item});
// process the response appropriately
const updatedItem = await response.json();
```
## API Reference
The ezcap approach is opinionated in order to make using zcaps a pleasant
experience for developers. To do this, it makes two fundamental assumptions
regarding the systems it interacts with:
* The systems are HTTP-based and REST-ful in nature.
* The REST-ful systems center around reading and writing resources.
If these assumptions do not apply to your system, the
[zcap](https://github.com/digitalbazaar/zcap) library might
be a better, albeit more complex, solution for you.
Looking at each of these core assumptions more closely will help explain how designing systems to these constraints make it much easier to think about
zcaps. Let's take a look at the first assumption:
> The systems are HTTP-based and REST-ful in nature.
Many modern systems tend to have HTTP-based interfaces that are REST-ful in
nature. That typically means that most resource URLs are organized by namespaces, collections, and items:
`/<root-namespace>/<collection-id>/<item-id>`. In practice,
this tends to manifest itself as URLs that look like
`/my-account/things/1`. The ezcap approach maps the authorization model
in a 1-to-1 way to the URL. Following along with the example, the root
capability would then be `/my-account`, which you will typically create and
have access to. You can then take that root capability and delegate access
to things like `/my-account/things` to let entities you trust modify the
`things` collection. You can also choose to be more specific and only
delegate to `/my-account/things/1` to really lock down access. ezcap attempts
to keep things very simple by mapping URL hierarchy to authorization scope.
Now, let's examine the second assumption that makes things easier:
> The REST-ful systems center around reading and writing resources.
There is an incredible amount of flexibility that zcaps provide. You can
define a variety of actions: read, write, bounce, atomicSwap, start, etc.
However, all that flexibility adds complexity and one of the goals of ezcap
is to reduce complexity to the point where the solution is good enough for
80% of the use cases. A large amount of REST-ful interactions tend to
revolve around reading and writing collections and the items in those
collections. For this reason, there are only two actions that are exposed
by default in ezcap: read and write. Keeping the number of actions to a
bare minimum has allowed implementers to achieve very complex use cases with
very simple code.
These are the two assumptions that ezcap makes and with those two assumptions,
80% of all use cases we've encountered are covered.
{{>main}}
## Contribute
See [the contribute file](https://github.com/digitalbazaar/bedrock/blob/master/CONTRIBUTING.md)! PRs accepted.
If editing the README.md, please follow the
[standard-readme](https://github.com/RichardLitt/standard-readme) specification.
## Commercial Support
Commercial support for this library is available upon request from
Digital Bazaar: support@digitalbazaar.com
## License
[New BSD License (3-clause)](LICENSE) © Digital Bazaar
[Web Crypto API]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API