jose

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

Github stars Tracking Chart

jose

"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 jose

The test suite utilizes examples defined in RFC7520 to confirm its JOSE
implementation is correct.

Available JWT validation profiles

Have a question about using jose? - ask.
Found a bug? - report it.
Missing a feature? - If it wasn't already discussed before, ask for it.
Found a vulnerability? - Reach out to us via email first, see security vulnerability disclosure.

If you want to quickly add secure token-based authentication to Node.js projects, feel free to check Auth0’s free plan at auth0.com/overview.

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

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']
  }
)

ID Token Verifying

ID Token is a JWT, but profiled, there are additional requirements to a JWT to be accepted as an
ID Token and it is pretty easy to omit some, use the profile option of JWT.verify or the
JWT.IdToken.verify shorthand to make sure what you're accepting is really an ID Token meant to
your Client. This will then perform all doable validations given the input. See the
documentation for more.

jose.JWT.IdToken.verify(
  'eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJzdWIiOiJmb28iLCJub25jZSI6ImE1MWNjZjA4ZjRiYmIwNmU4ODcxNWRkYzRiYmI0MWQ4IiwiYXVkIjoidXJuOmV4YW1wbGU6Y2xpZW50X2lkIiwiZXhwIjoxNTYzODg4ODMwLCJpYXQiOjE1NjM4ODUyMzAsImlzcyI6Imh0dHBzOi8vb3AuZXhhbXBsZS5jb20ifQ.RKCZczgICF5G9XdNDSwe4dolGauQHptpFKPzahA2wYGG2HKrKhyC8ZzqpeVc8cbntuqFBgABJVv6_9YICRx_dgwPYydTpZfZYjHnxrdWF9QsIPEGs672mrnhqIXUnXoseZ0TF6GOq6P7Qbf6gk1ru7TAbr_ieyJnNWcJhh5iHpz1k3mFz0TyTh7UNXshtQXftPUipqz4OBni5r9UaZXHw8B3QYOnms8__GJ3owOxaqkr1jgRs_EWqMlBNjPaj7ElVaeBWljDKuoK673tH0heSpgzUmUX_W8IDUVqs33uglpZwAQC7cAA5mGEg2odcRpvpP5M-WaP4RE9dl9jzcYmrw',
  keyOrStore,
  {
    issuer: 'https://op.example.com',
    audience: 'urn:example:client_id',
    nonce: 'a51ccf08f4bbb06e88715ddc4bbb41d8',
    algorithms: ['PS256']
  }
)

Note: Depending on the channel you receive an ID Token from the following claims may be required
and must also be checked: at_hash, c_hash or s_hash. Use e.g. oidc-token-hash
to validate those hashes after getting the ID Token payload and signature validated by jose

JWT Access Token Verifying

When accepting a JWT-formatted OAuth 2.0 Access Token there are additional requirements for the JWT
to be accepted as an Access Token according to the specification
and it is pretty easy to omit some. Use the profile option of JWT.verify or the
JWT.AccessToken.verify shorthand to make sure what you're accepting is really a JWT Access Token
meant for your Resource Server. This will then perform all doable validations given the input. See
the documentation for more.

jose.JWT.AccessToken.verify(
  'eyJhbGciOiJQUzI1NiIsInR5cCI6ImF0K0pXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJzdWIiOiJmb28iLCJjbGllbnRfaWQiOiJ1cm46ZXhhbXBsZTpjbGllbnRfaWQiLCJhdWQiOiJ1cm46ZXhhbXBsZTpyZXNvdXJjZS1zZXJ2ZXIiLCJleHAiOjE1NjM4ODg4MzAsImlzcyI6Imh0dHBzOi8vb3AuZXhhbXBsZS5jb20iLCJzY29wZSI6ImFwaTpyZWFkIn0.UYy8vEGWS0cS24giCYobMMy9-bqI45p807yV1l-2WXX2J4UO-eohV_R58LE2oM88gl414c6XydO6QSYXul5roNPoOs41jpEvreQIP-HmegjbWGutktWJKfvoOblE5FjYwjrwStjLQGUzkq6KWcnDLPGmpFy7n6gZ4LF8YVz4dLEaO335hMNVNrmSPSXYqr7bAWybnLVpLxjDYwNfCO1g0_TlFx8fHh2OftHoOOmJFltFwb8JypkSB-JXVVSEh43IOEjeeMJIG_ylWIOxfLLi5Q7vPWgub83ZTkuGNe4KmlQJKIsH5k0yZSshsLYUOOH0RiXqQ-SA4Ubh3Fowigdu-g',
  keyOrStore,
  {
    issuer: 'https://op.example.com',
    audience: 'urn:example:resource-server',
    algorithms: ['PS256']
  }
)

Logout Token Verifying

