jose
"JSON Web Almost Everything" - JWA, JWS, JWE, JWT, JWK, JWKS for Node.js with minimal dependencies

New major version is available
v2.x
continues being supported. It will continue receiving bug fixes until 2022-04-30. It will not be receiving any new features.
v3.x
is available with
Revised API
No dependencies
Browser support
Promise-based API
experimental (non-blocking 🎉) Node.js libuv thread pool based runtime
Implemented specs & features
The following specifications are implemented by jose
JSON Web Signature (JWS) - RFC7515
JSON Web Encryption (JWE) - RFC7516
JSON Web Key (JWK) - RFC7517
JSON Web Algorithms (JWA) - RFC7518
JSON Web Token (JWT) - RFC7519
JSON Web Key Thumbprint - RFC7638
JWS Unencoded Payload Option - RFC7797
CFRG Elliptic Curve ECDH and Signatures - RFC8037
secp256k1 EC Key curve support - JOSE Registrations for WebAuthn Algorithms
The test suite utilizes examples defined in RFC7520 to confirm its JOSE implementation is correct.
Available JWT validation profiles
Generic JWT
OIDC ID Token - OpenID Connect Core 1.0
(draft 04) OIDC Logout Token - OpenID Connect Back-Channel Logout 1.0
(draft 06) OAuth 2.0 JWT Access Tokens - JWT Profile for OAuth 2.0 Access Tokens
Support
If you or your business use jose
, please consider becoming a sponsor so I can continue maintaining it and adding new features carefree.
Documentation
Usage
For the best performance Node.js version >=12.0.0 is recommended, but ^10.13.0 lts/dubnium is also supported.
Installing jose
npm install jose@2
Usage
const jose = require('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 jose
} = jose
Keys and KeyStores
Prepare your Keys and KeyStores. See the documentation for more.
const key = jose.JWK.asKey(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.asKey(jwk)
const keystore = new jose.JWKS.KeyStore(key, anotherKey)
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 for more.
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 Verifying
Verify with a public or symmetric key with plethora of convenience options. See the documentation for more.
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 for more.
jose.JWS.sign(
{ sub: 'johndoe' },
privateKey,
{ kid: privateKey.kid }
)
JWS Verifying
Verify with a public or symmetric key. See the documentation for more.
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 for more.
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 for more.
jose.JWE.decrypt(
'eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiRUNESC1FUyIsImVwayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6IkVsUGhsN1ljTVZsWkhHM0daSkRoOVJhemNYYlN2VFNheUF6aTBINFFtRUEiLCJ5IjoiM0hDREJTRy12emd6cGtLWmJqMU05UzVuUEJrTDBBdFM4U29ORUxMWE1SayJ9fQ..FhmidRo0twvFA7jcfKFNJw.o112vgiG_qUL1JR5WHpsErcxxgaK_FAa7vCWJ--WulndLpdwdRXHd9k3aL_k8K67xoAThrt10d7dSY2TlPpHdYkw979u0V-C4TNrpzNkv5jpBjU6hHyKpoGZfEsiTD1ivHaFy3ZLCTS69kN_eVKsZGLVf_dkq6Sz6bWE4-ln_fuwukPyMvjTyaTreLjPLBZW.ocKwptCm4Zn437L5hWFnHg',
privateKey
)
Detailed Support Matrix
JWK Key Types
Supported
kty
value
crv
values
RSA
✓
RSA
Elliptic Curve
✓
EC
P-256, secp256k1[1], P-384, P-521
Octet Key Pair
✓
OKP
Ed25519, Ed448[1], X25519[1], X448[1]
Octet sequence
✓
oct
Compact
✓
✓
✓
✓
General JSON
✓
✓
✓
✓
Flattened JSON
✓
✓
✓
✓
RSASSA-PKCS1-v1_5
✓
RS256, RS384, RS512
RSASSA-PSS
✓
PS256, PS384, PS512
ECDSA
✓
ES256, ES256K[1], ES384, ES512
Edwards-curve DSA
✓
EdDSA
HMAC with SHA-2
✓
HS256, HS384, HS512
Unsecured JWS
✓
none[2]
AES
✓
A128KW[1], A192KW[1], A256KW[1]
AES GCM
✓
A128GCMKW, A192GCMKW, A256GCMKW
Direct Key Agreement
✓
dir
RSAES OAEP
✓
RSA-OAEP, RSA-OAEP-256[3], RSA-OAEP-384[3], RSA-OAEP-512[3]
RSAES-PKCS1-v1_5
✓
RSA1_5
PBES2
✓
PBES2-HS256+A128KW[1], PBES2-HS384+A192KW[1], PBES2-HS512+A256KW[1]
ECDH-ES
✓[4]
ECDH-ES, ECDH-ES+A128KW[1], ECDH-ES+A192KW[1], ECDH-ES+A256KW[1]
AES GCM
✓
A128GCM, A192GCM, A256GCM
AES_CBC_HMAC_SHA2
✓
A128CBC-HS256, A192CBC-HS384, A256CBC-HS512
Legend:
✓ Implemented
✕ Missing node crypto support / won't implement
◯ TBD
1 Not supported in Electron due to Electron's use of BoringSSL
2 Unsecured JWS is supported for the JWS and JWT sign and verify operations but it is an entirely opt-in behaviour, downgrade attacks are prevented by the required use of a special JWK.Key
-like object that cannot be instantiated through the key import API
3 RSAES OAEP using SHA-2 and MGF1 with SHA-2 is only supported when Node.js >=12.9.0
runtime is detected
4 ECDH-ES with X25519 and X448 keys is only supported when Node.js ^12.17.0 || >=13.9.0
runtime is detected
5 Draft specification profiles are updated as minor versions of the library, therefore, since they may have breaking changes use the ~
semver operator when using these and pay close attention to changelog and the drafts themselves.
FAQ
Supported Versions
Semver?
Yes. Everything that's either exported in the TypeScript definitions file or documented is subject to Semantic Versioning 2.0.0. The rest is to be considered private API and is subject to change between any versions.
Although. Draft specification profiles are updated as minor versions of the library, therefore, since they may have breaking changes use the ~
semver operator when using these and pay close attention to changelog and the drafts themselves.
How do I use it outside of Node.js
It is only built for >=10.13.0 Node.js environment - including jose
in transpiled browser-environment targeted projects is not supported and may result in unexpected results.
it supports JWK Key Format for all four key types (oct, RSA, EC and OKP)
it is providing Key and KeyStore abstractions
there is JSON Web Encryption support
it supports all JWS / JWE Serialization Syntaxes
it supports the "crit" member validations to make sure extensions are handled correctly
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
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
, 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.
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 using node-jose
for openid-client
and oidc-provider
and came to realize its shortcomings in terms of performance and API (not having well defined errors).
+ this was an amazing opportunity to learn JOSE as a whole
Last updated