{"id":19163217,"url":"https://github.com/oada/oada-certs","last_synced_at":"2025-06-15T05:33:44.238Z","repository":{"id":30145228,"uuid":"33695391","full_name":"OADA/oada-certs","owner":"OADA","description":"Generate and verify oauth dynamic client registration metadata","archived":false,"fork":false,"pushed_at":"2023-02-16T19:01:41.000Z","size":1687,"stargazers_count":1,"open_issues_count":4,"forks_count":0,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-05-24T00:33:05.468Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OADA.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"AUTHORS","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-04-09T22:13:28.000Z","updated_at":"2022-03-30T04:19:40.000Z","dependencies_parsed_at":"2024-06-21T15:44:24.276Z","dependency_job_id":"53baa3b0-358b-4459-a4cc-6300be106950","html_url":"https://github.com/OADA/oada-certs","commit_stats":{"total_commits":51,"total_committers":7,"mean_commits":7.285714285714286,"dds":0.607843137254902,"last_synced_commit":"1a0a6bef0bbb978edb5725a4e9ccbba450d0df55"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/OADA/oada-certs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OADA%2Foada-certs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OADA%2Foada-certs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OADA%2Foada-certs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OADA%2Foada-certs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OADA","download_url":"https://codeload.github.com/OADA/oada-certs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OADA%2Foada-certs/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259926928,"owners_count":22933131,"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","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-09T09:14:31.501Z","updated_at":"2025-06-15T05:33:44.195Z","avatar_url":"https://github.com/OADA.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @oada/certs\n\n[![npm](https://img.shields.io/npm/v/@oada/certs)](https://www.npmjs.com/package/@oada/certs)\n[![Downloads/week](https://img.shields.io/npm/dw/@oada/certs.svg)](https://npmjs.org/package/@oada/certs)\n[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n[![License](https://img.shields.io/github/license/OADA/oada-certs)](LICENSE)\n\nUse this to create/sign/interact with OADA developer certificates and any other\nkeys or signatures in the OADA and Trellis ecosystems.\n\n## Installation\n\n```shell\n# If you want command-line tool:\nyarn global add @oada/certs\n\n# If you just want to use the JS libs in your project:\nyarn add @oada/certs\n```\n\n## Command-line: setup an OADA domain folder\n\n```shell\ncd domain_folder\noada-certs --create-keys\noada-certs\n```\n\nNOTE: default is to look in the current folder for signing keys\n\n## Command-line: sign a certificate\n\n```shell\n# creates signed_software_statement.js in current folder\noada-certs --signkey=\"./some_path_to_privatekey_pem\" --sign=./some_path_to_unsigned_cert.js\n\n# If you are hosting signing key with a jku:\noada-certs --signkey=\"./some_path_to_privatekey_pem\" --signjku=\"https://some.jku.url\" --signkid=\"someKeyIdAtThatJKU\" --sign=\"./path_to_unsigned_cert.js\"\n```\n\n## Command-line: validate/debug a certificate\n\n```shell\n# Note: caching is in-memory and therefore unused here\noada-certs --validate=\"signed_software_statement.js\"\n\n# If there are errors, they will print here.  It will\n# also tell you if the certificate is trusted\n```\n\n## Include library in TypeScript/JavaScript\n\n```typescript\nimport * as oadacerts from '@oada/certs';\n\n// If you don't pass a jku, it puts the public jwk for the\n// sign key into the JWT automatically\ntry {\n  const signed_jwt_cert = await oadacerts.sign(payload, signkey, {\n    jku: 'https://url.to.some.jwkset',\n    kid: 'someKeyidInThatSet',\n  });\n} catch (error: unknown) {\n  console.log(error, 'Error in signing certificate');\n}\n\n// Returns a promise:\nconst { trusted, payload, valid, details } = await oadacerts.validate(\n  signed_jwt_cert\n);\n// trusted = true if cert was signed by key on a trusted list\n// payload = JSON object that is the decoded client certificate\n// valid = true if cert was decodable with a correct signature\n// details = array of details about the validation process to help with debugging a cert\n// NOTE: if the certificate is untrusted, it cannot use a jku in the signature,\n//    it must use a jwk to be considered valid.  This avoids fetching potentially malicious URL's.\n\n// Self-explanatory utilities for working with JWK key sets (jwks):\noadacerts.jwksUtils.isJWK(key);\noadacerts.jwksUtils.isJWKset(set);\noadacerts.jwksUtils.findJWK(kid, jwks);\n// jwkForSignature attempts to figure out the correct public JWK to use in\n// validating a given signature.  Uses an intelligent cache for remote-hosted\n// jwk's.\n// What makes this function tricky is the \"hint\":\n// It was designed to make it simple to say something like:\n// \"hint: I looked up the JKU ot JWK on the signature, and it was from a trusted source.\"\n// (i.e. hint = truthy),\n// and it's truthy value is then either the JWKS (object) from the trusted source,\n//     or the jku (string) of the trusted source's jwks\n// or\n// \"hint: I looked at my trusted sources and this one doesn't have a jwk or jku that matches.\"\n// (i.e. hint === false)\n// which means \"just use the header on the signature because I have no outside reference that verifies it\"\n//\n// - If boolean false, use the jku from the jose header and if no jku then use jose's jwk\n// - If boolean true, throw error (it should have been either an object or a string)\n// - If string, assume string is a jku uri, go get that URI and then check jose's jwk against it\n// - If object and looks like a jwks, look for jose's jwk in the set\n// - If object and looks like a jwk, compare that jwk with jose's jwk\nconst jwk = oadacerts.jwksUtils.jwkForSignature(jwt, hint, { timeout: 1000 });\n```\n\n## API\n\n### _async_ `sign(payload, key, options)`\n\nGenerates a JWT with the given payload, signed with the given key.\nKey should be a JWK, but it can also be a PEM string.\n\n- `payload` _required_: The JSON payload to sign in the JWT.\n- `key` _required_: JWK private key to sign with. If this is a string instead\n  of a JWK, it is assumed to be a PEM string.\n- `options` _optional_: If you need to specify a given `kid` (key id) and `jku`\n  (JWK set URL) because your key is trusted, you can pass them here in\n  `options.header`. `options.header` is passed to `jose.JWS.createSign`.\n\n### _async_ `validate(signature, options)`\n\n- `sig` _required_: the signed JWT to validate\n- `options` _optional_:\n  - `options.timeout` (default: 1000 ms): How long to wait on remote URL\n    requests.\n  - `options.trustedListCacheTime` (default: 3600 sec): How long to use\n    immediately use the cached value for the trusted list before waiting on the\n    request to finish.\n  - `options.additionalTrustedListURIs`: Any additional URLs (array of\n    strings) to include in the search for a trusted key.\n  - `options.disableDefaultTrustedListURI`: Only use the\n    additionalTrustedListURI's, not the default one.\n\nReturns `{ trusted, payload, valid, header, details }`\n\n- `trusted`: `true|false`: true if signing key was on the trusted list\n- `payload`: the decoded payload\n- `valid`: `true|false`: true if the JWT was a valid JWT and the signature\n  matched, says nothing about whether it was trusted.\n- `details`: array of strings about the validation process that can be helpful\n  for debugging.\n\n### `validate.TRUSTED_LIST_URI`\n\nExports the core `TRUSTED_LIST_URI` string for convenience as a property on the validate function.\n\n### `validate.clearCache()`\n\nMainly for testing, you can clear the internal in-memory cache for all trusted lists with this function.\n\n### `jwksUtils.isJWKSet(set)`\n\nReturn `true` if `set` looks like a JWK set (`jwks`)\n\n### `jwksUtils.isJWK(key)`\n\nReturn `true` if `key` looks like a `jwk`.\n\n### `jwksUtils.findJWK(kid, jwks)`\n\nSearch for the given `kid` (key id) in the `jwks` (JWK set)\n\n### `jwksUtils.decodeWithoutVerify(jwt)`\n\nGiven a JWT, decode the header, payload, and signature without verifying them.\nReturns `{ header, payload, signature }`\n\n### _async_ `jwksUtils.jwkForSignature(jwt, hint, options)`\n\nReturns to you the JWK necessary to validate a given JWT. Described above in detail in the javascript example.\n\n### `jwksUtils.clearJWKSCache()`\n\nMainly for testing, clear the internal JWK key cache (i.e. previous `jku`-based keys that it has looked up). This is not the trusted list cache.\n\n### `jwksUtils.getJWKSCache()`\n\nReturns the JWK cache to you if you want to see it. Mainly for testing.\n\n### `jwksUtils.cachePruneOldest()`\n\nEliminates the oldest entry from the JWK cache. Mainly for testing.\n\n### _async_ `keys.create()`\n\nReturns `{ public, private }`. Both are JWK's. You can use `private` to sign things.\n\n### _async_ `keys.pubFromPriv(priv)`\n\nGiven a private JWK, return the corresponding public key as a JWK.\n\n### `jose`\n\nExports the internally-used `node-jose` module for convenience.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foada%2Foada-certs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foada%2Foada-certs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foada%2Foada-certs/lists"}