mirror of
https://github.com/danbulant/jose
synced 2026-05-19 04:18:52 +00:00
docs: documentation, README, .github files, getting ready to publish
This commit is contained in:
parent
8dd95426dc
commit
b656702276
11 changed files with 1240 additions and 264 deletions
32
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
32
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: There's a bug in @panva/jose I want to report
|
||||
title: 'bug: '
|
||||
labels: bug
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
|
||||
**To Reproduce**
|
||||
|
||||
Steps to reproduce the behaviour:
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
**Expected behaviour**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Environment:**
|
||||
- @panva/jose version: [e.g. v1.0.0]
|
||||
- node version: [e.g. v11.9.0]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
||||
- [ ] the bug is happening on latest @panva/jose too.
|
||||
- [ ] i have tried DEBUG (see readme.md) and can see the issue is with the provider and not my code.
|
||||
- [ ] i have searched the issues tracker on github for similar issues and couldn't find anything related.
|
||||
21
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
21
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
name: Feature proposal
|
||||
about: I have an idea for a new @panva/jose feature
|
||||
title: 'proposal: '
|
||||
labels: enhancement
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is.
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
||||
- [ ] i have searched the configuration section for this feature and couldn't find it
|
||||
- [ ] i have searched the issues tracker on github for similar requests and couldn't find anything related.
|
||||
6
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
6
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
name: Question
|
||||
about: I have a question about using @panva/jose
|
||||
title: 'question: '
|
||||
labels: question
|
||||
---
|
||||
20
.github/ISSUE_TEMPLATE/security-vulnerability.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/security-vulnerability.md
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
name: Security Vulnerability
|
||||
about: I want to disclose a vulnerability
|
||||
---
|
||||
|
||||
<!--
|
||||
Do not disclose vulnerabilities this way. Reach out to the project team via e.g. email, we'll
|
||||
work together on patching the vulnerability and follow some form of Responsible disclosure once
|
||||
fixed. Thank you. https://en.wikipedia.org/wiki/Responsible_disclosure
|
||||
-->
|
||||
<!--
|
||||
Do not disclose vulnerabilities this way. Reach out to the project team via e.g. email, we'll
|
||||
work together on patching the vulnerability and follow some form of Responsible disclosure once
|
||||
fixed. Thank you. https://en.wikipedia.org/wiki/Responsible_disclosure
|
||||
-->
|
||||
<!--
|
||||
Do not disclose vulnerabilities this way. Reach out to the project team via e.g. email, we'll
|
||||
work together on patching the vulnerability and follow some form of Responsible disclosure once
|
||||
fixed. Thank you. https://en.wikipedia.org/wiki/Responsible_disclosure
|
||||
-->
|
||||
1
.npmrc
Normal file
1
.npmrc
Normal file
|
|
@ -0,0 +1 @@
|
|||
access = public
|
||||
9
.travis.yml
Normal file
9
.travis.yml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
language: node_js
|
||||
node_js: stable
|
||||
script: npm run coverage
|
||||
after_script: npx codecov
|
||||
jobs:
|
||||
include:
|
||||
- stage: Lint
|
||||
script: npm run lint
|
||||
after_script: skip
|
||||
62
CODE_OF_CONDUCT.md
Normal file
62
CODE_OF_CONDUCT.md
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers
|
||||
pledge to making participation in our project and our community a harassment-free experience for
|
||||
everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level
|
||||
of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behaviour that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behaviour by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit
|
||||
permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behaviour and are
|
||||
expected to take appropriate and fair corrective action in response to any instances of unacceptable
|
||||
behaviour.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits,
|
||||
code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or
|
||||
to ban temporarily or permanently any contributor for other behaviours that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is
|
||||
representing the project or its community. Examples of representing a project or community include
|
||||
using an official project e-mail address, posting via an official social media account, or acting as
|
||||
an appointed representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behaviour may be reported by contacting
|
||||
the project team at panva.ip@gmail.com. The project team will review and investigate all complaints,
|
||||
and will respond in a way that it deems appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident. Further details of
|
||||
specific enforcement policies may be posted separately.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at
|
||||
[http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
30
CONTRIBUTING.md
Normal file
30
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Contributing to @panva/jose
|
||||
|
||||
Please note we have a [code of conduct][coc], please follow it in all your interactions with the
|
||||
project.
|
||||
|
||||
When contributing to this project, please first discuss the change you wish to make via issue,
|
||||
email, or any other method with the owners of this project before proposing a change via a Pull
|
||||
Request. Use (and follow!) the appropriate [Issue Template][new-issue] to do so. A contribution that
|
||||
implements something non-standard will most likely be dismissed.
|
||||
|
||||
## Rules of the discussions
|
||||
|
||||
Remember to be very clear and transparent when discussing any issue in the discussions boards. We
|
||||
ask that you keep the language to English and keep on track with the issue at hand. Lastly, please
|
||||
be respectful of our fellow contributors and keep an exemplary level of professionalism at all
|
||||
times.
|
||||
|
||||
## Pull Request Checklist
|
||||
|
||||
- No additional runtime dependencies unless previously agreed upon
|
||||
- `npm run lint` passes
|
||||
- File names must be snake_case.js
|
||||
- Add tests covering 100% of the library code you are adding or modifying
|
||||
- Unless previously agreed upon (i.e. fixing a bug) all contributions must be backwards compatible
|
||||
- Update the documentation
|
||||
- Do not commit unnecessary whitespace
|
||||
|
||||
[coc]: https://github.com/panva/jose/blob/master/CODE_OF_CONDUCT.md
|
||||
[new-issue]: https://github.com/panva/jose/issues/new/choose
|
||||
[standard-version]: https://github.com/conventional-changelog/standard-version
|
||||
395
README.md
395
README.md
|
|
@ -4,12 +4,7 @@
|
|||
|
||||
"JSON Web Almost Everything" - JWA, JWS, JWE, JWK, JWKS for Node.js with minimal dependencies
|
||||
|
||||
See the [`@panva/jwt`](https://github.com/panva/jwt) package for JWT.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
- [Implemented specs & features](#implemented-specs--features)
|
||||
- [Usage](#usage)
|
||||
See the [`@panva/jwt`](https://github.com/panva/jwt) (coming soon™) for JWT convenience abstraction.
|
||||
|
||||
## Implemented specs & features
|
||||
|
||||
|
|
@ -30,7 +25,8 @@ implementation is correct.
|
|||
|
||||
Legend:
|
||||
- **✓** Implemented
|
||||
- **✕** Missing node crypto support / won't implement / not planned / PR welcome
|
||||
- **✕** Missing node crypto support / won't implement
|
||||
- **◯** not planned (yet?) / PR / Use-Case first welcome
|
||||
|
||||
| JWK Key Types | Supported ||
|
||||
| -- | -- | -- |
|
||||
|
|
@ -68,327 +64,199 @@ Legend:
|
|||
|
||||
---
|
||||
|
||||
Remaining tasks:
|
||||
- ✓ JWKS abstraction
|
||||
- ✓ `crit` JWE/JWS Header parameter handling
|
||||
- ✓ `b64` JWS crit support
|
||||
- ✓ JWE `zip` handling
|
||||
- ✓ JWE/JWS decrypt/verify algorithm whitelisting
|
||||
- ◯ JWE/JWS reference (true/false for `kid`, name of the field for other fields)
|
||||
- ◯ whitelist additional JWK reference fields (`kid`, `jku`, `x5c`, `x5t`, `x5t#S256`, `x5u`)
|
||||
- ◯ README and documentation
|
||||
- ◯ .d.ts types
|
||||
- ◯ .github files (templates, CoC, Contributing)
|
||||
- ◯ `@panva/jwt`
|
||||
- `compact` only with convenience methods and options
|
||||
- `@panva/jose` as a dependency
|
||||
Pending Node.js Support 🤞:
|
||||
- [RFC8037][spec-cfrg] (EdDSA, OKP kty, etc)
|
||||
- `crypto.getCurves().includes('Curve25519')` // => 😢
|
||||
- `crypto.getCurves().includes('Curve448')` // => 😢
|
||||
- `openssl ecparam -list_curves` // => 😢
|
||||
|
||||
Won't implement:
|
||||
- ✕ JWS embedded key / referenced verification - won't implement, who needs it can decode the header
|
||||
and pass the (`x5c`, `jwk`) to `JWK.importKey` and validate with that key, similarly the
|
||||
application can handle fetching the referenced `x5u` or `jku`
|
||||
- ✕ JWS detached content - won't implement, who needs it can remove/attach the payload after/before
|
||||
the respective operation
|
||||
- ✕ "none" alg support, no crypto, no use, don't bother
|
||||
- ✕ JWS embedded key / referenced verification
|
||||
- one can decode the header and pass the (`x5c`, `jwk`) to `JWK.importKey` and validate with that
|
||||
key, similarly the application can handle fetching and then instantiating the referenced `x5u`
|
||||
or `jku` in its own code. This way you opt-in to these behaviours and for `x5c` specifically
|
||||
the recipient is responsible for validating the certificate chain is trusted
|
||||
- ✕ JWS detached content
|
||||
- one can remove/attach the payload after/before the respective operation
|
||||
- ✕ "none" alg support
|
||||
- no crypto, no use
|
||||
|
||||
Not Planned / PR | Use-Case | Discussion Welcome:
|
||||
- ◯ automatically adding `kid` reference to JWS / JWE Headers
|
||||
- ◯ `x5c`, `x5t`, `x5t#S256`, `x5u` etc `JWK.Key` fields
|
||||
|
||||
</details>
|
||||
|
||||
Missing a feature? - If it wasn't already discussed before, [ask for it][suggest-feature].
|
||||
Found a bug? - [report it][bug].
|
||||
<br>
|
||||
|
||||
<h2>Support</h2>
|
||||
Have a question about using @panva/jose? - [ask][ask].
|
||||
Found a bug? - [report it][bug].
|
||||
Missing a feature? - If it wasn't already discussed before, [ask for it][suggest-feature].
|
||||
Found a vulnerability? - Reach out to us via email first, see [security vulnerability disclosure][security-vulnerability].
|
||||
|
||||
## Support
|
||||
|
||||
[<img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" width="160" align="right">][support-patreon]
|
||||
If you or your business use @panva/jose, please consider becoming a [Patron][support-patreon] so I can continue maintaining it and adding new features carefree. You may also donate one-time via [PayPal][support-paypal].
|
||||
[<img src="https://cdn.jsdelivr.net/gh/gregoiresgt/payment-icons@183140a5ff8f39b5a19d59ebeb2c77f03c3a24d3/Assets/Payment/PayPal/Paypal@2x.png" width="100" align="right">][support-paypal]
|
||||
|
||||
## Documentation
|
||||
|
||||
- [@panva/jose API Documentation][documentation]
|
||||
- [JWK (JSON Web Key)][documentation-jwk]
|
||||
- [JWKS (JSON Web Key Set)][documentation-jwks]
|
||||
- [JWS (JSON Web Signature)][documentation-jws]
|
||||
- [JWE (JSON Web Encryption)][documentation-jwe]
|
||||
|
||||
## Usage
|
||||
|
||||
The minimal Node.js version supported is v11.8.0
|
||||
The minimal Node.js version required is v11.8.0
|
||||
|
||||
Installing @panva/jose
|
||||
|
||||
```sh
|
||||
$ npm install @panva/jose
|
||||
```
|
||||
|
||||
Usage
|
||||
```js
|
||||
const jose = require('@panva/jose')
|
||||
const {
|
||||
JWE, // JSON Web Encryption (JWE)
|
||||
JWK, // JSON Web Key (JWK)
|
||||
JWKS, // JSON Web Key Set (JWKS)
|
||||
JWS, // JSON Web Signature (JWS)
|
||||
errors // errors utilized by @panva/jose
|
||||
} = require('@panva/jose')
|
||||
|
||||
} = jose
|
||||
```
|
||||
|
||||
## JWK (JSON Web Key)
|
||||
#### Keys and KeyStores
|
||||
|
||||
All @panva/jose operations require `JWK.Key` or `JWKS.KeyStore` as arguments. Here's
|
||||
how to get a `JWK.Key`.
|
||||
|
||||
#### Class: JWK `<RSAKey>` | `<ECKey>` | `<OctKey>`
|
||||
|
||||
`<RSAKey>`, `<ECKey>` and `<OctKey>` represent a key usable for JWS and JWE operations. The
|
||||
`JWK.importKey()` method is used to retrieve a key representation of an existing key or secret.
|
||||
`JWK.generate()` method is used to generate a new random key.
|
||||
|
||||
#### JWK `#importKey(key[, options])` asymmetric key import
|
||||
|
||||
Imports an asymmetric private or public key. Supports importing JWK formatted keys (private, public,
|
||||
secrets), `pem` and `der` formatted private and public keys, `pem` formatted X.509 certificates.
|
||||
Private keys may also be passphrase protected.
|
||||
|
||||
<details>
|
||||
<summary><em><strong>API</strong></em> (Click to expand)</summary>
|
||||
|
||||
- `key`: `<Object>` | `<string>` | `<Buffer>` | `<KeyObject>`
|
||||
- `key`: `<string>` | `<Buffer>`
|
||||
- `format`: `<string>` Must be 'pem' or 'der'. Default: 'pem'.
|
||||
- `type`: `<string>` Must be 'pkcs1', 'pkcs8' or 'sec1'. This option is required only if the format is 'der' and ignored if it is 'pem'.
|
||||
- `passphrase`: `<string>` | `<Buffer>` The passphrase to use for decryption.
|
||||
- `options`: `<Object>`
|
||||
- `alg`: `<string>` option identifies the algorithm intended for use with the key.
|
||||
- `use`: `<string>` option indicates whether the key is to be used for encrypting & decrypting data or signing & verifying data. Must be 'sig' or 'enc'.
|
||||
- `kid`: `<string>` Key ID Parameter. When not provided is computed using the method defined in [RFC7638][spec-thumbprint]
|
||||
- Returns: `<RSAKey>` | `<ECKey>`
|
||||
|
||||
See the underlying Node.js API for details on importing private and public keys in the different formats
|
||||
|
||||
- [crypto.createPrivateKey(key)](https://nodejs.org/api/crypto.html#crypto_crypto_createprivatekey_key)
|
||||
- [crypto.createPublicKey(key)](https://nodejs.org/api/crypto.html#crypto_crypto_createpublickey_key)
|
||||
- [crypto.createSecretKey(key)](https://nodejs.org/api/crypto.html#crypto_crypto_createsecretkey_key)
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
|
||||
Prepare your Keys and KeyStores. See the [documentation][documentation-jwk] for more.
|
||||
|
||||
```js
|
||||
const { readFileSync } = require('fs')
|
||||
const { JWK: { importKey } } = require('@panva/jose')
|
||||
const key = jose.JWK.importKey(fs.readFileSync('path/to/key/file'))
|
||||
|
||||
const key = importKey(readFileSync('path/to/key/file'))
|
||||
// ECKey {
|
||||
// kty: 'EC',
|
||||
// public: true,
|
||||
// kid: [Getter],
|
||||
// crv: [Getter],
|
||||
// x: [Getter],
|
||||
// y: [Getter] }
|
||||
const jwk = { kty: 'EC',
|
||||
kid: 'dl4M_fcI7XoFCsQ22PYrQBkuxZ2pDcbDimcdFmmXM98',
|
||||
crv: 'P-256',
|
||||
x: 'v37avifcL-xgh8cy6IFzcINqqmFLc2JF20XUpn4Y2uQ',
|
||||
y: 'QTwy27XgP7ZMOdGOSopAHB-FU1JMQn3J9GEWGtUXreQ' }
|
||||
const anotherKey = jose.JWK.importKey(jwk)
|
||||
|
||||
const keystore = new jose.JWK.KeyStore(key, key2)
|
||||
```
|
||||
|
||||
</details>
|
||||
#### Signing
|
||||
|
||||
#### JWK `#importKey(secret[, options])` secret key import
|
||||
|
||||
Imports a symmetric key.
|
||||
|
||||
<details>
|
||||
<summary><em><strong>API</strong></em> (Click to expand)</summary>
|
||||
|
||||
- `secret`: `<string>` | `<Buffer>` | `<KeyObject>`
|
||||
- `options`: `<Object>`
|
||||
- `alg`: `<string>` option identifies the algorithm intended for use with the key.
|
||||
- `use`: `<string>` option indicates whether the key is to be used for encrypting & decrypting data or signing & verifying data. Must be 'sig' or 'enc'.
|
||||
- `kid`: `<string>` Key ID Parameter. When not provided is computed using the method defined in [RFC7638][spec-thumbprint]
|
||||
- Returns: `<OctKey>`
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
|
||||
Sign with a private or symmetric key using compact serialization. See the [documentation][documentation-jws] for more.
|
||||
|
||||
```js
|
||||
const { JWK: { importKey } } = require('@panva/jose')
|
||||
|
||||
const key = importKey(Buffer.from('8yHym6h5CG5FylbzrCn8fhxEbp3kOaTsgLaawaaJ'))
|
||||
// OctKey {
|
||||
// kty: 'oct',
|
||||
// kid: [Getter],
|
||||
// k: [Getter] }
|
||||
jose.JWS.sign(
|
||||
{ sub: 'johndoe' },
|
||||
privateKey
|
||||
)
|
||||
```
|
||||
|
||||
</details>
|
||||
#### Verifying
|
||||
|
||||
#### JWK `#importKey(jwk)` JWK-formatted key import
|
||||
|
||||
Imports a JWK formatted key. This supports JWK formatted EC, RSA and oct keys. Asymmetrical keys
|
||||
may be both private and public.
|
||||
|
||||
<details>
|
||||
<summary><em><strong>API</strong></em> (Click to expand)</summary>
|
||||
|
||||
- `jwk`: `<Object>`
|
||||
- `kty`: `<string>` Key type. Must be 'RSA', 'EC' or 'oct'.
|
||||
- `alg`: `<string>` option identifies the algorithm intended for use with the key.
|
||||
- `use`: `<string>` option indicates whether the key is to be used for encrypting & decrypting data or signing & verifying data. Must be 'sig' or 'enc'.
|
||||
- `kid`: `<string>` Key ID Parameter. When not provided is computed using the method defined in [RFC7638][spec-thumbprint]
|
||||
- `e`, `n` properties as `<string>` for RSA public keys
|
||||
- `e`, `n`, `d`, `p`, `q`, `dp`, `dq`, `qi` properties as `<string>` for RSA private keys
|
||||
- `crv`, `x`, `y` properties as `<string>` for EC public keys
|
||||
- `crv`, `x`, `y`, `d` properties as `<string>` for EC private keys
|
||||
- `k` properties as `<string>` for secret oct keys
|
||||
- Returns: `<RSAKey>` | `<ECKey>` | `<OctKey>`
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
|
||||
Verify with a public or symmetric key. See the [documentation][documentation-jws] for more.
|
||||
|
||||
```js
|
||||
const { JWK: { importKey } } = require('@panva/jose')
|
||||
const jwk = {
|
||||
kty: 'RSA',
|
||||
kid: 'r1LkbBo3925Rb2ZFFrKyU3MVex9T2817Kx0vbi6i_Kc',
|
||||
use: 'sig',
|
||||
e: 'AQAB',
|
||||
n: 'xwQ72P9z9OYshiQ-ntDYaPnnfwG6u9JAdLMZ5o0dmjlcyrvwQRdoFIKPnO65Q8mh6F_LDSxjxa2Yzo_wdjhbPZLjfUJXgCzm54cClXzT5twzo7lzoAfaJlkTsoZc2HFWqmcri0BuzmTFLZx2Q7wYBm0pXHmQKF0V-C1O6NWfd4mfBhbM-I1tHYSpAMgarSm22WDMDx-WWI7TEzy2QhaBVaENW9BKaKkJklocAZCxk18WhR0fckIGiWiSM5FcU1PY2jfGsTmX505Ub7P5Dz75Ygqrutd5tFrcqyPAtPTFDk8X1InxkkUwpP3nFU5o50DGhwQolGYKPGtQ-ZtmbOfcWQ'
|
||||
}
|
||||
|
||||
const key = importKey(jwk)
|
||||
// RSAKey {
|
||||
// kty: 'RSA',
|
||||
// public: true,
|
||||
// use: 'sig',
|
||||
// kid: 'r1LkbBo3925Rb2ZFFrKyU3MVex9T2817Kx0vbi6i_Kc',
|
||||
// e: [Getter],
|
||||
// n: [Getter] }
|
||||
jose.JWS.verify(
|
||||
'eyJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJqb2huZG9lIn0.T_SYLQV3A5_kFDDVNuoadoURSEtuSOR-dG2CMmrP-ULK9xbIf2vYeiHOkvTrnqGlWEGBGxYtsP1VkXmNsi1uOw',
|
||||
publicKey
|
||||
)
|
||||
```
|
||||
|
||||
</details>
|
||||
#### Encrypting
|
||||
|
||||
#### JWK `#generate(kty[, crvOrSize[, options[, private]]])` generating new keys
|
||||
Encrypt using the recipient's public key or a shared symmetrical secret. See the [documentation][documentation-jwe] for more.
|
||||
|
||||
Securely generates a new RSA, EC or oct key.
|
||||
```js
|
||||
jose.JWE.encrypt(
|
||||
'eyJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJqb2huZG9lIn0.T_SYLQV3A5_kFDDVNuoadoURSEtuSOR-dG2CMmrP-ULK9xbIf2vYeiHOkvTrnqGlWEGBGxYtsP1VkXmNsi1uOw',
|
||||
publicKey
|
||||
)
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary><em><strong>API</strong></em> (Click to expand)</summary>
|
||||
#### Verifying
|
||||
|
||||
- `kty`: `<string>` Key type. Must be 'RSA', 'EC' or 'oct'.
|
||||
- `crvOrSize`: `<number>` | `<string>` key's bit size or in case of EC keys the curve
|
||||
- `options`: `<Object>`
|
||||
- `alg`: `<string>` option identifies the algorithm intended for use with the key.
|
||||
- `use`: `<string>` option indicates whether the key is to be used for encrypting & decrypting data or signing & verifying data. Must be 'sig' or 'enc'.
|
||||
- `kid`: `<string>` Key ID Parameter. When not provided is computed using the method defined in [RFC7638][spec-thumbprint]
|
||||
- `private`: `<boolean>` **Default** 'true'. Is the resulting key private or public (when asymmetrical)
|
||||
- Returns: `Promise<RSAKey>` | `Promise<ECKey>` | `Promise<OctKey>`
|
||||
Decrypt using the private key or a shared symmetrical secret. See the [documentation][documentation-jwe] for more.
|
||||
|
||||
</details>
|
||||
```js
|
||||
jose.JWE.decrypt(
|
||||
'eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiRUNESC1FUyIsImVwayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6IkVsUGhsN1ljTVZsWkhHM0daSkRoOVJhemNYYlN2VFNheUF6aTBINFFtRUEiLCJ5IjoiM0hDREJTRy12emd6cGtLWmJqMU05UzVuUEJrTDBBdFM4U29ORUxMWE1SayJ9fQ..FhmidRo0twvFA7jcfKFNJw.o112vgiG_qUL1JR5WHpsErcxxgaK_FAa7vCWJ--WulndLpdwdRXHd9k3aL_k8K67xoAThrt10d7dSY2TlPpHdYkw979u0V-C4TNrpzNkv5jpBjU6hHyKpoGZfEsiTD1ivHaFy3ZLCTS69kN_eVKsZGLVf_dkq6Sz6bWE4-ln_fuwukPyMvjTyaTreLjPLBZW.ocKwptCm4Zn437L5hWFnHg',
|
||||
privateKey
|
||||
)
|
||||
```
|
||||
|
||||
#### JWK `#generateSync(kty[, crvOrSize[, options[, private]]])`
|
||||
## FAQ
|
||||
|
||||
Synchronous version of JWK `#generate`
|
||||
#### Semver?
|
||||
|
||||
<details>
|
||||
<summary><em><strong>API</strong></em> (Click to expand)</summary>
|
||||
**Yes.** Everything that's either exported in the TypeScript definitions file or [documented][documentation]
|
||||
is subject to [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html). The rest is to be
|
||||
considered private API and is subject to change between any versions.
|
||||
|
||||
- `kty`: `<string>` Key type. Must be 'RSA', 'EC' or 'oct'.
|
||||
- `crvOrSize`: `<number>` | `<string>` key's bit size or in case of EC keys the curve. **Default** 2048 for RSA, 'P-256' for EC and 256 for oct.
|
||||
- `options`: `<Object>`
|
||||
- `alg`: `<string>` option identifies the algorithm intended for use with the key.
|
||||
- `use`: `<string>` option indicates whether the key is to be used for encrypting & decrypting data or signing & verifying data. Must be 'sig' or 'enc'.
|
||||
- `kid`: `<string>` Key ID Parameter. When not provided is computed using the method defined in [RFC7638][spec-thumbprint]
|
||||
- `private`: `<boolean>` **Default** 'true'. Is the resulting key private or public (when asymmetrical)
|
||||
- Returns: `<RSAKey>` | `<ECKey>` | `<OctKey>`
|
||||
#### How do I use it outside of Node.js
|
||||
|
||||
</details>
|
||||
It is **only built for Node.js** environment - it builds on top of the `crypto` module and requires
|
||||
the KeyObject API that was added in Node.js v11.6.0.
|
||||
|
||||
## JWKS (JSON Web Key Set)
|
||||
#### How is it different from [`node-jose`][node-jose]
|
||||
|
||||
- [Class: KeyStore](#class-keystore)
|
||||
- [new KeyStore([keys])](#new-keystorekeys)
|
||||
- [keystore.all([parameters])](#keystoreallparameters)
|
||||
- [keystore.get([parameters])](#keystoregetparameters)
|
||||
- [keystore.add(key)](#keystoreaddkey)
|
||||
- [keystore.remove(key)](#keystoreremovekey)
|
||||
- [keystore.generate(...)](#keystoregenerate)
|
||||
- [keystore.generateSync(...)](#keystoregeneratesync)
|
||||
`node-jose` is built to work in any javascript runtime, to be able to do that it packs a lot of
|
||||
backfill and javascript implementation code in the form of
|
||||
[`node-forge`](https://github.com/digitalbazaar/forge), this significantly increases the footprint
|
||||
of the module with dependencies that either aren't ever used or have native implementation available
|
||||
in Node.js already, those are often times faster and more reliable.
|
||||
|
||||
#### Class: `KeyStore`
|
||||
#### How is it different from [`node-jws`](https://github.com/brianloveswords/node-jws) or [`node-jwa`](https://github.com/brianloveswords/node-jwa)?
|
||||
|
||||
`KeyStore` is an abstraction representing a set of JWKs
|
||||
- it is providing Key and KeyStore abstractions
|
||||
- there is JSON Web Encryption support
|
||||
- there is no asynchronous API since node crypto is ultimately entirely synchronous
|
||||
- it supports all JWS / JWE Serialization Syntaxes
|
||||
|
||||
#### `new KeyStore([keys])`
|
||||
#### What is the ultimate goal?
|
||||
|
||||
Creates a new KeyStore, either empty or populated.
|
||||
- **No dependencies**, the moment JWK formatted keys are supported by node's `crypto` the direct
|
||||
dependency count will go down from 1 to 0. 🚀
|
||||
- Just the API one needs, having used other jose modules for 3+ years I only include what's useful
|
||||
|
||||
<details>
|
||||
<summary><em><strong>API</strong></em> (Click to expand)</summary>
|
||||
#### Why? Just, why?
|
||||
|
||||
- `keys`: `<Key[]>` Array of key keys instantiated by `JWK.importKey`
|
||||
- Returns: `<KeyStore>`
|
||||
I was / (still am) using [`node-jose`][node-jose] for [`openid-client`](https://github.com/panva/node-openid-client)
|
||||
and [`oidc-provider`](https://github.com/panva/node-oidc-provider) and came to realize its shortcomings
|
||||
in terms of performance and API (not having well defined errors). When Node.js v12 lands in April
|
||||
2019 I will be releasing new major versions of both those libraries using @panva/jose.
|
||||
|
||||
</details>
|
||||
|
||||
#### `keystore.all([parameters])`
|
||||
|
||||
Retrieves an array of keys matching the provider parameters, returns all if none are provided. The
|
||||
returned array is sorted by relevance based on the parameters. Keys with the exact algorithm or use
|
||||
specified by the parameters are first.
|
||||
|
||||
<details>
|
||||
<summary><em><strong>API</strong></em> (Click to expand)</summary>
|
||||
|
||||
- `parameters`: `<Object>`
|
||||
- `kty`: `<string>` Key Type to filter for.
|
||||
- `alg`: `<string>` Key supported algorithm to filter for.
|
||||
- `use`: `<string>` Key use to filter for.
|
||||
- `kid`: `<string>` Key ID to filter for.
|
||||
- Returns: `<Key[]>` Array of key instances or an empty array when none are matching the parameters.
|
||||
|
||||
</details>
|
||||
|
||||
#### `keystore.get([parameters])`
|
||||
|
||||
Retrieves a single key matching the provider parameters. The most relevant Key based on the
|
||||
parameters is returned.
|
||||
|
||||
<details>
|
||||
<summary><em><strong>API</strong></em> (Click to expand)</summary>
|
||||
|
||||
- `parameters`: `<Object>`
|
||||
- `kty`: `<string>` Key Type to filter for.
|
||||
- `alg`: `<string>` Key supported algorithm to filter for.
|
||||
- `use`: `<string>` Key use to filter for.
|
||||
- `kid`: `<string>` Key ID to filter for.
|
||||
- Returns: `<RSAKey>` | `<ECKey>` | `<OctKey>` | `<undefined>`
|
||||
|
||||
</details>
|
||||
|
||||
#### `keystore.add(key)`
|
||||
|
||||
Adds a key instance to the store unless it is already included.
|
||||
|
||||
<details>
|
||||
<summary><em><strong>API</strong></em> (Click to expand)</summary>
|
||||
|
||||
- `key`: `<RSAKey>` | `<ECKey>` | `<OctKey>`
|
||||
|
||||
</details>
|
||||
|
||||
#### `keystore.remove(key)`
|
||||
|
||||
Ensures a key is removed from a store.
|
||||
|
||||
<details>
|
||||
<summary><em><strong>API</strong></em> (Click to expand)</summary>
|
||||
|
||||
- `key`: `<RSAKey>` | `<ECKey>` | `<OctKey>`
|
||||
|
||||
</details>
|
||||
|
||||
#### `keystore.generate(...)`
|
||||
|
||||
Asynchronously generates new random key and automatically adds it to the store. See `JWK.generate` for the API.
|
||||
|
||||
#### `keystore.generateSync(...)`
|
||||
|
||||
Synchronous version of `keystore.generate`.
|
||||
+ this was an amazing opportunity to learn JOSE as a whole
|
||||
|
||||
#### Where's the performance coming from?
|
||||
|
||||
No endless stream of yielded promises, uses KeyObject instances for crypto operations, once a
|
||||
KeyObject is instantiated the keys do not need to be "prepped" and validated any more in neither
|
||||
the Node runtime nor the underlying OpenSSL implementation. In some cases this yields 2x throughput
|
||||
for the actual crypto operation.
|
||||
|
||||
[node-jose]: https://github.com/cisco/node-jose
|
||||
[documentation]: https://github.com/panva/jose/blob/master/docs/README.md
|
||||
[documentation-jws]: https://github.com/panva/jose/blob/master/docs/README.md#jws-json-web-signature
|
||||
[documentation-jwe]: https://github.com/panva/jose/blob/master/docs/README.md#jwe-json-web-encryption
|
||||
[documentation-jwk]: https://github.com/panva/jose/blob/master/docs/README.md#jwk-json-web-key
|
||||
[documentation-jwks]: https://github.com/panva/jose/blob/master/docs/README.md#jwks-json-web-key-set
|
||||
[documentation]: https://github.com/panva/jose/blob/master/docs/README.md
|
||||
[documentation]: https://github.com/panva/jose/blob/master/docs/README.md
|
||||
[travis-image]: https://api.travis-ci.com/panva/jose.svg?branch=master
|
||||
[travis-url]: https://travis-ci.com/panva/jose
|
||||
[codecov-image]: https://img.shields.io/codecov/c/github/panva/jose/master.svg
|
||||
[codecov-url]: https://codecov.io/gh/panva/jose
|
||||
[suggest-feature]: https://github.com/panva/jose/issues/new?template=feature-request.md
|
||||
[bug]: https://github.com/panva/jose/issues/new?template=bug-report.md
|
||||
[suggest-feature]: https://github.com/panva/jose/issues/new?labels=enhancement&template=feature-request.md&title=proposal%3A+
|
||||
[bug]: https://github.com/panva/jose/issues/new?labels=bug&template=bug-report.md&title=bug%3A+
|
||||
[ask]: https://github.com/panva/jose/issues/new?labels=question&template=question.md&title=question%3A+
|
||||
[security-vulnerability]: https://github.com/panva/jose/issues/new?template=security-vulnerability.md
|
||||
[support-patreon]: https://www.patreon.com/panva
|
||||
[support-paypal]: https://www.paypal.me/panva
|
||||
[spec-jwa]: https://tools.ietf.org/html/rfc7518
|
||||
|
|
@ -396,5 +264,6 @@ Synchronous version of `keystore.generate`.
|
|||
[spec-jwe]: https://tools.ietf.org/html/rfc7516
|
||||
[spec-b64]: https://tools.ietf.org/html/rfc7797
|
||||
[spec-jwk]: https://tools.ietf.org/html/rfc7517
|
||||
[spec-cfrg]: https://tools.ietf.org/html/rfc8037
|
||||
[spec-thumbprint]: https://tools.ietf.org/html/rfc7638
|
||||
[spec-cookbook]: https://tools.ietf.org/html/rfc7520
|
||||
|
|
|
|||
922
docs/README.md
Normal file
922
docs/README.md
Normal file
|
|
@ -0,0 +1,922 @@
|
|||
# @panva/jose API Documentation
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
- [JWK (JSON Web Key)](#jwk-json-web-key)
|
||||
- [JWKS (JSON Web Key Set)](#jwks-json-web-key-set)
|
||||
- [JWS (JSON Web Signature)](#jws-json-web-signature)
|
||||
- [JWE (JSON Web Encryption)](#jwe-json-web-encryption)
|
||||
|
||||
## Support
|
||||
|
||||
[<img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" width="160" align="right">][support-patreon]
|
||||
If you or your business use @panva/jose, please consider becoming a [Patron][support-patreon] so I can continue maintaining it and adding new features carefree. You may also donate one-time via [PayPal][support-paypal].
|
||||
[<img src="https://cdn.jsdelivr.net/gh/gregoiresgt/payment-icons@183140a5ff8f39b5a19d59ebeb2c77f03c3a24d3/Assets/Payment/PayPal/Paypal@2x.png" width="100" align="right">][support-paypal]
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
## JWK (JSON Web Key)
|
||||
|
||||
<!-- TOC JWK START -->
|
||||
- [Class: <JWK.Key> and <JWK.RSAKey> | <JWK.ECKey> | <JWK.OctKey>](#class-jwkkey-and-jwkrsakey--jwkeckey--jwkoctkey)
|
||||
- [key.kty](#keykty)
|
||||
- [key.alg](#keyalg)
|
||||
- [key.use](#keyuse)
|
||||
- [key.kid](#keykid)
|
||||
- [key.public](#keypublic)
|
||||
- [key.private](#keyprivate)
|
||||
- [key.algorithms([operation])](#keyalgorithmsoperation)
|
||||
- [key.toJWK([private])](#keytojwkprivate)
|
||||
- JWK.importKey
|
||||
- [JWK.importKey(key[, options]) asymmetric key import](#jwkimportkeykey-options-asymmetric-key-import)
|
||||
- [JWK.importKey(secret[, options]) secret key import](#jwkimportkeysecret-options-secret-key-import)
|
||||
- [JWK.importKey(jwk) JWK-formatted key import](#jwkimportkeyjwk-jwk-formatted-key-import)
|
||||
- [JWK.generate(kty[, crvOrSize[, options[, private]]]) generating new keys](#jwkgeneratekty-crvorsize-options-private-generating-new-keys)
|
||||
- [JWK.generateSync(kty[, crvOrSize[, options[, private]]])](#jwkgeneratesynckty-crvorsize-options-private)
|
||||
- [JWK.isKey(object)](#jwkiskeyobject)
|
||||
<!-- TOC JWK END -->
|
||||
|
||||
All @panva/jose operations require `<JWK.Key>` or `<JWKS.KeyStore>` as arguments. Here's
|
||||
how to get a `<JWK.Key>` instances generated or instantiated from existing key material.
|
||||
|
||||
|
||||
```js
|
||||
const { JWK } = require('@panva/jose')
|
||||
// { importKey: [Function: importKey],
|
||||
// generate: [AsyncFunction: generate],
|
||||
// generateSync: [Function: generateSync] }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Class: `<JWK.Key>` and `<JWK.RSAKey>` | `<JWK.ECKey>` | `<JWK.OctKey>`
|
||||
|
||||
`<JWK.RSAKey>`, `<JWK.ECKey>` and `<JWK.OctKey>` represent a key usable for JWS and JWE operations. The
|
||||
`JWK.importKey()` method is used to retrieve a key representation of an existing key or secret.
|
||||
`JWK.generate()` method is used to generate a new random key.
|
||||
|
||||
`<JWK.RSAKey>`, `<JWK.ECKey>` and `<JWK.OctKey>` inherit methods from `<JWK.Key>` and in addition
|
||||
to the properties documented below have the respective key component properties exported as `<string>`
|
||||
in their format defined by the specifications.
|
||||
|
||||
- `e, n` for Public RSA Keys
|
||||
- `e, n, d, p, q, dp, dq, qi` for Private RSA Keys
|
||||
- `crv, x, y` for Public EC Keys
|
||||
- `crv, x, y, n` for Private EC Keys
|
||||
- `k` for Symmetric keys
|
||||
|
||||
---
|
||||
|
||||
#### `key.kty`
|
||||
|
||||
Returns the key's JWK Key Type Parameter. 'EC', 'RSA' or 'oct' for the respective supported key types
|
||||
|
||||
- `<string>`
|
||||
|
||||
---
|
||||
|
||||
#### `key.alg`
|
||||
|
||||
Returns the key's JWK Algorithm Parameter if set, undefined otherwise. If set the key is only usable
|
||||
for that one algorithm and will fail when used with others.
|
||||
|
||||
- `<string>`
|
||||
|
||||
---
|
||||
|
||||
#### `key.use`
|
||||
|
||||
Returns the key's JWK Key Use Parameter if set, undefined otherwise. Only 'sig' and 'enc' values
|
||||
are supported. If set the key can only be used for either signing / verification or encryption
|
||||
related operations (key management or encryption)
|
||||
|
||||
- `<string>`
|
||||
|
||||
---
|
||||
|
||||
#### `key.kid`
|
||||
|
||||
Returns the key's JWK Key ID Parameter if set, if not set it will be calculated using the method
|
||||
defined in [RFC7638][spec-thumbprint]
|
||||
|
||||
- `<string>`
|
||||
|
||||
---
|
||||
|
||||
#### `key.public`
|
||||
|
||||
Returns true/false if the key is asymmetric and public. Returns false for symmetric keys.
|
||||
|
||||
- `<boolean>`
|
||||
|
||||
---
|
||||
|
||||
#### `key.private`
|
||||
|
||||
Returns true/false if the key is asymmetric and private. Returns false for symmetric keys.
|
||||
|
||||
- `<boolean>`
|
||||
|
||||
---
|
||||
|
||||
#### `key.algorithms([operation])`
|
||||
|
||||
Returns a [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)
|
||||
of algorithms the key may perform.
|
||||
|
||||
- `operation`: `<string>` Must be one of 'encrypt', 'decrypt', 'sign', 'verify', 'wrapKey', 'unwrapKey'
|
||||
- Returns: `Set<string>`
|
||||
|
||||
<details>
|
||||
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
|
||||
|
||||
```js
|
||||
const { JWK: { generateSync } } = require('@panva/jose')
|
||||
|
||||
const privateKey = generateSync('RSA')
|
||||
privateKey.algorithms()
|
||||
// Set {
|
||||
// 'PS256',
|
||||
// 'RS256',
|
||||
// 'PS384',
|
||||
// 'RS384',
|
||||
// 'PS512',
|
||||
// 'RS512',
|
||||
// 'RSA-OAEP',
|
||||
// 'RSA1_5' }
|
||||
privateKey.algorithms('wrapKey')
|
||||
// Set {
|
||||
// 'RSA-OAEP',
|
||||
// 'RSA1_5' }
|
||||
|
||||
const publicKey = generateSync('RSA', 2048, { use: 'enc' }, false)
|
||||
publicKey.algorithms('sign')
|
||||
// Set {}
|
||||
publicKey.algorithms('unwrapKey')
|
||||
// Set {}
|
||||
publicKey.algorithms('wrapKey')
|
||||
// Set {
|
||||
// 'RSA-OAEP',
|
||||
// 'RSA1_5' }
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
#### `key.toJWK([private])`
|
||||
|
||||
Exports the key to a JSON Web Key formatted object.
|
||||
|
||||
- `private`: `<boolean>` When true exports keys with its private components. **Default:** 'false'
|
||||
- Returns: `<Object>`
|
||||
|
||||
<details>
|
||||
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
|
||||
|
||||
```js
|
||||
const { JWK: { generateSync } } = require('@panva/jose')
|
||||
|
||||
const key = generateSync('RSA', 2048, { use: 'sig', alg: 'PS256' })
|
||||
key.toJWK()
|
||||
// { kty: 'RSA',
|
||||
// kid: 'UFldqYiAzlc1aGj5SoqxqYnWcv2Nc4us2ryQe3-FsUA',
|
||||
// e: 'AQAB',
|
||||
// n:
|
||||
// 'uKEKEJUrnfBdXr6zmzq91fQHhW_8GFFUAYtvt5Uvj9wzsWDbspfL9MorhJgkPioo9T6QQvyyEJBaAQOLZxLsPORk83vmB9OACQT3PEM2LbSFK7XUoZGwqlf8Anvs7M1GwvypYbc1v1WrCqcsjrbmYF9TZkV8nNsy2cweh9gFNR-lIiZCHWDgnP6PifoeGvC9RxKdusFa66vtUJGUcoVmMoiOM7EDVdYOP91qJtbDBx7NPPywwD-8pt3UVBW0bYvOqHGF6XXky5JiB8AZQ2NdZHWxklaM2fd8Mxu9CT3xSYg51nS0KV7wO9lAh_ynBpxE2Qmr-7nvKkkDMOL1FSoEQw',
|
||||
// alg: 'PS256',
|
||||
// use: 'sig' }
|
||||
key.toJWK(true)
|
||||
// { kty: 'RSA',
|
||||
// kid: 'UFldqYiAzlc1aGj5SoqxqYnWcv2Nc4us2ryQe3-FsUA',
|
||||
// e: 'AQAB',
|
||||
// n:
|
||||
// 'uKEKEJUrnfBdXr6zmzq91fQHhW_8GFFUAYtvt5Uvj9wzsWDbspfL9MorhJgkPioo9T6QQvyyEJBaAQOLZxLsPORk83vmB9OACQT3PEM2LbSFK7XUoZGwqlf8Anvs7M1GwvypYbc1v1WrCqcsjrbmYF9TZkV8nNsy2cweh9gFNR-lIiZCHWDgnP6PifoeGvC9RxKdusFa66vtUJGUcoVmMoiOM7EDVdYOP91qJtbDBx7NPPywwD-8pt3UVBW0bYvOqHGF6XXky5JiB8AZQ2NdZHWxklaM2fd8Mxu9CT3xSYg51nS0KV7wO9lAh_ynBpxE2Qmr-7nvKkkDMOL1FSoEQw',
|
||||
// d:
|
||||
// 'F9G24bLNAMBM23dQ5prqeNrVyZJL_LspUlWx4QZfL3kiNiUf0uegiYE3ohCaxGZeCF288Nd3BYoKAo15g5--WJDCsWLvp1zS7Nb2KpElQTpD4ALCXuHT3_Yf7hYc1-QX1_oOxCuFxJyBx4sPxY21JQPHV69pRzdEVTLvUWk-Kr8k-kgu8xFOsyqLK0g0IBAtwOX2ksIPLuHT-nGh_VQwfpJowq1MoUZD-y_6Ai5HWAZy9t6gARpG3K4yBcmAQBRIQgoFiGw41BqVB5fJyjVZDsMbvT_iEFKkrHRjifUI6QTNtt1k9xOFIL_Ojzn6aLylm58AGD8oORWZvfpmJJ03yQ',
|
||||
// p:
|
||||
// '8lvcv5Ov9rJsa_kaCJBRijeOdz3La11_26o2QDpkINFKKoDNWRpIT0KZNF4P16Z5OXOK6rSezuN2vACAPg3riUHVdbRyFhMI6FvQhlx7unyv07xBBqbnp8dV2NiQv3-rFeNPV_5RqZHJyqQga-VUXvwics3eUzm_2CbrMQG3Klc',
|
||||
// q:
|
||||
// 'wwVZ6d5uZm9kj3tWICF1FqCWHwSWMt1wgFZ3DOp2LPuqBHjYPas4zwXd3V4wolaCi8irbTfbL0F6c51yN72-enAjgm6r5yzxedkV9GWk5U0y8VrNwYm55qz1o88LB6PX6RG5Lp2rYZp_34dgCrllQc8T-5YY4KIHy7TaLkKkGfU',
|
||||
// dp:
|
||||
// 'sPZseCIxcPOVAT3xSWF_eGnah6zCVJH_4vglBr7cD65h9ij4R-BN_jnFvhwUe0Ud7No2C-x4rN4f-2RuP2FQo3dDkt-AEigx79_iocjzuxaCGBu0a1QBgFunjl-LSZjB5oiEjd6v6B4AdwtidQYNlhGKYcN6W9CmCQFZ5_21rZ8',
|
||||
// dq:
|
||||
// 'sokKmGSuUw61U_mIjh-zDoTzCfBsBKLepE8D7AoVJ_c43aE37bT7a-MmCst44JUsLAYIkhMpkKh0DrXb45XMdFCG4ZipvRhS9Ma9J6GKBPXYpkYHyZ9pVfmPY2he456mQdOc4UUsqU0EtcE8NnUlcsq9s3vkyHjthBrMBr-xdaU',
|
||||
// qi:
|
||||
// 'jbZrzP8f3y0-ZAjqSQAPbKnQI0Vli952nQTUgffF2Bh2q0dB719PHjmIV7NjwCFOMcNx-2usJFwI9VikgN9GTGauakvG7SFzXD8yHiRzFwcjYvXDuJ-4Q1Yjo1m4JUIW_BLVnzauSg0P9qnxT1dxvchEQRIIfF72FW80BsJD4LQ',
|
||||
// alg: 'PS256',
|
||||
// use: 'sig' }
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
#### `JWK.importKey(key[, options])` asymmetric key import
|
||||
|
||||
Imports an asymmetric private or public key. Supports importing JWK formatted keys (private, public,
|
||||
secrets), `pem` and `der` formatted private and public keys, `pem` formatted X.509 certificates.
|
||||
Private keys may also be passphrase protected.
|
||||
|
||||
|
||||
- `key`: `<Object>` | `<string>` | `<Buffer>` | `<KeyObject>`
|
||||
- `key`: `<string>` | `<Buffer>`
|
||||
- `format`: `<string>` Must be 'pem' or 'der'. **Default:** 'pem'.
|
||||
- `type`: `<string>` Must be 'pkcs1', 'pkcs8' or 'sec1'. This option is required only if the format is 'der' and ignored if it is 'pem'.
|
||||
- `passphrase`: `<string>` | `<Buffer>` The passphrase to use for decryption.
|
||||
- `options`: `<Object>`
|
||||
- `alg`: `<string>` option identifies the algorithm intended for use with the key.
|
||||
- `use`: `<string>` option indicates whether the key is to be used for encrypting & decrypting data or signing & verifying data. Must be 'sig' or 'enc'.
|
||||
- `kid`: `<string>` Key ID Parameter. When not provided is computed using the method defined in [RFC7638][spec-thumbprint]
|
||||
- Returns: `<JWK.RSAKey>` | `<JWK.ECKey>`
|
||||
|
||||
See the underlying Node.js API for details on importing private and public keys in the different formats
|
||||
|
||||
- [crypto.createPrivateKey(key)](https://nodejs.org/api/crypto.html#crypto_crypto_createprivatekey_key)
|
||||
- [crypto.createPublicKey(key)](https://nodejs.org/api/crypto.html#crypto_crypto_createpublickey_key)
|
||||
- [crypto.createSecretKey(key)](https://nodejs.org/api/crypto.html#crypto_crypto_createsecretkey_key)
|
||||
|
||||
<details>
|
||||
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
|
||||
|
||||
```js
|
||||
const { readFileSync } = require('fs')
|
||||
const { JWK: { importKey } } = require('@panva/jose')
|
||||
|
||||
const key = importKey(readFileSync('path/to/key/file'))
|
||||
// ECKey {
|
||||
// kty: 'EC',
|
||||
// public: true,
|
||||
// kid: [Getter],
|
||||
// crv: [Getter],
|
||||
// x: [Getter],
|
||||
// y: [Getter] }
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
#### `JWK.importKey(secret[, options])` secret key import
|
||||
|
||||
Imports a symmetric key.
|
||||
|
||||
- `secret`: `<string>` | `<Buffer>` | `<KeyObject>`
|
||||
- `options`: `<Object>`
|
||||
- `alg`: `<string>` option identifies the algorithm intended for use with the key.
|
||||
- `use`: `<string>` option indicates whether the key is to be used for encrypting & decrypting data or signing & verifying data. Must be 'sig' or 'enc'.
|
||||
- `kid`: `<string>` Key ID Parameter. When not provided is computed using the method defined in [RFC7638][spec-thumbprint]
|
||||
- Returns: `<JWK.OctKey>`
|
||||
|
||||
<details>
|
||||
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
|
||||
|
||||
```js
|
||||
const { JWK: { importKey } } = require('@panva/jose')
|
||||
|
||||
const key = importKey(Buffer.from('8yHym6h5CG5FylbzrCn8fhxEbp3kOaTsgLaawaaJ'))
|
||||
// OctKey {
|
||||
// kty: 'oct',
|
||||
// kid: [Getter],
|
||||
// k: [Getter] }
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
#### `JWK.importKey(jwk)` JWK-formatted key import
|
||||
|
||||
Imports a JWK formatted key. This supports JWK formatted EC, RSA and oct keys. Asymmetrical keys
|
||||
may be both private and public.
|
||||
|
||||
- `jwk`: `<Object>`
|
||||
- `kty`: `<string>` Key type. Must be 'RSA', 'EC' or 'oct'.
|
||||
- `alg`: `<string>` option identifies the algorithm intended for use with the key.
|
||||
- `use`: `<string>` option indicates whether the key is to be used for encrypting & decrypting data or signing & verifying data. Must be 'sig' or 'enc'.
|
||||
- `kid`: `<string>` Key ID Parameter. When not provided is computed using the method defined in [RFC7638][spec-thumbprint]
|
||||
- `e`, `n` properties as `<string>` for RSA public keys
|
||||
- `e`, `n`, `d`, `p`, `q`, `dp`, `dq`, `qi` properties as `<string>` for RSA private keys
|
||||
- `crv`, `x`, `y` properties as `<string>` for EC public keys
|
||||
- `crv`, `x`, `y`, `d` properties as `<string>` for EC private keys
|
||||
- `k` properties as `<string>` for secret oct keys
|
||||
- Returns: `<JWK.RSAKey>` | `<JWK.ECKey>` | `<JWK.OctKey>`
|
||||
|
||||
<details>
|
||||
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
|
||||
|
||||
```js
|
||||
const { JWK: { importKey } } = require('@panva/jose')
|
||||
const jwk = {
|
||||
kty: 'RSA',
|
||||
kid: 'r1LkbBo3925Rb2ZFFrKyU3MVex9T2817Kx0vbi6i_Kc',
|
||||
use: 'sig',
|
||||
e: 'AQAB',
|
||||
n: 'xwQ72P9z9OYshiQ-ntDYaPnnfwG6u9JAdLMZ5o0dmjlcyrvwQRdoFIKPnO65Q8mh6F_LDSxjxa2Yzo_wdjhbPZLjfUJXgCzm54cClXzT5twzo7lzoAfaJlkTsoZc2HFWqmcri0BuzmTFLZx2Q7wYBm0pXHmQKF0V-C1O6NWfd4mfBhbM-I1tHYSpAMgarSm22WDMDx-WWI7TEzy2QhaBVaENW9BKaKkJklocAZCxk18WhR0fckIGiWiSM5FcU1PY2jfGsTmX505Ub7P5Dz75Ygqrutd5tFrcqyPAtPTFDk8X1InxkkUwpP3nFU5o50DGhwQolGYKPGtQ-ZtmbOfcWQ'
|
||||
}
|
||||
|
||||
const key = importKey(jwk)
|
||||
// RSAKey {
|
||||
// kty: 'RSA',
|
||||
// public: true,
|
||||
// use: 'sig',
|
||||
// kid: 'r1LkbBo3925Rb2ZFFrKyU3MVex9T2817Kx0vbi6i_Kc',
|
||||
// e: [Getter],
|
||||
// n: [Getter] }
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
#### `JWK.generate(kty[, crvOrSize[, options[, private]]])` generating new keys
|
||||
|
||||
Securely generates a new RSA, EC or oct key.
|
||||
|
||||
- `kty`: `<string>` Key type. Must be 'RSA', 'EC' or 'oct'.
|
||||
- `crvOrSize`: `<number>` | `<string>` key's bit size or in case of EC keys the curve
|
||||
- `options`: `<Object>`
|
||||
- `alg`: `<string>` option identifies the algorithm intended for use with the key.
|
||||
- `use`: `<string>` option indicates whether the key is to be used for encrypting & decrypting data or signing & verifying data. Must be 'sig' or 'enc'.
|
||||
- `kid`: `<string>` Key ID Parameter. When not provided is computed using the method defined in [RFC7638][spec-thumbprint]
|
||||
- `private`: `<boolean>` **Default** 'true'. Is the resulting key private or public (when asymmetrical)
|
||||
- Returns: `Promise<JWK.RSAKey>` | `Promise<JWK.ECKey>` | `Promise<JWK.OctKey>`
|
||||
|
||||
<details>
|
||||
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
|
||||
|
||||
```js
|
||||
const { JWK: { generate } } = require('@panva/jose')
|
||||
(async () => {
|
||||
const key = await generate('EC', 'P-384', { use: 'sig' })
|
||||
// ECKey {
|
||||
// kty: 'EC',
|
||||
// private: true,
|
||||
// use: 'sig',
|
||||
// kid: [Getter],
|
||||
// crv: [Getter],
|
||||
// x: [Getter],
|
||||
// y: [Getter],
|
||||
// d: [Getter] }
|
||||
})()
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
#### `JWK.generateSync(kty[, crvOrSize[, options[, private]]])`
|
||||
|
||||
Synchronous version of `JWK.generate()`
|
||||
|
||||
- `kty`: `<string>` Key type. Must be 'RSA', 'EC' or 'oct'.
|
||||
- `crvOrSize`: `<number>` | `<string>` key's bit size or in case of EC keys the curve. **Default** 2048 for RSA, 'P-256' for EC and 256 for oct.
|
||||
- `options`: `<Object>`
|
||||
- `alg`: `<string>` option identifies the algorithm intended for use with the key.
|
||||
- `use`: `<string>` option indicates whether the key is to be used for encrypting & decrypting data or signing & verifying data. Must be 'sig' or 'enc'.
|
||||
- `kid`: `<string>` Key ID Parameter. When not provided is computed using the method defined in [RFC7638][spec-thumbprint]
|
||||
- `private`: `<boolean>` **Default** 'true'. Is the resulting key private or public (when asymmetrical)
|
||||
- Returns: `<JWK.RSAKey>` | `<JWK.ECKey>` | `<JWK.OctKey>`
|
||||
|
||||
<details>
|
||||
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
|
||||
|
||||
```js
|
||||
const { JWK: { generateSync } } = require('@panva/jose')
|
||||
const key = generateSync('RSA', 2048, { use: 'enc' })
|
||||
// RSAKey {
|
||||
// kty: 'RSA',
|
||||
// private: true,
|
||||
// use: 'enc',
|
||||
// kid: [Getter],
|
||||
// e: [Getter],
|
||||
// n: [Getter],
|
||||
// d: [Getter],
|
||||
// p: [Getter],
|
||||
// q: [Getter],
|
||||
// dp: [Getter],
|
||||
// dq: [Getter],
|
||||
// qi: [Getter] }
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
#### `JWK.isKey(object)`
|
||||
|
||||
Returns 'true' if the value is an instance of `<JWK.Key>`.
|
||||
|
||||
- `object`: `<any>`
|
||||
- Returns: `<boolean>`
|
||||
|
||||
---
|
||||
|
||||
## JWKS (JSON Web Key Set)
|
||||
|
||||
<!-- TOC JWKS START -->
|
||||
- [Class: <JWKS.KeyStore>](#class-jwkskeystore)
|
||||
- [new JWKS.KeyStore([keys])](#new-jwkskeystorekeys)
|
||||
- [keystore.size](#keystoresize)
|
||||
- [keystore.all([parameters])](#keystoreallparameters)
|
||||
- [keystore.get([parameters])](#keystoregetparameters)
|
||||
- [keystore.add(key)](#keystoreaddkey)
|
||||
- [keystore.remove(key)](#keystoreremovekey)
|
||||
- [keystore.generate(...)](#keystoregenerate)
|
||||
- [keystore.generateSync(...)](#keystoregeneratesync)
|
||||
- [keystore.toJWKS([private])](#keystoretojwksprivate)
|
||||
- [JWKS.KeyStore.fromJWKS(jwks)](#jwkskeystorefromjwksjwks)
|
||||
<!-- TOC JWKS END -->
|
||||
|
||||
```js
|
||||
const { JWKS } = require('@panva/jose')
|
||||
// { KeyStore: [Function: KeyStore] }
|
||||
```
|
||||
|
||||
#### Class: `<JWKS.KeyStore>`
|
||||
|
||||
`JWKS.KeyStore` is an abstraction representing a set of JWKs, a keystore instance may be queried for
|
||||
keys matching specific parameters. Keystores may be instantiated either populated, or empty and there
|
||||
are lifecycle `keystore.remove()` and `keystore.add()` methods for adding/removing keys from an existing
|
||||
store.
|
||||
|
||||
---
|
||||
|
||||
#### `new JWKS.KeyStore([keys])`
|
||||
|
||||
Creates a new KeyStore, either empty or populated.
|
||||
|
||||
- `keys`: `<JWK.Key[]>` Array of key keys instantiated by `JWK.importKey()`
|
||||
- Returns: `<JWKS.KeyStore>`
|
||||
|
||||
---
|
||||
|
||||
#### `keystore.size`
|
||||
|
||||
Returns the number of keys in the keystore.
|
||||
|
||||
- `<number>`
|
||||
---
|
||||
|
||||
#### `keystore.all([parameters])`
|
||||
|
||||
Retrieves an array of keys matching the provider parameters, returns all if none are provided. The
|
||||
returned array is sorted by relevance based on the parameters. Keys with the exact algorithm or use
|
||||
specified by the parameters are first.
|
||||
|
||||
- `parameters`: `<Object>`
|
||||
- `kty`: `<string>` Key Type to filter for.
|
||||
- `alg`: `<string>` Key supported algorithm to filter for.
|
||||
- `use`: `<string>` Key use to filter for.
|
||||
- `kid`: `<string>` Key ID to filter for.
|
||||
- Returns: `<Key[]>` Array of key instances or an empty array when none are matching the parameters.
|
||||
|
||||
---
|
||||
|
||||
#### `keystore.get([parameters])`
|
||||
|
||||
Retrieves a single key matching the provider parameters. The most relevant Key based on the
|
||||
parameters is returned.
|
||||
|
||||
- `parameters`: `<Object>`
|
||||
- `kty`: `<string>` Key Type to filter for.
|
||||
- `alg`: `<string>` Key supported algorithm to filter for.
|
||||
- `use`: `<string>` Key use to filter for.
|
||||
- `kid`: `<string>` Key ID to filter for.
|
||||
- Returns: `<JWK.RSAKey>` | `<JWK.ECKey>` | `<JWK.OctKey>` | `<undefined>`
|
||||
|
||||
---
|
||||
|
||||
#### `keystore.add(key)`
|
||||
|
||||
Adds a key instance to the store unless it is already included.
|
||||
|
||||
- `key`: `<JWK.RSAKey>` | `<JWK.ECKey>` | `<JWK.OctKey>`
|
||||
|
||||
---
|
||||
|
||||
#### `keystore.remove(key)`
|
||||
|
||||
Ensures a key is removed from a store.
|
||||
|
||||
- `key`: `<JWK.RSAKey>` | `<JWK.ECKey>` | `<JWK.OctKey>`
|
||||
|
||||
---
|
||||
|
||||
#### `keystore.generate(...)`
|
||||
|
||||
Asynchronously generates new random key and automatically adds it to the store. See `JWK.generate()` for the API.
|
||||
|
||||
---
|
||||
|
||||
#### `keystore.generateSync(...)`
|
||||
|
||||
Synchronous version of `keystore.generate()`.
|
||||
|
||||
---
|
||||
|
||||
#### `keystore.toJWKS([private])`
|
||||
|
||||
Exports the keystore to a JSON Web Key Set formatted object.
|
||||
|
||||
- `private`: `<boolean>` When true exports keys with their private components. **Default:** 'false'
|
||||
- Returns: `<Object>`
|
||||
|
||||
---
|
||||
|
||||
#### `JWKS.KeyStore.fromJWKS(jwks)`
|
||||
|
||||
Creates a new KeyStore from a JSON Web Key Set.
|
||||
|
||||
- `jwks`: `<Object>` JWKS formatted object (`{ keys: [{ kty: '...', ... }, ...] }`)
|
||||
- Returns: `<JWKS.KeyStore>`
|
||||
|
||||
<details>
|
||||
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
|
||||
|
||||
```js
|
||||
const { JWKS: { KeyStore } } = require('@panva/jose')
|
||||
const jwks = { keys:
|
||||
[ { kty: 'RSA',
|
||||
kid: 'gqUcZ2TjhmNrVOd1d27tedkabhOTs9WghMHIyjIBn7Y',
|
||||
e: 'AQAB',
|
||||
n:
|
||||
'vi1Aui6R0rUL_7pdcFKKMhBF25h4x8WiTZ4w66eNZhwIp48lz-vBuyUUrSR-RwcuvnxlXdjBdSaN-PZkNRDv2bXE3mVtjZgoYyzQlGLJ1wduQaBXIkrQWxc7yzL91MvtP1kWwFHHrQHZRlpiFQQm9gNCy2wXCTbWGT9kjrR1W1bkwhmOKK4rF-hMgaCNDrtEQ6xWknxV8aXW4itouJ0pJv8xplc6J14f_SNq6arVUcAZ26EzJYC2fcvqwsrnKzvW7QxQGQzh-u9Tn82Tl14Omh1KDV8C7Vb_m8XClv_9zOrKBGdaTl1zgINyMEaa_IMophnBgK_kAXvtVvEThQ93GQ',
|
||||
use: 'enc' } ] }
|
||||
const ks = KeyStore.fromJWKS(jwks)
|
||||
// KeyStore {}
|
||||
ks.size
|
||||
// 1
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## JWS (JSON Web Signature)
|
||||
|
||||
<!-- TOC JWS START -->
|
||||
- [Class: <JWS.Sign>](#class-jwssign)
|
||||
- [new JWS.Sign(payload)](#new-jwssignpayload)
|
||||
- [sign.recipient(key[, protected[, header]])](#signrecipientkey-protected-header)
|
||||
- [sign.sign(serialization)](#signsignserialization)
|
||||
- [JWS.sign(payload, key[, protected])](#jwssignpayload-key-protected)
|
||||
- [JWS.sign.flattened(payload, key[, protected[, header]])](#jwssignflattenedpayload-key-protected-header)
|
||||
- [JWS.verify(jws, keyOrStore[, options])](#jwsverifyjws-keyorstore-options)
|
||||
<!-- TOC JWS END -->
|
||||
|
||||
The `<JWS>` module provides methods required to sign or verify JSON Web Signatures in either one of
|
||||
the defined serializations.
|
||||
|
||||
```js
|
||||
const { JWS } = require('@panva/jose')
|
||||
// { Sign: [Function: Sign],
|
||||
// sign:
|
||||
// { [Function: bound single]
|
||||
// flattened: [Function: bound single] },
|
||||
// verify: [Function: bound jwsVerify] }
|
||||
```
|
||||
|
||||
#### Class: `<JWS.Sign>`
|
||||
|
||||
`<JWS.Sign>` is the class used when you need to produce a JWS for multiple recipients (with multiple
|
||||
signatures of the same payload) using the General JWS JSON Serialization Syntax.
|
||||
|
||||
<details>
|
||||
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
|
||||
|
||||
```js
|
||||
const { JWK, JWS } = require('@panva/jose')
|
||||
|
||||
const key = JWK.importKey({
|
||||
kty: 'oct',
|
||||
k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg'
|
||||
})
|
||||
const key2 = JWK.importKey({
|
||||
kty: 'oct',
|
||||
k: 'AAPapAv4LbFbiVawEjagUBluYqN5rhna-8nuldDvOx8'
|
||||
})
|
||||
|
||||
const payload = {
|
||||
sub: 'John Doe'
|
||||
}
|
||||
|
||||
const sig = new JWS.Sign(payload)
|
||||
sig.recipient(key, { alg: 'HS256' }, { foo: 'bar' })
|
||||
sig.recipient(key2, { alg: 'HS512' }, { foo: 'baz' })
|
||||
sig.sign('general')
|
||||
// { payload: 'eyJzdWIiOiJKb2huIERvZSJ9',
|
||||
// signatures:
|
||||
// [ { protected: 'eyJhbGciOiJIUzI1NiJ9',
|
||||
// header: { foo: 'bar' },
|
||||
// signature: 'mnBcKK-9setCco03NtYws-RMlYXP3LGlDu2RUB7vetQ' },
|
||||
// { protected: 'eyJhbGciOiJIUzUxMiJ9',
|
||||
// header: { foo: 'baz' },
|
||||
// signature:
|
||||
// 'R7e5ZUkgiZQLh8JagoCbwAY21e9A-Y0rhUGQkhihLOvIU8JG2AyZ9zROOUICaUucf8NQKc2dEaIKdRCXy-fDdQ' } ] }
|
||||
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
#### `new JWS.Sign(payload)`
|
||||
|
||||
Creates a new Sign object for the provided payload, intended for one or more recipients.
|
||||
|
||||
- `payload`: `<Object>` | `<string>` | `<Buffer>` The payload that will be signed. When `<Object>` it
|
||||
will be automatically serialized to JSON before signing
|
||||
- Returns: `<JWS.Sign>`
|
||||
|
||||
---
|
||||
|
||||
#### `sign.recipient(key[, protected[, header]])`
|
||||
|
||||
Adds a recipient to the JWS, the Algorithm that will be used to sign with is either provided as part
|
||||
of the Protected or Unprotected Header or inferred from the provided `<JWK.Key>` instance.
|
||||
|
||||
- `key`: `<JWK.Key>` The key to sign with.
|
||||
- `protected`: `<Object>` Protected Header for this recipient
|
||||
- `header`: `<Object>` Unprotected Header for this recipient
|
||||
|
||||
---
|
||||
|
||||
#### `sign.sign(serialization)`
|
||||
|
||||
Performs the signing operations for each registered recipient and returns the final JWS representation
|
||||
in the serialization requested. The JWS is validated for conformance during this step. Please note
|
||||
that only 'general' and 'flattened' serialization supports Unprotected Per-Recipient Header and only
|
||||
the 'general' serialization supports multiple recipients. See `<JWS.sign>` and `<JWS.sign.flattened>`
|
||||
for shorthand methods to sign for a single recipient.
|
||||
|
||||
- `serialization`: `<string>` JWS Serialization. Must be one of 'general', 'flattened', 'compact'
|
||||
- Returns: `<string>` | `<Object>`
|
||||
|
||||
---
|
||||
|
||||
#### `JWS.sign(payload, key[, protected])`
|
||||
|
||||
Performs the signing operation and 'compact' JWS serialization of the result. The Algorithm that
|
||||
will be used to sign with is either provided as part of the Protected Header or inferred from the
|
||||
provided `<JWK.Key>` instance.
|
||||
|
||||
- `payload`: `<Object>` | `<string>` | `<Buffer>` The payload that will be signed. When `<Object>` it
|
||||
will be automatically serialized to JSON before signing
|
||||
- `key`: `<JWK.Key>` The key to sign with.
|
||||
- `protected`: `<Object>` Protected Header
|
||||
- Returns: `<string>`
|
||||
|
||||
<details>
|
||||
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
|
||||
|
||||
```js
|
||||
const { JWK, JWS } = require('@panva/jose')
|
||||
|
||||
const key = JWK.importKey({
|
||||
kty: 'oct',
|
||||
k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg'
|
||||
})
|
||||
|
||||
const payload = {
|
||||
sub: 'John Doe'
|
||||
}
|
||||
JWS.sign(payload, key, { alg: 'HS256' })
|
||||
// eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2huIERvZSJ9.mnBcKK-9setCco03NtYws-RMlYXP3LGlDu2RUB7vetQ
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
#### `JWS.sign.flattened(payload, key[, protected[, header]])`
|
||||
|
||||
Performs the signing operation and 'flattened' JWS serialization of the result. The Algorithm that
|
||||
will be used to sign with is either provided as part of the Protected or Unprotected Header or inferred from the
|
||||
provided `<JWK.Key>` instance.
|
||||
|
||||
- `payload`: `<Object>` | `<string>` | `<Buffer>` The payload that will be signed. When `<Object>` it
|
||||
will be automatically serialized to JSON before signing
|
||||
- `key`: `<JWK.Key>` The key to sign with.
|
||||
- `protected`: `<Object>` Protected Header
|
||||
- `header`: `<Object>` Unprotected Header
|
||||
- Returns: `<Object>`
|
||||
|
||||
<details>
|
||||
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
|
||||
|
||||
```js
|
||||
const { JWK, JWS } = require('@panva/jose')
|
||||
|
||||
const key = JWK.importKey({
|
||||
kty: 'oct',
|
||||
k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg'
|
||||
})
|
||||
|
||||
const payload = {
|
||||
sub: 'John Doe'
|
||||
}
|
||||
|
||||
JWS.sign.flattened(payload, key)
|
||||
// { payload: 'eyJzdWIiOiJKb2huIERvZSJ9',
|
||||
// protected: 'eyJhbGciOiJIUzI1NiJ9',
|
||||
// signature: 'mnBcKK-9setCco03NtYws-RMlYXP3LGlDu2RUB7vetQ' }
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
#### `JWS.verify(jws, keyOrStore[, options])`
|
||||
|
||||
Verifies the provided JWS in either serialization with a given `<JWK.Key>` or `<JWKS.KeyStore>`
|
||||
|
||||
- `jws`: `<Object>` | `<string>` The JWS to verify. This must be a valid JWS.
|
||||
- `keyOrStore`: `<JWK.Key>` | `<JWKS.KeyStore>` The key or store to verify with. When `<JWKS.KeyStore>`
|
||||
instance is provided a selection of possible candidate keys will be done and the operation will
|
||||
succeed if just one key or signature (in case of General JWS JSON Serialization Syntax) matches.
|
||||
- `options`: `<Object>`
|
||||
- `algorithms`: `string[]` Array of Algorithms to accept, when the signature does not use an
|
||||
algorithm from this list the verification will fail. **Default:** 'undefined' - accepts all
|
||||
algorithms available on the keys
|
||||
- `complete`: `<boolean>` When true returns a complete object with the parsed headers and payload
|
||||
instead of just the verified payload. **Default:** 'false'
|
||||
- `crit`: `string[]` Array of Critical Header Parameter names to recognize. **Default:** '[]'
|
||||
- Returns: `<string>` | `<Object>`
|
||||
|
||||
<details>
|
||||
<summary><em><strong>Example</strong></em> (Click to expand)</summary>
|
||||
|
||||
```js
|
||||
const { JWK, JWS, JWKS } = require('@panva/jose')
|
||||
|
||||
const key = JWK.importKey({
|
||||
kty: 'oct',
|
||||
k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg'
|
||||
})
|
||||
const key2 = JWK.importKey({
|
||||
kty: 'oct',
|
||||
k: 'AAPapAv4LbFbiVawEjagUBluYqN5rhna-8nuldDvOx8'
|
||||
})
|
||||
|
||||
const compact = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2huIERvZSJ9.mnBcKK-9setCco03NtYws-RMlYXP3LGlDu2RUB7vetQ'
|
||||
|
||||
const flattened = { payload: 'eyJzdWIiOiJKb2huIERvZSJ9',
|
||||
protected: 'eyJhbGciOiJIUzI1NiJ9',
|
||||
signature: 'mnBcKK-9setCco03NtYws-RMlYXP3LGlDu2RUB7vetQ' }
|
||||
|
||||
const general = { payload: 'eyJzdWIiOiJKb2huIERvZSJ9',
|
||||
signatures:
|
||||
[ { protected: 'eyJhbGciOiJIUzI1NiJ9',
|
||||
header: { foo: 'bar' },
|
||||
signature: 'mnBcKK-9setCco03NtYws-RMlYXP3LGlDu2RUB7vetQ' },
|
||||
{ protected: 'eyJhbGciOiJIUzUxMiJ9',
|
||||
header: { foo: 'baz' },
|
||||
signature:
|
||||
'R7e5ZUkgiZQLh8JagoCbwAY21e9A-Y0rhUGQkhihLOvIU8JG2AyZ9zROOUICaUucf8NQKc2dEaIKdRCXy-fDdQ' } ] }
|
||||
|
||||
JWS.verify(compact, key)
|
||||
// { sub: 'John Doe' }
|
||||
|
||||
JWS.verify(flattened, key2)
|
||||
// JWSVerificationFailed: signature verification failed
|
||||
|
||||
JWS.verify(compact, key, { complete: true })
|
||||
// { payload: { sub: 'John Doe' }, protected: { alg: 'HS256' }, key: OctKey {} }
|
||||
|
||||
JWS.verify(flattened, key, { algorithms: ['PS256'] })
|
||||
// JOSEAlgNotWhitelisted: alg not whitelisted
|
||||
|
||||
JWS.verify(general, key)
|
||||
// { sub: 'John Doe' }
|
||||
JWS.verify(general, key2)
|
||||
// { sub: 'John Doe' }
|
||||
|
||||
JWS.verify(general, key, { complete: true })
|
||||
// { payload: { sub: 'John Doe' },
|
||||
// protected: { alg: 'HS256' },
|
||||
// header: { foo: 'bar' },
|
||||
// key: : OctKey {} } <- key
|
||||
JWS.verify(general, key2, { complete: true })
|
||||
// { payload: { sub: 'John Doe' },
|
||||
// protected: { alg: 'HS512' },
|
||||
// header: { foo: 'baz' },
|
||||
// key: : OctKey {} } <- key2
|
||||
const keystore = new JWKS.KeyStore(key)
|
||||
JWS.verify(general, keystore, { complete: true })
|
||||
// { payload: { sub: 'John Doe' },
|
||||
// protected: { alg: 'HS256' },
|
||||
// header: { foo: 'bar' },
|
||||
// key: : OctKey {} } <- key that matched in the keystore
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## JWE (JSON Web Encryption)
|
||||
|
||||
<!-- TOC JWE START -->
|
||||
- [Class: <JWE.Encrypt>](#class-jweencrypt)
|
||||
- [new JWE.Encrypt(cleartext[, protected[, unprotected[, aad]]])](#new-jweencryptcleartext-protected-unprotected-aad)
|
||||
- [encrypt.recipient(key[, header])](#encryptrecipientkey-header)
|
||||
- [encrypt.encrypt(serialization)](#encryptencryptserialization)
|
||||
- [JWE.encrypt(cleartext, key[, protected])](#jweencryptcleartext-key-protected)
|
||||
- [JWE.encrypt.flattened(cleartext, key[, protected[, header[, aad]]])](#jweencryptflattenedcleartext-key-protected-header-aad)
|
||||
- [JWE.decrypt(jwe, keyOrStore[, options])](#jwedecryptjwe-keyorstore-options)
|
||||
<!-- TOC JWE END -->
|
||||
|
||||
The `<JWE>` module provides methods required to encrypt or decrypt JSON Web Encryptions in either one of
|
||||
the defined serializations.
|
||||
|
||||
```js
|
||||
const { JWE } = require('@panva/jose')
|
||||
// { Encrypt: [Function: Encrypt],
|
||||
// encrypt:
|
||||
// { [Function: bound single]
|
||||
// flattened: [Function: bound single] },
|
||||
// decrypt: [Function: bound jweDecrypt] }
|
||||
```
|
||||
|
||||
#### Class: `<JWE.Encrypt>`
|
||||
|
||||
`<JWE.Encrypt>` is the class used when you need to produce a JWE for multiple recipients using the
|
||||
General JWE JSON Serialization Syntax.
|
||||
|
||||
---
|
||||
|
||||
#### `new JWE.Encrypt(cleartext[, protected[, unprotected[, aad]]])`
|
||||
|
||||
Creates a new Encrypt object for the provided cleartext with optional Protected and Unprotected
|
||||
Headers and Additional Authenticated Data.
|
||||
|
||||
- `cleartext`: `<string>` | `<Buffer>` The cleartext that will be encrypted.
|
||||
- `protected`: `<Object>` JWE Protected Header
|
||||
- `unprotected`: `<Object>` JWE Shared Unprotected Header
|
||||
- `aad`: `<string>` | `<Buffer>` JWE Additional Authenticated Data
|
||||
- Returns: `<JWE.Encrypt>`
|
||||
|
||||
---
|
||||
|
||||
#### `encrypt.recipient(key[, header])`
|
||||
|
||||
Adds a recipient to the JWE, the Algorithm that will be used to wrap or derive the Content Encryption
|
||||
Key (CEK) is either provided as part of the combined JWE Header for the recipient or inferred from
|
||||
the provided `<JWK.Key>` instance.
|
||||
|
||||
- `key`: `<JWK.Key>` The key to use for Key Management or Direct Encryption
|
||||
- `header`: `<Object>` JWE Per-Recipient Unprotected Header
|
||||
|
||||
---
|
||||
|
||||
#### `encrypt.encrypt(serialization)`
|
||||
|
||||
Performs the encryption operations for each registered recipient and returns the final JWE representation
|
||||
in the serialization requested. The JWE is validated for conformance during this step. Please note
|
||||
that only 'general' and 'flattened' serialization supports Unprotected Per-Recipient Header and AAD
|
||||
and only the 'general' serialization supports multiple recipients. See `<JWE.encrypt>` and `<JWE.encrypt.flattened>`
|
||||
for shorthand methods to encrypt for a single recipient.
|
||||
|
||||
- `serialization`: `<string>` JWE Serialization. Must be one of 'general', 'flattened', 'compact'
|
||||
- Returns: `<string>` | `<Object>`
|
||||
|
||||
---
|
||||
|
||||
#### `JWE.encrypt(cleartext, key[, protected])`
|
||||
|
||||
Performs the encryption operation and 'compact' JWE serialization of the result. The Algorithm that
|
||||
will be used to wrap or derive the Content Encryption Key (CEK) is either provided as part of the
|
||||
Protected Header or inferred from the provided `<JWK.Key>` instance.
|
||||
|
||||
- `cleartext`: `<string>` | `<Buffer>` The cleartext that will be encrypted.
|
||||
- `key`: `<JWK.Key>` The key to use for Key Management or Direct Encryption
|
||||
- `protected`: `<Object>` JWE Protected Header
|
||||
- Returns: `<string>`
|
||||
|
||||
---
|
||||
|
||||
#### `JWE.encrypt.flattened(cleartext, key[, protected[, header[, aad]]])`
|
||||
|
||||
Performs the encryption operation and 'flattened' JWE serialization of the result. The Algorithm that
|
||||
will be used to wrap or derive the Content Encryption Key (CEK) is either provided as part of the
|
||||
combined JWE Header or inferred from the provided `<JWK.Key>` instance.
|
||||
|
||||
- `cleartext`: `<string>` | `<Buffer>` The cleartext that will be encrypted.
|
||||
- `key`: `<JWK.Key>` The key to use for Key Management or Direct Encryption
|
||||
- `protected`: `<Object>` JWE Protected Header
|
||||
- `unprotected`: `<Object>` JWE Shared Unprotected Header
|
||||
- `aad`: `<string>` | `<Buffer>` JWE Additional Authenticated Data
|
||||
- Returns: `<Object>`
|
||||
|
||||
---
|
||||
|
||||
#### `JWE.decrypt(jwe, keyOrStore[, options])`
|
||||
|
||||
Verifies the provided JWE in either serialization with a given `<JWK.Key>` or `<JWKS.KeyStore>`
|
||||
|
||||
- `jwe`: `<Object>` | `<string>` The JWE to decrypt. This must be a valid JWE.
|
||||
- `keyOrStore`: `<JWK.Key>` | `<JWKS.KeyStore>` The key or store to decrypt with. When `<JWKS.KeyStore>`
|
||||
instance is provided a selection of possible candidate keys will be done and the operation will
|
||||
succeed if just one key or signature (in case of General JWE JSON Serialization Syntax) matches.
|
||||
- `options`: `<Object>`
|
||||
- `algorithms`: `string[]` Array of Algorithms to accept, when the JWE does not use an
|
||||
Key Management algorithm from this list the decryption will fail. **Default:** 'undefined' -
|
||||
accepts all algorithms available on the keys
|
||||
- `complete`: `<boolean>` When true returns a complete object with the parsed headers, verified AAD
|
||||
and cleartext instead of just the cleartext. **Default:** 'false'
|
||||
- Returns: `<string>` | `<Object>`
|
||||
|
||||
|
||||
[spec-thumbprint]: https://tools.ietf.org/html/rfc7638
|
||||
[support-patreon]: https://www.patreon.com/panva
|
||||
[support-paypal]: https://www.paypal.me/panva
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
{
|
||||
"name": "@panva/jose",
|
||||
"version": "0.0.1",
|
||||
"version": "0.8.0",
|
||||
"description": "JSON Web Almost Everything - JWA, JWS, JWE, JWK, JWKS for Node.js with minimal dependencies",
|
||||
"keywords": [
|
||||
"compact",
|
||||
"decrypt",
|
||||
"encrypt",
|
||||
"flattened",
|
||||
"general",
|
||||
"jose",
|
||||
"jwa",
|
||||
"jwe",
|
||||
|
|
@ -63,6 +66,7 @@
|
|||
}
|
||||
},
|
||||
"nyc": {
|
||||
"all": true,
|
||||
"reporter": [
|
||||
"lcov",
|
||||
"text-summary"
|
||||
|
|
|
|||
Loading…
Reference in a new issue