mirror of
https://github.com/danbulant/jose
synced 2026-05-25 13:01:49 +00:00
319 lines
13 KiB
Markdown
319 lines
13 KiB
Markdown
# @panva/jose
|
|
|
|
[![build][travis-image]][travis-url] [![codecov][codecov-image]][codecov-url]
|
|
|
|
"JSON Web Almost Everything" - JWA, JWS, JWE, JWT, JWK, JWKS for Node.js with minimal dependencies
|
|
|
|
## Implemented specs & features
|
|
|
|
The following specifications are implemented by @panva/jose
|
|
|
|
- JSON Web Signature (JWS) - [RFC7515][spec-jws]
|
|
- JSON Web Encryption (JWE) - [RFC7516][spec-jwe]
|
|
- JSON Web Key (JWK) - [RFC7517][spec-jwk]
|
|
- JSON Web Algorithms (JWA) - [RFC7518][spec-jwa]
|
|
- JSON Web Token (JWT) - [RFC7519][spec-jwt]
|
|
- JSON Web Key (JWK) Thumbprint - [RFC7638][spec-thumbprint]
|
|
- JWS Unencoded Payload Option - [RFC7797][spec-b64]
|
|
|
|
The test suite utilizes examples defined in [RFC7520][spec-cookbook] to confirm its JOSE
|
|
implementation is correct.
|
|
|
|
<details>
|
|
<summary><em><strong>Detailed feature matrix</strong></em> (Click to expand)</summary><br>
|
|
|
|
Legend:
|
|
- **✓** Implemented
|
|
- **✕** Missing node crypto support / won't implement
|
|
- **◯** not planned (yet?) / PR / Use-Case first welcome
|
|
|
|
| JWK Key Types | Supported ||
|
|
| -- | -- | -- |
|
|
| RSA | ✓ | RSA |
|
|
| Elliptic Curve | ✓ | EC |
|
|
| Octet sequence | ✓ | oct |
|
|
|
|
| Serialization | JWS Sign | JWS Verify | JWE Encrypt | JWE Decrypt |
|
|
| -- | -- | -- | -- | -- |
|
|
| Compact | ✓ | ✓ | ✓ | ✓ |
|
|
| General JSON | ✓ | ✓ | ✓ | ✓ |
|
|
| Flattened JSON | ✓ | ✓ | ✓ | ✓ |
|
|
|
|
| JWS Algorithms | Supported ||
|
|
| -- | -- | -- |
|
|
| RSASSA-PKCS1-v1_5 | ✓ | RS256, RS384, RS512 |
|
|
| RSASSA-PSS | ✓ | PS256, PS384, PS512 |
|
|
| ECDSA | ✓ | ES256, ES384, ES512 |
|
|
| HMAC with SHA-2 | ✓ | HS256, HS384, HS512 |
|
|
|
|
| JWE Key Management Algorithms | Supported ||
|
|
| -- | -- | -- |
|
|
| AES | ✓ | A128KW, A192KW, A256KW |
|
|
| AES GCM | ✓ | A128GCMKW, A192GCMKW, A256GCMKW |
|
|
| Direct Key Agreement | ✓ | dir |
|
|
| RSAES OAEP | ✓<sup>*</sup> | RSA-OAEP <sub>(<sup>*</sup>RSA-OAEP-256 is not supported due to its lack of support in Node.JS)</sub> |
|
|
| RSAES-PKCS1-v1_5 | ✓ | RSA1_5 |
|
|
| PBES2 | ✓ | PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW |
|
|
| ECDH-ES | ✓ | ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW |
|
|
|
|
| JWE Content Encryption Algorithms | Supported ||
|
|
| -- | -- | -- |
|
|
| AES GCM | ✓ | A128GCM, A192GCM, A256GCM |
|
|
| AES_CBC_HMAC_SHA2 | ✓ | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 |
|
|
|
|
---
|
|
|
|
Pending Node.js Support 🤞:
|
|
- [RFC8037][spec-cfrg] (EdDSA, OKP kty, etc). See [#12](https://github.com/panva/jose/issues/12)
|
|
|
|
Won't implement:
|
|
- ✕ 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>
|
|
|
|
<br>
|
|
|
|
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]
|
|
- [JWT (JSON Web Token)][documentation-jwt]
|
|
- [JWS (JSON Web Signature)][documentation-jws]
|
|
- [JWE (JSON Web Encryption)][documentation-jwe]
|
|
|
|
## Usage
|
|
|
|
⚠️ Minimal Node.js version required is **v11.8.0** ⚠️ The plan is to release v1.0.0 when Node.js
|
|
v12.0.0 releases in April 2019
|
|
|
|
Installing @panva/jose
|
|
|
|
```console
|
|
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)
|
|
JWT, // JSON Web Token (JWT)
|
|
errors // errors utilized by @panva/jose
|
|
} = jose
|
|
```
|
|
|
|
#### Keys and KeyStores
|
|
|
|
Prepare your Keys and KeyStores. See the [documentation][documentation-jwk] for more.
|
|
|
|
```js
|
|
const key = jose.JWK.importKey(fs.readFileSync('path/to/key/file'))
|
|
|
|
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)
|
|
```
|
|
|
|
### JWT vs JWS
|
|
|
|
The JWT module provides IANA registered claim type and format validations on top of JWS as well as
|
|
convenience options for verifying UNIX timestamps, setting maximum allowed JWT age, verifying
|
|
audiences, and more.
|
|
|
|
The JWS module on the other hand handles the other JWS Serialization Syntaxes with all their
|
|
additional available features and allows signing of any payload, i.e. not just serialized JSON
|
|
objects.
|
|
|
|
#### JWT Signing
|
|
|
|
Sign with a private or symmetric key with plethora of convenience options. See the
|
|
[documentation][documentation-jwt] for more.
|
|
|
|
```js
|
|
jose.JWT.sign(
|
|
{ 'urn:example:claim': 'foo' },
|
|
privateKey,
|
|
{
|
|
algorithm: 'PS256',
|
|
audience: 'urn:example:client_id',
|
|
expiresIn: '1 hour',
|
|
header: {
|
|
typ: 'JWT'
|
|
},
|
|
issuer: 'https://op.example.com'
|
|
}
|
|
)
|
|
```
|
|
|
|
#### JWT Verification
|
|
|
|
Verify with a public or symmetric key with plethora of convenience options. See the
|
|
[documentation][documentation-jwt] for more.
|
|
|
|
```js
|
|
jose.JWT.verify(
|
|
'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzI1NiIsImtpZCI6IjRQQXBsVkJIN0toS1ZqN0xob0RFM0VVQnNGc0hvaTRhSmxBZGstM3JuME0ifQ.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6ImZvbyIsImF1ZCI6InVybjpleGFtcGxlOmNsaWVudF9pZCIsImlzcyI6Imh0dHBzOi8vb3AuZXhhbXBsZS5jb20iLCJpYXQiOjE1NTEyOTI2MjksImV4cCI6MTU1MTI5NjIyOX0.nE5fgRL8gvlStf_wB4mJ0TSXVmhJRnUVQuZ0ts6a1nWnnk0Rv69bEJ12BoMdpyPrGa_W6dxU4HFj89F4pQwW0kqBK2-TZ_n9lq-iqupj46w_lpKOfPC3clVc7ZmqYF81bEA-nX93cSKqVV-qPNPEFenb8XHKszYhBFu_uiRg9rXj2qXVU7PXGJAGTzhVgVxB-3XDB1bQ_6KiDCwzVPftrHxEYLydRCaHzggDg6sAFUhQqhPguKuE2gs6jVUh_gIL2RXeoLoinx6gZ72rfovaOmud-yzNIUN8Tvo0pqBmx0s_lEhTlfrQCzN7hZNmV1eG0GDDE-S_CfZhPePnVJZoRA',
|
|
publicKey,
|
|
{
|
|
issuer: 'https://op.example.com',
|
|
audience: 'urn:example:client_id',
|
|
algorithms: ['PS256']
|
|
}
|
|
)
|
|
```
|
|
|
|
#### JWS Signing
|
|
|
|
Sign with a private or symmetric key using compact serialization. See the
|
|
[documentation][documentation-jws] for more.
|
|
|
|
```js
|
|
jose.JWS.sign(
|
|
{ sub: 'johndoe' },
|
|
privateKey,
|
|
{ kid: privateKey.kid }
|
|
)
|
|
```
|
|
|
|
#### JWS Verifying
|
|
|
|
Verify with a public or symmetric key. See the [documentation][documentation-jws] for more.
|
|
|
|
```js
|
|
jose.JWS.verify(
|
|
'eyJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJqb2huZG9lIn0.T_SYLQV3A5_kFDDVNuoadoURSEtuSOR-dG2CMmrP-ULK9xbIf2vYeiHOkvTrnqGlWEGBGxYtsP1VkXmNsi1uOw',
|
|
publicKey
|
|
)
|
|
```
|
|
|
|
#### JWE Encrypting
|
|
|
|
Encrypt using the recipient's public key or a shared symmetrical secret. See the
|
|
[documentation][documentation-jwe] for more.
|
|
|
|
```js
|
|
jose.JWE.encrypt(
|
|
'eyJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJqb2huZG9lIn0.T_SYLQV3A5_kFDDVNuoadoURSEtuSOR-dG2CMmrP-ULK9xbIf2vYeiHOkvTrnqGlWEGBGxYtsP1VkXmNsi1uOw',
|
|
publicKey,
|
|
{ kid: publicKey.kid }
|
|
)
|
|
```
|
|
|
|
#### JWE Decrypting
|
|
|
|
Decrypt using the private key or a shared symmetrical secret. See the
|
|
[documentation][documentation-jwe] for more.
|
|
|
|
```js
|
|
jose.JWE.decrypt(
|
|
'eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiRUNESC1FUyIsImVwayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6IkVsUGhsN1ljTVZsWkhHM0daSkRoOVJhemNYYlN2VFNheUF6aTBINFFtRUEiLCJ5IjoiM0hDREJTRy12emd6cGtLWmJqMU05UzVuUEJrTDBBdFM4U29ORUxMWE1SayJ9fQ..FhmidRo0twvFA7jcfKFNJw.o112vgiG_qUL1JR5WHpsErcxxgaK_FAa7vCWJ--WulndLpdwdRXHd9k3aL_k8K67xoAThrt10d7dSY2TlPpHdYkw979u0V-C4TNrpzNkv5jpBjU6hHyKpoGZfEsiTD1ivHaFy3ZLCTS69kN_eVKsZGLVf_dkq6Sz6bWE4-ln_fuwukPyMvjTyaTreLjPLBZW.ocKwptCm4Zn437L5hWFnHg',
|
|
privateKey
|
|
)
|
|
```
|
|
|
|
## FAQ
|
|
|
|
#### Semver?
|
|
|
|
**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.
|
|
|
|
#### How do I use it outside of Node.js
|
|
|
|
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.
|
|
|
|
#### How is it different from [`node-jose`][node-jose]
|
|
|
|
`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.
|
|
|
|
#### How is it different from [`node-jws`](https://github.com/brianloveswords/node-jws) or [`node-jwa`](https://github.com/brianloveswords/node-jwa)?
|
|
|
|
- it is not only validating the signatures, it is making sure the JWE/JWS is syntactically correct,
|
|
e.g. not having duplicated header parameters between protected/unprotected or per-recipient
|
|
headers, it does the "crit" member check to make sure extensions are handled correctly
|
|
- 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
|
|
|
|
#### What is the ultimate goal?
|
|
|
|
- **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
|
|
|
|
#### Why? Just, why?
|
|
|
|
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.
|
|
|
|
+ this was an amazing opportunity to learn JOSE as a whole
|
|
|
|
[ask]: https://github.com/panva/jose/issues/new?labels=question&template=question.md&title=question%3A+
|
|
[bug]: https://github.com/panva/jose/issues/new?labels=bug&template=bug-report.md&title=bug%3A+
|
|
[codecov-image]: https://img.shields.io/codecov/c/github/panva/jose/master.svg
|
|
[codecov-url]: https://codecov.io/gh/panva/jose
|
|
[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-jws]: https://github.com/panva/jose/blob/master/docs/README.md#jws-json-web-signature
|
|
[documentation-jwt]: https://github.com/panva/jose/blob/master/docs/README.md#jwt-json-web-token
|
|
[documentation]: https://github.com/panva/jose/blob/master/docs/README.md
|
|
[node-jose]: https://github.com/cisco/node-jose
|
|
[security-vulnerability]: https://github.com/panva/jose/issues/new?template=security-vulnerability.md
|
|
[spec-b64]: https://tools.ietf.org/html/rfc7797
|
|
[spec-cfrg]: https://tools.ietf.org/html/rfc8037
|
|
[spec-cookbook]: https://tools.ietf.org/html/rfc7520
|
|
[spec-jwa]: https://tools.ietf.org/html/rfc7518
|
|
[spec-jwe]: https://tools.ietf.org/html/rfc7516
|
|
[spec-jwk]: https://tools.ietf.org/html/rfc7517
|
|
[spec-jws]: https://tools.ietf.org/html/rfc7515
|
|
[spec-jwt]: https://tools.ietf.org/html/rfc7519
|
|
[spec-thumbprint]: https://tools.ietf.org/html/rfc7638
|
|
[suggest-feature]: https://github.com/panva/jose/issues/new?labels=enhancement&template=feature-request.md&title=proposal%3A+
|
|
[support-patreon]: https://www.patreon.com/panva
|
|
[support-paypal]: https://www.paypal.me/panva
|
|
[travis-image]: https://api.travis-ci.com/panva/jose.svg?branch=master
|
|
[travis-url]: https://travis-ci.com/panva/jose
|