npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@digitalbazaar/ezcap

v4.1.0

Published

[![Node.js CI](https://github.com/digitalbazaar/ezcap/workflows/Node.js%20CI/badge.svg)](https://github.com/digitalbazaar/ezcap/actions?query=workflow%3A%22Node.js+CI%22)

Downloads

1,561

Readme

ezcap

Node.js CI

An easy to use, opinionated Authorization Capabilities (zcap) client library for the browser and Node.js.

Table of Contents

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

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".

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.

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.

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.

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.

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.

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.

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

Classes

Functions

Typedefs

ZcapClient

Kind: global class

new ZcapClient(options)

Creates a new ZcapClient instance that can be used to perform requests against HTTP URLs that are authorized via Authorization Capabilities (ZCAPs).

Returns: ZcapClient - - The new ZcapClient instance.

| Param | Type | Description | | --- | --- | --- | | options | object | The options to use. | | options.SuiteClass | LinkedDataSignatureSuiteClass | The LD signature suite class to use to sign requests and delegations. | | [options.didDocument] | object | A DID Document that contains capabilityInvocation and capabilityDelegation verification relationships; didDocument and keyPairs, or invocationSigner and delegationSigner must be provided in order to invoke or delegate zcaps, respectively. | | [options.keyPairs] | Map | A map of key pairs associated with didDocument indexed by key pair; didDocument and keyPairs, or invocationSigner and delegationSigner must be provided in order to invoke or delegate zcaps, respectively. | | [options.delegationSigner] | object | An object with a .sign() function and id and controller properties that will be used for delegating zcaps; delegationSigner or didDocument and keyPairs must be provided to delegate zcaps. | | [options.invocationSigner] | object | An object with a .sign() function and id and controller properties that will be used for signing requests; invocationSigner or didDocument and keyPairs must be provided to invoke zcaps. | | [options.agent] | HttpsAgent | An optional HttpsAgent to use to when performing HTTPS requests. | | [options.defaultHeaders] | object | The optional default HTTP headers to include in every invocation request. | | [options.documentLoader] | function | Optional document loader to load suite-related contexts. If none is provided, one will be auto-generated if the suite class expresses its required context. |

zcapClient.delegate(options) ⇒ Promise.<object>

Delegates an Authorization Capability to a target delegate.

Kind: instance method of ZcapClient
Returns: Promise.<object> - - A promise that resolves to a delegated capability.

| Param | Type | Description | | --- | --- | --- | | options | object | The options to use. | | [options.capability] | object | The parent capability to delegate; must be an object if it is a delegated zcap, can be a string if it is a root zcap but then invocationTarget must be specified; if not specified, this will be auto-generated as a root zcap for the given invocationTarget. | | options.controller | string | The URL identifying the entity to delegate to, i.e., the party that will control the new zcap. | | [options.invocationTarget] | string | Optional invocation target to use when narrowing a capability's existing invocationTarget. Default is to use capability.invocationTarget, provided that capability is an object. | | [options.expires] | string | Date | Optional expiration value for the delegation. Default is 5 minutes after Date.now(). | | [options.allowedActions] | string | Array | Optional list of allowed actions or string specifying allowed delegated action. Default: [] - delegate all actions. |

zcapClient.request(options) ⇒ Promise.<object>

Performs an HTTP request given an Authorization Capability (zcap) and/or a target URL. If no URL is given, the invocation target from the capability will be used. If a capability is given as a string, it MUST be a root capability. If both a capability and a URL are given, then the capability's invocation target MUST be a RESTful prefix of or equivalent to the URL.

Kind: instance method of ZcapClient
Returns: Promise.<object> - - A promise that resolves to an HTTP response.

| Param | Type | Description | | --- | --- | --- | | options | object | The options to use. | | [options.url] | string | The URL to invoke the Authorization Capability against; if not provided, a capability must be provided instead. | | [options.capability] | string | object | The capability to invoke at the given URL. Default: generate root capability from options.url. | | [options.method] | string | The HTTP method to use when accessing the resource. Default: 'get'. | | [options.action] | string | The capability action that is being invoked. Default: 'read'. | | [options.headers] | object | The additional headers to sign and send along with the HTTP request. Default: {}. | | options.json | object | The JSON object, if any, to send with the request. |

zcapClient.read(options) ⇒ Promise.<object>

Convenience function that invokes an Authorization Capability against a given URL to perform a read operation.

Kind: instance method of ZcapClient
Returns: Promise.<object> - - A promise that resolves to an HTTP response.

| Param | Type | Description | | --- | --- | --- | | options | object | The options to use. | | options.url | string | The URL to invoke the Authorization Capability against. | | options.headers | object | The additional headers to sign and send along with the HTTP request. | | [options.capability] | string | The capability to invoke at the given URL. Default: generate root capability from options.url. |

zcapClient.write(options) ⇒ Promise.<object>

Convenience function that invokes an Authorization Capability against a given URL to perform a write operation.

Kind: instance method of ZcapClient
Returns: Promise.<object> - - A promise that resolves to an HTTP response.

| Param | Type | Description | | --- | --- | --- | | options | object | The options to use. | | options.url | string | The URL to invoke the Authorization Capability against. | | options.json | object | The JSON object, if any, to send with the request. | | [options.headers] | object | The additional headers to sign and send along with the HTTP request. | | [options.capability] | string | The capability to invoke at the given URL. Default: generate root capability from options.url. |

getCapabilitySigners(options) ⇒ object

Retrieves the first set of capability invocation and delegation signers associated with the didDocument from the keyPairs.

Kind: global function
Returns: object - - A valid invocationSigner and delegationSigner associated with the didDocument.

| Param | Type | Description | | --- | --- | --- | | options | object | The options to use. | | options.didDocument | string | A DID Document containing verification relationships for capability invocation and delegation. | | options.keyPairs | string | A map containing keypairs indexed by key ID. |

generateZcapUri(options) ⇒ string

Generate a zcap URI given a root capability URL or a delegated flag.

Kind: global function
Returns: string - - A zcap URI.

| Param | Type | Description | | --- | --- | --- | | options | object | The options to use. | | [options.url] | string | Optional URL identifying the root capability. |

HttpsAgent : object

An object that manages connection persistence and reuse for HTTPS requests.

Kind: global typedef
See: https://nodejs.org/api/https.html#https_class_https_agent

LinkedDataSignatureSuiteClass : object

An class that can be instantiated to create a suite capable of generating a Linked Data Signature. Its constructor must receive a signer instance that includes .sign() function and id and controller properties.

Kind: global typedef

Contribute

See the contribute file! PRs accepted.

If editing the README.md, please follow the standard-readme specification.

Commercial Support

Commercial support for this library is available upon request from Digital Bazaar: [email protected]

License

New BSD License (3-clause) © Digital Bazaar