{"id":19122897,"url":"https://github.com/digitalbazaar/ezcap-express","last_synced_at":"2026-03-05T20:04:03.855Z","repository":{"id":37795529,"uuid":"327189117","full_name":"digitalbazaar/ezcap-express","owner":"digitalbazaar","description":"Authorization Capability (zcap) middleware for express.js HTTP servers","archived":false,"fork":false,"pushed_at":"2025-09-24T19:45:37.000Z","size":178,"stargazers_count":2,"open_issues_count":2,"forks_count":2,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-10-13T02:35:38.320Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/digitalbazaar.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-01-06T03:30:27.000Z","updated_at":"2025-09-24T19:45:41.000Z","dependencies_parsed_at":"2024-04-02T21:42:22.807Z","dependency_job_id":"75841925-018f-44dd-b9f5-e6ce360cb56b","html_url":"https://github.com/digitalbazaar/ezcap-express","commit_stats":{"total_commits":236,"total_committers":6,"mean_commits":"39.333333333333336","dds":"0.48305084745762716","last_synced_commit":"0142e3166a3fd2a67d74dc12abe85046dd449c37"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/digitalbazaar/ezcap-express","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalbazaar%2Fezcap-express","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalbazaar%2Fezcap-express/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalbazaar%2Fezcap-express/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalbazaar%2Fezcap-express/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/digitalbazaar","download_url":"https://codeload.github.com/digitalbazaar/ezcap-express/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digitalbazaar%2Fezcap-express/sbom","scorecard":{"id":342348,"data":{"date":"2025-08-11","repo":{"name":"github.com/digitalbazaar/ezcap-express","commit":"4a37490ab1f966ac09e72969868622a72861273f"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.5,"checks":[{"name":"Maintained","score":5,"reason":"6 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":2,"reason":"Found 3/11 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/main.yaml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yaml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/digitalbazaar/ezcap-express/main.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yaml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/digitalbazaar/ezcap-express/main.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yaml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/digitalbazaar/ezcap-express/main.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yaml:31: update your workflow using https://app.stepsecurity.io/secureworkflow/digitalbazaar/ezcap-express/main.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yaml:45: update your workflow using https://app.stepsecurity.io/secureworkflow/digitalbazaar/ezcap-express/main.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yaml:47: update your workflow using https://app.stepsecurity.io/secureworkflow/digitalbazaar/ezcap-express/main.yaml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/main.yaml:54: update your workflow using https://app.stepsecurity.io/secureworkflow/digitalbazaar/ezcap-express/main.yaml/main?enable=pin","Warn: npmCommand not pinned by hash: .github/workflows/main.yaml:19","Warn: npmCommand not pinned by hash: .github/workflows/main.yaml:35","Warn: npmCommand not pinned by hash: .github/workflows/main.yaml:51","Info:   0 out of   6 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   3 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: BSD 3-Clause \"New\" or \"Revised\" License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 24 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T06:11:07.247Z","repository_id":37795529,"created_at":"2025-08-18T06:11:07.248Z","updated_at":"2025-08-18T06:11:07.248Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279013997,"owners_count":26085345,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T05:23:28.853Z","updated_at":"2025-10-13T02:35:39.048Z","avatar_url":"https://github.com/digitalbazaar.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ezcap express library (@digitalbazaar/ezcap-express)\n\n[![Build Status](https://img.shields.io/github/actions/workflow/status/digitalbazaar/ezcap-express/main.yaml)](https://github.com/digitalbazaar/ezcap-express/actions/workflows/main.yaml)\n\n\u003e zcap's gettin' you down? Get on the Ezcap Express! Woot WOoot! 🚇🎉\n\nConnect middleware that provides easy Authorization Capability (zcap) support\nfor express.js HTTP servers and more.\n\n## Table of Contents\n\n- [Background](#background)\n- [Security](#security)\n- [Install](#install)\n- [Usage](#usage)\n- [Contribute](#contribute)\n- [Commercial Support](#commercial-support)\n- [License](#license)\n\n## Background\n\nThis library provides Node.js express middleware that can be used to protect\nresources on HTTP servers using Authorization Capabilities (zcaps). The library\nis configured with secure and sensible defaults to help developers get started\nquickly and ensure that their server code is production-ready.\n\n## Security\n\nThe security characteristics of this library are largely influenced by design\ndecisions made by client and server software. For clients, implementers should\npay particular attention to secure private key management. For servers, security\ncharacteristics are largely dependent on how carefully the server manages zcap\nregistrations, zcap invocations, and zcap delegations. Bugs or failures related\nto client key management, or server zcap validity checking will lead to security\nfailures. It is imperative that implementers audit their implementations,\npreferably via parties other than the implementer.\n\n## Install\n\n- Node.js 14+ is supported.\n- [Web Crypto API][] is required by dependencies. Node.js 14 must use a polyfill.\n\nTo install from NPM:\n\n```\nnpm install @digitalbazaar/ezcap-express\n```\n\nTo install development code:\n\n```sh\ngit clone git@github.com:digitalbazaar/ezcap-express.git\ncd ezcap-express\nnpm install\n```\n\n## Usage\n\n* [Define getCapabilityController](#define-getcapabilitycontroller)\n* [Define documentLoader](#define-documentloader)\n* [Define authorizeMyZcapInvocation](#define-authorizemyzcapinvocation)\n* [Use authorizeMyZcapInvocation](#use-authorizemyzcapinvocation)\n* [Define getRootController](#define-getrootcontroller)\n\n### Define getRootController\n\n```js\n// this will only be called if `rootInvocationTarget` matches\n// one of the expected root invocation targets specified\nasync function getRootController({\n  req, rootCapabilityId, rootInvocationTarget\n}) {\n  // get controller for a service object from a database\n  let controller;\n  try {\n    const record = await database.getMyServiceObjectById({\n      // typically, root invocation target is a service object ID\n      id: rootInvocationTarget\n    });\n    controller = record.controller;\n  } catch(e) {\n    if(e.type === 'NotFoundError') {\n      const url = `${req.protocol}://${req.get('host')}${req.originalUrl}`;\n      throw new Error(\n        `Invalid capability identifier \"${rootCapabilityId}\" ` +\n        `for URL \"${url}\".`);\n    }\n    throw e;\n  }\n\n  // return the service object's controller so it will be\n  // added to the root capability for the service object\n  return controller;\n}\n```\n\n### Define documentLoader\n\n```js\nimport didIo from 'did-io';\nimport didKeyDriver from 'did-method-key';\nimport jldl from 'jsonld-document-loader';\n\nconst _documentLoader = new jldl.JsonLdDocumentLoader();\n\n// support did:key\ndidIo.use('key', didKeyDriver.driver());\n\nasync function documentLoader(url) {\n  let document;\n  if(url.startsWith('did:')) {\n    document = await didIo.get({did: url, forceConstruct: true});\n    return {\n      contextUrl: null,\n      documentUrl: url,\n      document\n    };\n  }\n\n  // finally, try the base document loader\n  return _documentLoader(url);\n}\n```\n\n### Define authorizeMyZcapInvocation\n\n```js\nimport {authorizeZcapInvocation} from '@digitalbazaar/ezcap-express';\n\nasync function authorizeMyZcapInvocation({expectedAction} = {}) {\n  return authorizeZcapInvocation({\n    getExpectedValues({req}) {\n      const expectedHost = 'ezcap.example';\n      const {localId} = req.params;\n      const serviceObjectId =\n        `https://${expectedHost}/${encodeURIComponent(localId)}`;\n      return {\n        action: expectedAction,\n        host: expectedHost,\n        rootInvocationTarget: serviceObjectId\n      };\n    },\n    getRootController\n  });\n};\n```\n\n### Use authorizeMyZcapInvocation\n\n```js\nimport express from 'express';\nimport asyncHandler from 'express-async-handler';\n\nconst app = express();\n\napp.post('/my-objects/:localId',\n  authorizeMyZcapInvocation(),\n  asyncHandler(async (req, res) =\u003e {\n    // your code goes here\n    // req.zcap is available to provide authz information\n  }));\n```\n\n## API Reference\n\nThe ezcap approach is opinionated in order to make using zcaps a pleasant\nexperience for developers. To do this, it makes two fundamental assumptions\nregarding the systems it interacts with:\n\n* The systems are HTTP-based and REST-ful in nature.\n* The REST-ful systems center around reading and writing resources.\n\nIf these assumptions do not apply to your system, the\n[zcap](https://github.com/digitalbazaar/zcap) library might\nbe a better, albeit more complex, solution for you.\n\nLooking at each of these core assumptions more closely will help explain how designing systems to these constraints make it much easier to think about\nzcaps. Let's take a look at the first assumption:\n\n\u003e The systems are HTTP-based and REST-ful in nature.\n\nMany modern systems tend to have HTTP-based interfaces that are REST-ful in\nnature. That typically means that most resource URLs are organized by namespaces, collections, and items:\n`/\u003croot-namespace\u003e/\u003ccollection-id\u003e/\u003citem-id\u003e`. In practice,\nthis tends to manifest itself as URLs that look like\n`/my-account/things/1`. The ezcap approach maps the authorization model\nin a 1-to-1 way to the URL. Following along with the example, the root\ncapability would then be `/my-account`, which you will typically create and\nhave access to. You can then take that root capability and delegate access\nto things like `/my-account/things` to let entities you trust modify the\n`things` collection. You can also choose to be more specific and only\ndelegate to `/my-account/things/1` to really lock down access. ezcap attempts\nto keep things very simple by mapping URL hierarchy to authorization scope.\n\nNow, let's examine the second assumption that makes things easier:\n\n\u003e The REST-ful systems center around reading and writing resources.\n\nThere is an incredible amount of flexibility that zcaps provide. You can\ndefine a variety of actions: read, write, bounce, atomicSwap, start, etc.\nHowever, all that flexibility adds complexity and one of the goals of ezcap\nis to reduce complexity to the point where the solution is good enough for\n80% of the use cases. A large amount of REST-ful interactions tend to\nrevolve around reading and writing collections and the items in those\ncollections. For this reason, there are only two actions that are exposed\nby default in ezcap: read and write. Keeping the number of actions to a\nbare minimum has allowed implementers to achieve very complex use cases with\nvery simple code.\n\nThese are the two assumptions that ezcap makes and with those two assumptions,\n80% of all use cases we've encountered are covered.\n\n## Functions\n\n\u003cdl\u003e\n\u003cdt\u003e\u003ca href=\"#authorizeZcapInvocation\"\u003eauthorizeZcapInvocation(options)\u003c/a\u003e ⇒ \u003ccode\u003efunction\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eAuthorizes an incoming request.\u003c/p\u003e\n\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#authorizeZcapRevocation\"\u003eauthorizeZcapRevocation(options)\u003c/a\u003e ⇒ \u003ccode\u003efunction\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eAuthorizes a request to submit a zcap revocation.\u003c/p\u003e\n\u003cp\u003eThis middleware is opinionated; it MUST be attached to an endpoint that\nterminates in \u003ccode\u003e/zcaps/revocations/:revocationId\u003c/code\u003e. This to enable the\nmiddleware to automatically generate expected values for running zcap checks\nand to support a common, conventional revocation API pattern.\u003c/p\u003e\n\u003cp\u003eThe pattern is in support of controlled objects on a service, aka\n\u0026quot;service objects\u0026quot;. Each object\u0026#39;s controller is used to populate the root\nzcap for the object\u0026#39;s controller field. This root zcap has an invocation\ntarget that matches the URL for the service object, aka its\n\u0026quot;serviceObjectId\u0026quot;.\u003c/p\u003e\n\u003cp\u003eTherefore, any route that matches an invocation target for a root zcap for\na service SHOULD attach this middleware to:\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e\u0026lt;serviceObjectId\u0026gt;/zcaps/revocations/:revocationId\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eThis middleware will compute \u003ccode\u003eserviceObjectId\u003c/code\u003e by combining the expected\nhost with the subpath from the request URL that occurs before\n\u003ccode\u003e/zcaps/revocations/\u003c/code\u003e. It assumes that the request URL will have this\npattern if the middleware code has been reached. IOW, \u003ccode\u003eserviceObjectId\u003c/code\u003e will\nbe set using:\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ehttps://\u0026lt;expectedHost\u0026gt;/\u0026lt;URL subpath before \u0026quot;/zcaps/revocations/\u0026quot;\u0026gt;\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eNote: This middleware does NOT support having \u003ccode\u003e/zcaps/revocations/\u003c/code\u003e appear\nmultiple places in the request URL.\u003c/p\u003e\n\u003cp\u003eAttaching this middleware will enable any zcaps delegated from the service\nobject\u0026#39;s root zcap to be revoked without having to issue an additional zcap\nto use the revocation endpoint. This middleware makes that possible by\nsupporting the invocation of a dynamically generated root zcap with an\ninvocation target of:\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e\u0026lt;serviceObjectId\u0026gt;/zcaps/revocations/:revocationId\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eThis middleware will set the \u003ccode\u003econtroller\u003c/code\u003e of this root zcap to all\ncontrollers in the to-be-revoked zcap\u0026#39;s delegation chain, permitting any\nparticipant to revoke it. An error will be thrown prior to populating this\n\u003ccode\u003econtroller\u003c/code\u003e field if the root zcap in the to-be-revoked zcap\u0026#39;s chain does\nnot have \u003ccode\u003e\u0026lt;serviceObjectId\u0026gt;\u003c/code\u003e as its invocation target (or a prefix of it).\nThis ensures that the only zcaps that have been delegated from a root zcap\nusing the service object\u0026#39;s ID as part of its invocation target can be\nrevoked at its \u003ccode\u003e/zcaps/revocations\u003c/code\u003e route, i.e., other zcaps intended for\nother service objects -- or entirely other services -- cannot be revoked via\nthis middleware.\u003c/p\u003e\n\u003cp\u003eThis middleware will automatically generate two sets of expects values: one\nfor checking the invocation to revoke a capability and one for verifying the\ndelegation chain of the capability that is to be revoked. Only the expected\nhost value can and must be given as a parameter.\u003c/p\u003e\n\u003cp\u003eThe expected values for checking the capability invocation will be:\u003c/p\u003e\n\u003cp\u003ehost: \u003ccode\u003e\u0026lt;expectedHost\u0026gt;\u003c/code\u003e,\nrootInvocationTarget: [\n  // root zcap with this target, RZ1, can be delegated w/target attenuation\n  // to allow delegates to revoke any zcap, Z1, with RZ1 as the root in its\n  // chain, even if the delegate is not a controller in Z1\u0026#39;s chain\n  \u003ccode\u003e\u0026lt;serviceObjectId\u0026gt;\u003c/code\u003e,\n  // root zcap that this target, RZ2, can be used to revoke a zcap, Z2,\n  // with an \u0026quot;id\u0026quot; of \u003ccode\u003erevocationId\u003c/code\u003e; RZ2\u0026#39;s controller will be populated\n  // using all controllers from Z2\u0026#39;s chain, enabling any controller in that\n  // zcap\u0026#39;s chain to invoke RZ2 to revoke Z2\n  \u003ccode\u003e\u0026lt;serviceObjectId\u0026gt;/zcaps/revocations/\u0026lt;revocationId\u0026gt;\u003c/code\u003e,\n],\naction: \u0026#39;write\u0026#39;\n.\u003c/p\u003e\n\u003c/dd\u003e\n\u003c/dl\u003e\n\n## Typedefs\n\n\u003cdl\u003e\n\u003cdt\u003e\u003ca href=\"#GetExpectedValues\"\u003eGetExpectedValues\u003c/a\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#GetExpectedValues\"\u003eGetExpectedValues\u003c/a\u003e ⇒ \u003ccode\u003e\u003ca href=\"#ExpectedValues\"\u003eExpectedValues\u003c/a\u003e\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eA function for returning expected values when checking a zcap invocation.\u003c/p\u003e\n\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#ExpectedValues\"\u003eExpectedValues\u003c/a\u003e : \u003ccode\u003eobject\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eThe expected values for checking a zcap invocation performed via an HTTP\nrequest.\u003c/p\u003e\n\u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003ca name=\"authorizeZcapInvocation\"\u003e\u003c/a\u003e\n\n## authorizeZcapInvocation(options) ⇒ \u003ccode\u003efunction\u003c/code\u003e\nAuthorizes an incoming request.\n\n**Kind**: global function  \n**Returns**: \u003ccode\u003efunction\u003c/code\u003e - Returns an Express.js style middleware route handler.  \n\n| Param | Type | Default | Description |\n| --- | --- | --- | --- |\n| options | \u003ccode\u003eobject\u003c/code\u003e |  | Options hashmap. |\n| [options.allowTargetAttenuation] | \u003ccode\u003eboolean\u003c/code\u003e | \u003ccode\u003etrue\u003c/code\u003e | Allow the   invocationTarget of a delegation chain to be increasingly restrictive   based on a hierarchical RESTful URL structure. |\n| options.documentLoader | \u003ccode\u003eobject\u003c/code\u003e |  | Document loader used to load   DID Documents, capability documents, and JSON-LD Contexts. |\n| options.getExpectedValues | [\u003ccode\u003eGetExpectedValues\u003c/code\u003e](#GetExpectedValues) |  | Used to get the   expected values when checking the zcap invocation. |\n| options.getRootController | \u003ccode\u003efunction\u003c/code\u003e |  | Used to get the controller   of the root capability in the invoked capability's chain. |\n| options.getVerifier | \u003ccode\u003efunction\u003c/code\u003e |  | An async function to   call to get a verifier and verification method for the key ID. |\n| [options.inspectCapabilityChain] | \u003ccode\u003efunction\u003c/code\u003e |  | A function that can   inspect a capability chain, e.g., to check for revocations. |\n| [options.maxChainLength] | \u003ccode\u003enumber\u003c/code\u003e | \u003ccode\u003e10\u003c/code\u003e | The maximum length of the   capability delegation chain. |\n| [options.maxClockSkew] | \u003ccode\u003enumber\u003c/code\u003e | \u003ccode\u003e300\u003c/code\u003e | A maximum number of seconds   that clocks may be skewed when checking capability expiration date-times   against `date`, when comparing invocation proof creation time against   delegation proof creation time, and when comparing the capability   invocation expiration time against `now`. |\n| [options.maxDelegationTtl] | \u003ccode\u003enumber\u003c/code\u003e | \u003ccode\u003e1000*60*60*24*90\u003c/code\u003e | The maximum   milliseconds to live for a delegated zcap as measured by the time   difference between `expires` and `created` on the delegation proof. |\n| [options.onError] | \u003ccode\u003efunction\u003c/code\u003e |  | An error handler handler for   customizable error handling. |\n| options.suiteFactory | \u003ccode\u003eobject\u003c/code\u003e |  | A factory for creating the   supported suite(s) to use when verifying zcap delegation chains; this is   different from `getVerifier` which is used to produce a verifier for   verifying HTTP signatures used to invoke zcaps. |\n\n\u003ca name=\"authorizeZcapRevocation\"\u003e\u003c/a\u003e\n\n## authorizeZcapRevocation(options) ⇒ \u003ccode\u003efunction\u003c/code\u003e\nAuthorizes a request to submit a zcap revocation.\n\nThis middleware is opinionated; it MUST be attached to an endpoint that\nterminates in `/zcaps/revocations/:revocationId`. This to enable the\nmiddleware to automatically generate expected values for running zcap checks\nand to support a common, conventional revocation API pattern.\n\nThe pattern is in support of controlled objects on a service, aka\n\"service objects\". Each object's controller is used to populate the root\nzcap for the object's controller field. This root zcap has an invocation\ntarget that matches the URL for the service object, aka its\n\"serviceObjectId\".\n\nTherefore, any route that matches an invocation target for a root zcap for\na service SHOULD attach this middleware to:\n\n`\u003cserviceObjectId\u003e/zcaps/revocations/:revocationId`.\n\nThis middleware will compute `serviceObjectId` by combining the expected\nhost with the subpath from the request URL that occurs before\n`/zcaps/revocations/`. It assumes that the request URL will have this\npattern if the middleware code has been reached. IOW, `serviceObjectId` will\nbe set using:\n\n`https://\u003cexpectedHost\u003e/\u003cURL subpath before \"/zcaps/revocations/\"\u003e`.\n\nNote: This middleware does NOT support having `/zcaps/revocations/` appear\nmultiple places in the request URL.\n\nAttaching this middleware will enable any zcaps delegated from the service\nobject's root zcap to be revoked without having to issue an additional zcap\nto use the revocation endpoint. This middleware makes that possible by\nsupporting the invocation of a dynamically generated root zcap with an\ninvocation target of:\n\n`\u003cserviceObjectId\u003e/zcaps/revocations/:revocationId`.\n\nThis middleware will set the `controller` of this root zcap to all\ncontrollers in the to-be-revoked zcap's delegation chain, permitting any\nparticipant to revoke it. An error will be thrown prior to populating this\n`controller` field if the root zcap in the to-be-revoked zcap's chain does\nnot have `\u003cserviceObjectId\u003e` as its invocation target (or a prefix of it).\nThis ensures that the only zcaps that have been delegated from a root zcap\nusing the service object's ID as part of its invocation target can be\nrevoked at its `/zcaps/revocations` route, i.e., other zcaps intended for\nother service objects -- or entirely other services -- cannot be revoked via\nthis middleware.\n\nThis middleware will automatically generate two sets of expects values: one\nfor checking the invocation to revoke a capability and one for verifying the\ndelegation chain of the capability that is to be revoked. Only the expected\nhost value can and must be given as a parameter.\n\nThe expected values for checking the capability invocation will be:\n\nhost: `\u003cexpectedHost\u003e`,\nrootInvocationTarget: [\n  // root zcap with this target, RZ1, can be delegated w/target attenuation\n  // to allow delegates to revoke any zcap, Z1, with RZ1 as the root in its\n  // chain, even if the delegate is not a controller in Z1's chain\n  `\u003cserviceObjectId\u003e`,\n  // root zcap that this target, RZ2, can be used to revoke a zcap, Z2,\n  // with an \"id\" of `revocationId`; RZ2's controller will be populated\n  // using all controllers from Z2's chain, enabling any controller in that\n  // zcap's chain to invoke RZ2 to revoke Z2\n  `\u003cserviceObjectId\u003e/zcaps/revocations/\u003crevocationId\u003e`,\n],\naction: 'write'\n.\n\n**Kind**: global function  \n**Returns**: \u003ccode\u003efunction\u003c/code\u003e - Returns an Express.js style middleware route handler.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| options | \u003ccode\u003eobject\u003c/code\u003e | Options hashmap. |\n| options.documentLoader | \u003ccode\u003eobject\u003c/code\u003e | Document loader used to load   DID Documents, capability documents, and JSON-LD Contexts. |\n| options.expectedHost | \u003ccode\u003estring\u003c/code\u003e | The expected host header value   when checking the zcap invocation. |\n| options.getRootController | \u003ccode\u003efunction\u003c/code\u003e | Used to get the controller   of the root capability for the service object. |\n| options.getVerifier | \u003ccode\u003efunction\u003c/code\u003e | An async function to   call to get a verifier and verification method for the key ID. |\n| [options.inspectCapabilityChain] | \u003ccode\u003efunction\u003c/code\u003e | A function that can   inspect a capability chain, e.g., to check for revocations; it will be   used when verifying the invocation and the delegation chain for the   to-be-revoked capability. |\n| [options.onError] | \u003ccode\u003efunction\u003c/code\u003e | An error handler handler for   customizable error handling. |\n| options.suiteFactory | \u003ccode\u003eobject\u003c/code\u003e | A factory for creating the   supported suite(s) to use when verifying zcap delegation chains; this is   different from `getVerifier` which is used to produce a verifier for   verifying HTTP signatures used to invoke zcaps. |\n\n\u003ca name=\"GetExpectedValues\"\u003e\u003c/a\u003e\n\n## GetExpectedValues\n**Kind**: global typedef  \n\u003ca name=\"GetExpectedValues\"\u003e\u003c/a\u003e\n\n## GetExpectedValues ⇒ [\u003ccode\u003eExpectedValues\u003c/code\u003e](#ExpectedValues)\nA function for returning expected values when checking a zcap invocation.\n\n**Kind**: global typedef  \n**Returns**: [\u003ccode\u003eExpectedValues\u003c/code\u003e](#ExpectedValues) - - The expected values.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| options | \u003ccode\u003eobject\u003c/code\u003e | The options passed to the function. |\n| options.req | \u003ccode\u003eobject\u003c/code\u003e | The express request. |\n\n\u003ca name=\"ExpectedValues\"\u003e\u003c/a\u003e\n\n## ExpectedValues : \u003ccode\u003eobject\u003c/code\u003e\nThe expected values for checking a zcap invocation performed via an HTTP\nrequest.\n\n**Kind**: global typedef  \n**Properties**\n\n| Name | Type | Description |\n| --- | --- | --- |\n| [action] | \u003ccode\u003estring\u003c/code\u003e | The expected capability action; if no action   is specified during an invocation check, then a default action will be   determined based on the HTTP method from the request -- which is only safe   provided that the handler code path is also determined based on the HTTP   method in the request (i.e., typical method-based express/connect   routing); if the handler code path is determined by some other means,   e.g., the request body, then `action` MUST be set. |\n| host | \u003ccode\u003estring\u003c/code\u003e | The expected host in the request header. |\n| rootInvocationTarget | \u003ccode\u003estring\u003c/code\u003e \\| \u003ccode\u003eArray\u003c/code\u003e | The expected invocation   target for every acceptable root capability; each string must express an   absolute URI. |\n| [target] | \u003ccode\u003estring\u003c/code\u003e | The expected invocation target; if no target   is specified during an invocation check, then the target will default to   the absolute URL computed from the relative request URL and expected host   value. |\n\n\n## Contribute\n\nSee [the contribute file](https://github.com/digitalbazaar/bedrock/blob/master/CONTRIBUTING.md)!\n\nPRs accepted.\n\nIf editing the Readme, please conform to the\n[standard-readme](https://github.com/RichardLitt/standard-readme) specification.\n\n## Commercial Support\n\nCommercial support for this library is available upon request from\nDigital Bazaar: support@digitalbazaar.com\n\n## License\n\n[New BSD License (3-clause)](LICENSE) © Digital Bazaar\n\n[Web Crypto API]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdigitalbazaar%2Fezcap-express","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdigitalbazaar%2Fezcap-express","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdigitalbazaar%2Fezcap-express/lists"}