Logout Token is a JWT, but profiled, there are additional requirements to a JWT to be accepted as an
Logout Token and it is pretty easy to omit some, use the profile option of JWT.verify or the
JWT.LogoutToken.verify to make sure what you're accepting is really an Logout Token meant to your
Client. This will then perform all doable validations given the input. See the
documentation for more.

jose.JWT.LogoutToken.verify(
  'eyJhbGciOiJQUzI1NiJ9.eyJzdWIiOiJmb28iLCJhdWQiOiJ1cm46ZXhhbXBsZTpjbGllbnRfaWQiLCJpYXQiOjE1NjM4ODg4MzAsImp0aSI6ImhqazMyN2RzYSIsImlzcyI6Imh0dHBzOi8vb3AuZXhhbXBsZS5jb20iLCJldmVudHMiOnsiaHR0cDovL3NjaGVtYXMub3BlbmlkLm5ldC9ldmVudC9iYWNrY2hhbm5lbC1sb2dvdXQiOnt9fX0.SBi7uNUvjHL9TFoFzautGgTQ1MjyeGUNYHL7inpgq3XgTv6xc9EAKuPRtpixmhdNhmInGwUvAeqDSJxomwv1KK1cTndrC9zAMZ7h657BGQAwGhu7nTm41fWMpKQdiLa9sqp3yit5_FNBmqUNeOoMPrYT_Vl9ytsoNO89MUQy2aqCd-Z7BrNJZH0QycdW6dmYlrmZL7w3t3TaAXoJDJ4Hgl2Itkkkb6_6gO-VoPIdVD8sDuf1zQzGhIkmcFrk0fXczVYOkeF2hNYBuvsM8LuO-EPA3oyE2In9djai3M7yceTQetRa1vwlqWkg_xmYS59ry-6wT44aN7-Y6p0TdXm-Zg',
  keyOrStore,
  {
    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, 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, ES256K[1], ES384, ES512, Edwards-curve DSA, ✓, EdDSA, HMAC with SHA-2, ✓, HS256, HS384, HS512, Unsecured JWS, ✓, none[2], JWE Key Management Algorithms, Supported, --, --, --, AES, ✓, A128KW[1], A192KW[1], A256KW[1], AES GCM, ✓, A128GCMKW, A192GCMKW, A256GCMKW, Direct Key Agreement, ✓, dir, RSAES OAEP, ✓, RSA-OAEP, RSA-OAEP-256[3], RSAES-PKCS1-v1_5, ✓, RSA1_5, PBES2, ✓, PBES2-HS256+A128KW[1], PBES2-HS384+A192KW[1], PBES2-HS512+A256KW[1], ECDH-ES (for all EC keys), ✓, ECDH-ES, ECDH-ES+A128KW[1], ECDH-ES+A192KW[1], ECDH-ES+A256KW[1], ECDH-ES (for OKP X25519), ✓ via plugin, ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW, ECDH-ES (for OKP X448), ✕, (X)ChaCha, ✓ via plugin, C20PKW, XC20PKW, ECDH-ES+C20PKW, ECDH-ES+XC20PKW, JWE Content Encryption Algorithms, Supported, --, --, --, AES GCM, ✓, A128GCM, A192GCM, A256GCM, AES_CBC_HMAC_SHA2, ✓, A128CBC-HS256, A192CBC-HS384, A256CBC-HS512, (X)ChaCha, ✓ via plugin, C20P, XC20P, JWT profile validation, Supported, profile option value, --, --, --, ID Token - OpenID Connect Core 1.0, ✓, id_token, JWT Access Tokens JWT Profile for OAuth 2.0 Access Tokens, ✓, at+JWT, Logout Token - OpenID Connect Back-Channel Logout 1.0, ✓, logout_token, JARM - JWT Secured Authorization Response Mode for OAuth 2.0, ◯, 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 RSA-OAEP-256 is only supported when Node.js >= 12.9.0 runtime is detected

FAQ

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.

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.

How is it different from jws, jwa or jsonwebtoken?

  • 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 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

Overview

Name With Ownerpanva/jose
Primary LanguageTypeScript
Program languageJavaScript (Language Count: 3)
Platform
License:MIT License
Release Count212
Last Release Namev5.2.4 (Posted on 2024-04-07 09:35:27)
First Release Namev0.9.0 (Posted on )
Created At2018-11-06 08:46:01
Pushed At2024-05-02 07:17:39
Last Commit At
Stargazers Count4.8k
Watchers Count37
Fork Count295
Commits Count1.4k
Has Issues Enabled
Issues Count137
Issue Open Count0
Pull Requests Count47
Pull Requests Open Count0
Pull Requests Close Count22
Has Wiki Enabled
Is Archived
Is Fork
Is Locked
Is Mirror
Is Private
To the top