|  |  | # fast-jwt
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | [](https://npm.im/fast-jwt)
 | 
						
						
						
							|  |  | [](https://github.com/nearform/fast-jwt/actions/workflows/ci.yml)
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | <!-- [](https://codecov.io/gh/nearform/fast-jwt) -->
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Fast JSON Web Token implementation.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ## Installation
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Just run:
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ```bash
 | 
						
						
						
							|  |  | npm install fast-jwt
 | 
						
						
						
							|  |  | ```
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ## Usage
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ### createSigner
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Create a signer function by calling `createSigner` and providing one or more of the following options:
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `key`: A string or a buffer containing the secret for `HS*` algorithms or the PEM encoded private key for `RS*`, `PS*`, `ES*` and `EdDSA` algorithms. If the `key` is a passphrase protected private key it must be an object (more details below). The key can also be a function accepting a Node style callback or a function returning a promise. This is the only mandatory option, which MUST NOT be provided if the token algorithm is `none`.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `algorithm`: The algorithm to use to sign the token. The default value is autodetected from the key, using `RS256` for RSA private keys, `HS256` for plain secrets and the corresponding `ES` or `EdDSA` algorithms for EC or Ed\* private keys.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `mutatePayload`: If set to `true`, the original payload will be modified in place (via `Object.assign`) by the signing function. This is useful if you need a raw reference to the payload after claims have been applied to it but before it has been encoded into a token. Default is `false`.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `expiresIn`: Time span (in milliseconds) after which the token expires, added as the `exp` claim in the payload as defined by the [section 4.1.4 of RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4). This will override any existing value in the claim.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `notBefore`: Time span (in milliseconds) before the token is active, added as the `nbf` claim in the payload as defined by the [section 4.1.5 of RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5). This will override any existing value in the claim.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `jti`: The token unique identifier, added as the `jti` claim in the payload as defined by the [section 4.1.7 of RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.7). This will override any existing value in the claim.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `aud`: The token audience, added as the `aud` claim in the payload as defined by the [section 4.1.3 of RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3). This claim identifies the recipients that the token is intended for. It must be a string or an array of strings. This will override any existing value in the claim.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `iss`: The token issuer, added as the `iss` claim in the payload as defined by the [section 4.1.1 of RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1). It must be a string. This will override any existing value in the claim.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `sub`: The token subject, added as the `sub` claim in the payload as defined by the [section 4.1.2 of RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2). It must be a string. This will override any existing value in the claim.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `nonce`: The token nonce, added as the `nonce` claim in the payload. The `nonce` value is used to associate a Client session with an ID Token. Note that this is a [IANA JSON Web Token Claims Registry](https://www.iana.org/assignments/jwt/jwt.xhtml#claims) public claim registered by OpenID Connect (OIDC). It must be a string. This will override any existing value in the claim.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `kid`: The token key id, added as the `kid` claim in the header section (see [section 4.1.4 of RFC 7515](https://www.rfc-editor.org/rfc/rfc7515#section-4.1.4) and [section 4.5 of RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517#section-4.5)). It must be a string.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `header`: Additional claims to add to the header section. This will override the `typ` and `kid` claims.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `noTimestamp`: If set to `true`, the `iat` claim should not be added to the token. Default is `false`.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `clockTimestamp`: The timestamp in milliseconds (like the output of `Date.now()`) that should be used as the current time for all necessary time comparisons. Default is the system time.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | The signer is a function which accepts a payload and returns the token.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | The payload must be an object.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | If the `key` option is a function, the signer will also accept a Node style callback and will return a promise, supporting therefore both callback and async/await styles.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | If the `key` is a passphrase protected private key, the `algorithm` option must be provided and must be either a `RS*` or `ES*` encoded key and the `key` option must be an object with the following structure:
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ```js
 | 
						
						
						
							|  |  | {
 | 
						
						
						
							|  |  |   key: '<YOUR_RSA_ENCRYPTED_PRIVATE_KEY>',
 | 
						
						
						
							|  |  |   passphrase: '<PASSPHRASE_THAT_WAS_USED_TO_ENCRYPT_THE_PRIVATE_KEY>'
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | ```
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #### Example
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ```javascript
 | 
						
						
						
							|  |  | const { createSigner } = require('fast-jwt')
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // Sync style
 | 
						
						
						
							|  |  | const signSync = createSigner({ key: 'secret' })
 | 
						
						
						
							|  |  | const token = signSync({ a: 1, b: 2, c: 3 })
 | 
						
						
						
							|  |  | // => eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJiIjoyLCJjIjozLCJpYXQiOjE1Nzk1MjEyMTJ9.mIcxteEVjbh2MnKQ3EQlojZojGSyA_guqRBYHQURcfnCSSBTT2OShF8lo9_ogjAv-5oECgmCur_cDWB7x3X53g
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // Callback style
 | 
						
						
						
							|  |  | const signWithCallback = createSigner({ key: (callback) => callback(null, 'secret') })
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | signWithCallback({ a: 1, b: 2, c: 3 }, (err, token) => {
 | 
						
						
						
							|  |  |   // token === eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJiIjoyLCJjIjozLCJpYXQiOjE1Nzk1MjEyMTJ9.mIcxteEVjbh2MnKQ3EQlojZojGSyA_guqRBYHQURcfnCSSBTT2OShF8lo9_ogjAv-5oECgmCur_cDWB7x3X53g
 | 
						
						
						
							|  |  | })
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // Promise style - Note that the key function style and the signer function style are unrelated
 | 
						
						
						
							|  |  | async function test() {
 | 
						
						
						
							|  |  |   const signWithPromise = createSigner({ key: async () => 'secret' })
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |   const token = await signWithPromise({ a: 1, b: 2, c: 3 })
 | 
						
						
						
							|  |  |   // => eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJiIjoyLCJjIjozLCJpYXQiOjE1Nzk1MjEyMTJ9.mIcxteEVjbh2MnKQ3EQlojZojGSyA_guqRBYHQURcfnCSSBTT2OShF8lo9_ogjAv-5oECgmCur_cDWB7x3X53g
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // Using password protected private key - in this case you MUST provide the algorithm as well
 | 
						
						
						
							|  |  | const signSync = createSigner({
 | 
						
						
						
							|  |  |   algorithm: '<ANY_RS*_OR_ES*_ALGORITHM>',
 | 
						
						
						
							|  |  |   key: {
 | 
						
						
						
							|  |  |     key: '<YOUR_RSA_ENCRYPTED_PRIVATE_KEY>',
 | 
						
						
						
							|  |  |     passphrase: '<PASSPHRASE_THAT_WAS_USED_TO_ENCRYPT_THE_PRIVATE_KEY>'
 | 
						
						
						
							|  |  |   })
 | 
						
						
						
							|  |  | const token = signSync({ a: 1, b: 2, c: 3 })
 | 
						
						
						
							|  |  | ```
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ### createDecoder
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Create a decoder function by calling `createDecoder` and providing one or more of the following options:
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `complete`: Return an object with the decoded header, payload, signature and input (the token part before the signature), instead of just the content of the payload. Default is `false`.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `checkTyp`: When validating the decoded header, setting this option forces the check of the `typ` property against this value. Example: `checkTyp: 'JWT'`. Default is `undefined`.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | The decoder is a function which accepts a token (as Buffer or string) and returns the payload or the sections of the token.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #### Examples
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ```javascript
 | 
						
						
						
							|  |  | const { createDecoder } = require('fast-jwt')
 | 
						
						
						
							|  |  | const token =
 | 
						
						
						
							|  |  |   'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJiIjoyLCJjIjozLCJpYXQiOjE1Nzk1MjEyMTJ9.mIcxteEVjbh2MnKQ3EQlojZojGSyA_guqRBYHQURcfnCSSBTT2OShF8lo9_ogjAv-5oECgmCur_cDWB7x3X53g'
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // Standard decoder
 | 
						
						
						
							|  |  | const decode = createDecoder()
 | 
						
						
						
							|  |  | const payload = decode(token)
 | 
						
						
						
							|  |  | // => { a: 1, b: 2, c: 3, iat: 1579521212 }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // Complete decoder
 | 
						
						
						
							|  |  | const decodeComplete = createDecoder({ complete: true })
 | 
						
						
						
							|  |  | const sections = decodeComplete(token)
 | 
						
						
						
							|  |  | /* => 
 | 
						
						
						
							|  |  |   { 
 | 
						
						
						
							|  |  |     header: { alg: 'HS512', typ: 'JWT' }, 
 | 
						
						
						
							|  |  |     payload: { a: 1, b: 2, c: 3, iat: 1579521212 },
 | 
						
						
						
							|  |  |     signature: 'mIcxteEVjbh2MnKQ3EQlojZojGSyA/guqRBYHQURcfnCSSBTT2OShF8lo9/ogjAv+5oECgmCur/cDWB7x3X53g==',
 | 
						
						
						
							|  |  |     input: 'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJiIjoyLCJjIjozLCJpYXQiOjE1Nzk1MjEyMTJ9' 
 | 
						
						
						
							|  |  |   }
 | 
						
						
						
							|  |  | */
 | 
						
						
						
							|  |  | ```
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ### createVerifier
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Create a verifier function by calling `createVerifier` and providing one or more of the following options:
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `key`: A string or a buffer containing the secret for `HS*` algorithms or the PEM encoded public key for `RS*`, `PS*`, `ES*` and `EdDSA` algorithms. The key can also be a function accepting a Node style callback or a function returning a promise. This is the only mandatory option, which MUST NOT be provided if the token algorithm is `none`.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `algorithms`: List of strings with the names of the allowed algorithms. By default, all algorithms are accepted.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `complete`: Return an object with the decoded header, payload, signature and input (the token part before the signature), instead of just the content of the payload. Default is `false`.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `cache`: A positive number specifying the size of the verified tokens cache (using LRU strategy). Setting to `true` is equivalent to provide the size `1000`. When enabled, as you can see in the benchmarks section below, performances dramatically improve. By default the cache is disabled.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `cacheTTL`: The maximum time to live of a cache entry (in milliseconds). If the token has a earlier expiration or the verifier has a shorter `maxAge`, the earlier takes precedence. The default is `600000`, which is 10 minutes.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `errorCacheTTL`: A number or function `function (tokenError) => number` that represents the maximum time to live of a cache error entry (in milliseconds). Example: the `key` function fails or does not return a secret or public key. By default **errors are not cached**, the `errorCacheTTL` default value is `-1`.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `allowedJti`: A string, a regular expression, an array of strings or an array of regular expressions containing allowed values for the id claim (`jti`). By default, all values are accepted.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `allowedAud`: A string, a regular expression, an array of strings or an array of regular expressions containing allowed values for the audience claim (`aud`). By default, all values are accepted.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `allowedIss`: A string, a regular expression, an array of strings or an array of regular expressions containing allowed values for the issuer claim (`iss`). By default, all values are accepted.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `allowedSub`: A string, a regular expression, an array of strings or an array of regular expressions containing allowed values for the subject claim (`sub`). By default, all values are accepted.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `allowedNonce`: A string, a regular expression, an array of strings or an array of regular expressions containing allowed values for the nonce claim (`nonce`). By default, all values are accepted.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `requiredClaims`: An array of strings containing which claims should exist in the token. By default, no claim is marked as required.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `ignoreExpiration`: Do not validate the expiration of the token. Default is `false`.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `ignoreNotBefore`: Do not validate the activation of the token. Default is `false`.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `maxAge`: The maximum allowed age (in milliseconds) for tokens to still be valid. By default this is not checked.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `clockTimestamp`: The timestamp in milliseconds (like the output of `Date.now()`) that should be used as the current time for all necessary time comparisons. Default is the system time.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | - `clockTolerance`: Timespan in milliseconds is the tolerance to apply to the current timestamp when performing time comparisons. Default is `0`.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | The verifier is a function which accepts a token (as Buffer or string) and returns the payload or the sections of the token.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | If the `key` option is a function, the signer will also accept a Node style callback and will return a promise, supporting therefore both callback and async/await styles.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | #### Examples
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ```javascript
 | 
						
						
						
							|  |  | const { createVerifier, TOKEN_ERROR_CODES } = require('fast-jwt')
 | 
						
						
						
							|  |  | const token =
 | 
						
						
						
							|  |  |   'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJiIjoyLCJjIjozLCJpYXQiOjE1Nzk1MjEyMTJ9.mIcxteEVjbh2MnKQ3EQlojZojGSyA_guqRBYHQURcfnCSSBTT2OShF8lo9_ogjAv-5oECgmCur_cDWB7x3X53g'
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // Sync style
 | 
						
						
						
							|  |  | const verifySync = createVerifier({ key: 'secret' })
 | 
						
						
						
							|  |  | const payload = verifySync(token)
 | 
						
						
						
							|  |  | // => { a: 1, b: 2, c: 3, iat: 1579521212 }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // Callback style with complete return
 | 
						
						
						
							|  |  | const verifyWithCallback = createVerifier({ key: callback => callback(null, 'secret'), complete: true })
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | verifyWithCallback(token, (err, sections) => {
 | 
						
						
						
							|  |  |   /*
 | 
						
						
						
							|  |  |   sections === {
 | 
						
						
						
							|  |  |     header: { alg: 'HS512', typ: 'JWT' },
 | 
						
						
						
							|  |  |     payload: { a: 1, b: 2, c: 3, iat: 1579521212 },
 | 
						
						
						
							|  |  |     signature: 'mIcxteEVjbh2MnKQ3EQlojZojGSyA/guqRBYHQURcfnCSSBTT2OShF8lo9/ogjAv+5oECgmCur/cDWB7x3X53g==',
 | 
						
						
						
							|  |  |     input: 'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhIjoxLCJiIjoyLCJjIjozLCJpYXQiOjE1Nzk1MjEyMTJ9'
 | 
						
						
						
							|  |  |   }
 | 
						
						
						
							|  |  | */
 | 
						
						
						
							|  |  | })
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // Promise style - Note that the key function style and the verifier function style are unrelated
 | 
						
						
						
							|  |  | async function test() {
 | 
						
						
						
							|  |  |   const verifyWithPromise = createVerifier({ key: async () => 'secret' })
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |   const payload = await verifyWithPromise(token)
 | 
						
						
						
							|  |  |   // => { a: 1, b: 2, c: 3, iat: 1579521212 }
 | 
						
						
						
							|  |  | }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | // custom errorCacheTTL verifier
 | 
						
						
						
							|  |  | const verifier = createVerifier({
 | 
						
						
						
							|  |  |   key: 'secret',
 | 
						
						
						
							|  |  |   cache: true,
 | 
						
						
						
							|  |  |   errorCacheTTL: tokenError => {
 | 
						
						
						
							|  |  |     // customize the ttl based on the error code
 | 
						
						
						
							|  |  |     if (tokenError.code === TOKEN_ERROR_CODES.invalidKey) {
 | 
						
						
						
							|  |  |       return 1000
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  |     return 2000
 | 
						
						
						
							|  |  |   }
 | 
						
						
						
							|  |  | })
 | 
						
						
						
							|  |  | ```
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ## Algorithms supported
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | This is the lisf of currently supported algorithms:
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | | Name    | Description                                                             |
 | 
						
						
						
							|  |  | | ------- | ----------------------------------------------------------------------- |
 | 
						
						
						
							|  |  | | `none`  | Empty algorithm - The token signature section will be empty             |
 | 
						
						
						
							|  |  | | `HS256` | HMAC using SHA-256 hash algorithm                                       |
 | 
						
						
						
							|  |  | | `HS384` | HMAC using SHA-384 hash algorithm                                       |
 | 
						
						
						
							|  |  | | `HS512` | HMAC using SHA-512 hash algorithm                                       |
 | 
						
						
						
							|  |  | | `ES256` | ECDSA using P-256 curve and SHA-256 hash algorithm                      |
 | 
						
						
						
							|  |  | | `ES384` | ECDSA using P-384 curve and SHA-384 hash algorithm                      |
 | 
						
						
						
							|  |  | | `ES512` | ECDSA using P-521 curve and SHA-512 hash algorithm                      |
 | 
						
						
						
							|  |  | | `RS256` | RSASSA-PKCS1-v1_5 using SHA-256 hash algorithm                          |
 | 
						
						
						
							|  |  | | `RS384` | RSASSA-PKCS1-v1_5 using SHA-384 hash algorithm                          |
 | 
						
						
						
							|  |  | | `RS512` | RSASSA-PKCS1-v1_5 using SHA-512 hash algorithm                          |
 | 
						
						
						
							|  |  | | `PS256` | RSASSA-PSS using SHA-256 hash algorithm                                 |
 | 
						
						
						
							|  |  | | `PS384` | RSASSA-PSS using SHA-384 hash algorithm                                 |
 | 
						
						
						
							|  |  | | `PS512` | RSASSA-PSS using SHA-512 hash algorithm                                 |
 | 
						
						
						
							|  |  | | `EdDSA` | EdDSA tokens using Ed25519 or Ed448 keys, only supported on Node.js 12+ |
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ## Caching
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | fast-jwt supports caching of verified tokens.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | The cache layer, powered by [mnemonist](https://www.npmjs.com/package/mnemonist), is a LRU cache which dimension is controlled by the user, as described in the options list.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | When caching is enabled, verified tokens are always stored in cache. If the verification fails once, the error is cached as well for the time set by `errorCacheTTL` and the operation is not retried.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | For verified tokens, caching considers the time sensitive claims of the token (`iat`, `nbf` and `exp`) and make sure the verification is retried after a token becomes valid or after a token becomes expired.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Performances improvements varies by uses cases and by the type of the operation performed and the algorithm used.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | > **_Note:_** Errors are not cached by default, to change this behaviour use the `errorCacheTTL` option.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ## Token Error Codes
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | [Error codes](https://github.com/nearform/fast-jwt/blob/master/src/error.js) exported by `TOKEN_ERROR_CODES`.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ## JWKS
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | JWKS is supported via [get-jwks](https://github.com/nearform/get-jwks). Check out the documentation for integration examples.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ## Benchmarks
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ### Signing
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ```
 | 
						
						
						
							|  |  | ╔══════════════════════════════╤═════════╤═════════════════╤═══════════╤═════════════════════════╗
 | 
						
						
						
							|  |  | ║ Slower tests                 │ Samples │          Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟──────────────────────────────┼─────────┼─────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ HS512 - fast-jwt (async)     │   10000 │ 55766.29 op/sec │  ± 2.85 % │                         ║
 | 
						
						
						
							|  |  | ║ HS512 - jsonwebtoken (async) │   10000 │ 68764.89 op/sec │  ± 1.25 % │ + 23.31 %               ║
 | 
						
						
						
							|  |  | ║ HS512 - jsonwebtoken (sync)  │   10000 │ 70191.14 op/sec │  ± 1.84 % │ + 25.87 %               ║
 | 
						
						
						
							|  |  | ║ HS512 - jose (sync)          │   10000 │ 72844.84 op/sec │  ± 1.72 % │ + 30.63 %               ║
 | 
						
						
						
							|  |  | ╟──────────────────────────────┼─────────┼─────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ Fastest test                 │ Samples │          Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟──────────────────────────────┼─────────┼─────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ HS512 - fast-jwt (sync)      │   10000 │ 97602.16 op/sec │  ± 1.83 % │ + 75.02 %               ║
 | 
						
						
						
							|  |  | ╚══════════════════════════════╧═════════╧═════════════════╧═══════════╧═════════════════════════╝
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ╔══════════════════════════════╤═════════╤═══════════════╤═══════════╤═════════════════════════╗
 | 
						
						
						
							|  |  | ║ Slower tests                 │ Samples │        Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟──────────────────────────────┼─────────┼───────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ ES512 - fast-jwt (async)     │    1000 │ 419.29 op/sec │  ± 0.34 % │                         ║
 | 
						
						
						
							|  |  | ║ ES512 - jsonwebtoken (async) │    1000 │ 440.53 op/sec │  ± 0.26 % │ + 5.07 %                ║
 | 
						
						
						
							|  |  | ║ ES512 - jsonwebtoken (sync)  │    1000 │ 445.91 op/sec │  ± 0.16 % │ + 6.35 %                ║
 | 
						
						
						
							|  |  | ║ ES512 - jose (sync)          │    1000 │ 452.01 op/sec │  ± 0.20 % │ + 7.80 %                ║
 | 
						
						
						
							|  |  | ╟──────────────────────────────┼─────────┼───────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ Fastest test                 │ Samples │        Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟──────────────────────────────┼─────────┼───────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ ES512 - fast-jwt (sync)      │    1000 │ 467.54 op/sec │  ± 0.15 % │ + 11.51 %               ║
 | 
						
						
						
							|  |  | ╚══════════════════════════════╧═════════╧═══════════════╧═══════════╧═════════════════════════╝
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ╔══════════════════════════════╤═════════╤═══════════════╤═══════════╤═════════════════════════╗
 | 
						
						
						
							|  |  | ║ Slower tests                 │ Samples │        Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟──────────────────────────────┼─────────┼───────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ RS512 - fast-jwt (async)     │    1000 │ 196.13 op/sec │  ± 0.28 % │                         ║
 | 
						
						
						
							|  |  | ║ RS512 - jsonwebtoken (async) │    1000 │ 200.15 op/sec │  ± 0.23 % │ + 2.05 %                ║
 | 
						
						
						
							|  |  | ║ RS512 - jsonwebtoken (sync)  │    1000 │ 203.72 op/sec │  ± 0.18 % │ + 3.87 %                ║
 | 
						
						
						
							|  |  | ║ RS512 - jose (sync)          │    1000 │ 245.89 op/sec │  ± 0.39 % │ + 25.37 %               ║
 | 
						
						
						
							|  |  | ╟──────────────────────────────┼─────────┼───────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ Fastest test                 │ Samples │        Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟──────────────────────────────┼─────────┼───────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ RS512 - fast-jwt (sync)      │    1000 │ 273.31 op/sec │  ± 0.27 % │ + 39.36 %               ║
 | 
						
						
						
							|  |  | ╚══════════════════════════════╧═════════╧═══════════════╧═══════════╧═════════════════════════╝
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ╔══════════════════════════════╤═════════╤═══════════════╤═══════════╤═════════════════════════╗
 | 
						
						
						
							|  |  | ║ Slower tests                 │ Samples │        Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟──────────────────────────────┼─────────┼───────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ PS512 - jsonwebtoken (sync)  │    1000 │ 194.00 op/sec │  ± 0.27 % │                         ║
 | 
						
						
						
							|  |  | ║ PS512 - jsonwebtoken (async) │    1000 │ 202.08 op/sec │  ± 0.21 % │ + 4.17 %                ║
 | 
						
						
						
							|  |  | ║ PS512 - fast-jwt (async)     │    1000 │ 203.36 op/sec │  ± 0.19 % │ + 4.82 %                ║
 | 
						
						
						
							|  |  | ║ PS512 - jose (sync)          │    1000 │ 266.54 op/sec │  ± 0.29 % │ + 37.39 %               ║
 | 
						
						
						
							|  |  | ╟──────────────────────────────┼─────────┼───────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ Fastest test                 │ Samples │        Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟──────────────────────────────┼─────────┼───────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ PS512 - fast-jwt (sync)      │    1000 │ 272.11 op/sec │  ± 0.24 % │ + 40.26 %               ║
 | 
						
						
						
							|  |  | ╚══════════════════════════════╧═════════╧═══════════════╧═══════════╧═════════════════════════╝
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ╔══════════════════════════╤═════════╤═════════════════╤═══════════╤═════════════════════════╗
 | 
						
						
						
							|  |  | ║ Slower tests             │ Samples │          Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟──────────────────────────┼─────────┼─────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ EdDSA - fast-jwt (async) │    1000 │  8301.50 op/sec │  ± 0.70 % │                         ║
 | 
						
						
						
							|  |  | ║ EdDSA - jose (sync)      │    1500 │ 16561.83 op/sec │  ± 0.88 % │ + 99.50 %               ║
 | 
						
						
						
							|  |  | ╟──────────────────────────┼─────────┼─────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ Fastest test             │ Samples │          Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟──────────────────────────┼─────────┼─────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ EdDSA - fast-jwt (sync)  │    3000 │ 17514.99 op/sec │  ± 0.94 % │ + 110.99 %              ║
 | 
						
						
						
							|  |  | ╚══════════════════════════╧═════════╧═════════════════╧═══════════╧═════════════════════════╝
 | 
						
						
						
							|  |  | ```
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ### Decoding
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ```
 | 
						
						
						
							|  |  | ╔═════════════════════════════════╤═════════╤══════════════════╤═══════════╤═════════════════════════╗
 | 
						
						
						
							|  |  | ║ Slower tests                    │ Samples │           Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ RS512 - jsonwebtoken - complete │   10000 │ 126201.23 op/sec │  ± 2.84 % │                         ║
 | 
						
						
						
							|  |  | ║ RS512 - jsonwebtoken            │   10000 │ 143571.03 op/sec │  ± 1.82 % │ + 13.76 %               ║
 | 
						
						
						
							|  |  | ║ RS512 - jose - complete         │   10000 │ 252738.76 op/sec │  ± 5.62 % │ + 100.27 %              ║
 | 
						
						
						
							|  |  | ║ RS512 - fast-jwt                │   10000 │ 254921.59 op/sec │  ± 3.39 % │ + 102.00 %              ║
 | 
						
						
						
							|  |  | ║ RS512 - jose                    │   10000 │ 266197.51 op/sec │  ± 4.02 % │ + 110.93 %              ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ Fastest test                    │ Samples │           Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ RS512 - fast-jwt - complete     │   10000 │ 284719.82 op/sec │  ± 3.39 % │ + 125.61 %              ║
 | 
						
						
						
							|  |  | ╚═════════════════════════════════╧═════════╧══════════════════╧═══════════╧═════════════════════════╝
 | 
						
						
						
							|  |  | ```
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Note that for decoding the algorithm is irrelevant, so only one was measured.
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ### Verifying
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ```
 | 
						
						
						
							|  |  | ╔═════════════════════════════════════╤═════════╤══════════════════╤═══════════╤═════════════════════════╗
 | 
						
						
						
							|  |  | ║ Slower tests                        │ Samples │           Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ HS512 - jsonwebtoken (sync)         │   10000 │  49275.12 op/sec │  ± 1.41 % │                         ║
 | 
						
						
						
							|  |  | ║ HS512 - fast-jwt (async)            │   10000 │  51353.81 op/sec │  ± 2.98 % │ + 4.22 %                ║
 | 
						
						
						
							|  |  | ║ HS512 - jsonwebtoken (async)        │   10000 │  51610.98 op/sec │  ± 1.51 % │ + 4.74 %                ║
 | 
						
						
						
							|  |  | ║ HS512 - jose (sync)                 │   10000 │  64280.92 op/sec │  ± 1.73 % │ + 30.45 %               ║
 | 
						
						
						
							|  |  | ║ HS512 - fast-jwt (sync)             │   10000 │  75067.57 op/sec │  ± 2.40 % │ + 52.34 %               ║
 | 
						
						
						
							|  |  | ║ HS512 - fast-jwt (async with cache) │   10000 │ 175013.21 op/sec │  ± 4.42 % │ + 255.18 %              ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ Fastest test                        │ Samples │           Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ HS512 - fast-jwt (sync with cache)  │   10000 │ 207199.64 op/sec │  ± 3.15 % │ + 320.50 %              ║
 | 
						
						
						
							|  |  | ╚═════════════════════════════════════╧═════════╧══════════════════╧═══════════╧═════════════════════════╝
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ╔═════════════════════════════════════╤═════════╤══════════════════╤═══════════╤═════════════════════════╗
 | 
						
						
						
							|  |  | ║ Slower tests                        │ Samples │           Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ ES512 - fast-jwt (async)            │    1000 │    561.01 op/sec │  ± 0.44 % │                         ║
 | 
						
						
						
							|  |  | ║ ES512 - jsonwebtoken (sync)         │    1000 │    573.52 op/sec │  ± 0.27 % │ + 2.23 %                ║
 | 
						
						
						
							|  |  | ║ ES512 - jsonwebtoken (async)        │    1000 │    573.74 op/sec │  ± 0.26 % │ + 2.27 %                ║
 | 
						
						
						
							|  |  | ║ ES512 - fast-jwt (sync)             │    1000 │    597.68 op/sec │  ± 0.30 % │ + 6.54 %                ║
 | 
						
						
						
							|  |  | ║ ES512 - jose (sync)                 │    1000 │    604.42 op/sec │  ± 0.27 % │ + 7.74 %                ║
 | 
						
						
						
							|  |  | ║ ES512 - fast-jwt (async with cache) │   10000 │ 189999.48 op/sec │  ± 4.49 % │ + 33767.60 %            ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ Fastest test                        │ Samples │           Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ ES512 - fast-jwt (sync with cache)  │   10000 │ 192353.61 op/sec │  ± 4.79 % │ + 34187.22 %            ║
 | 
						
						
						
							|  |  | ╚═════════════════════════════════════╧═════════╧══════════════════╧═══════════╧═════════════════════════╝
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ╔═════════════════════════════════════╤═════════╤══════════════════╤═══════════╤═════════════════════════╗
 | 
						
						
						
							|  |  | ║ Slower tests                        │ Samples │           Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ RS512 - jsonwebtoken (async)        │    1500 │   7551.10 op/sec │  ± 0.92 % │                         ║
 | 
						
						
						
							|  |  | ║ RS512 - jsonwebtoken (sync)         │    4500 │   7750.46 op/sec │  ± 0.96 % │ + 2.64 %                ║
 | 
						
						
						
							|  |  | ║ RS512 - fast-jwt (async)            │    1000 │   8413.41 op/sec │  ± 0.99 % │ + 11.42 %               ║
 | 
						
						
						
							|  |  | ║ RS512 - jose (sync)                 │    4500 │  12382.58 op/sec │  ± 0.94 % │ + 63.98 %               ║
 | 
						
						
						
							|  |  | ║ RS512 - fast-jwt (sync)             │    4500 │  12665.45 op/sec │  ± 0.90 % │ + 67.73 %               ║
 | 
						
						
						
							|  |  | ║ RS512 - fast-jwt (sync with cache)  │   10000 │ 145107.65 op/sec │  ± 7.54 % │ + 1821.68 %             ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ Fastest test                        │ Samples │           Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ RS512 - fast-jwt (async with cache) │   10000 │ 158780.83 op/sec │  ± 3.90 % │ + 2002.75 %             ║
 | 
						
						
						
							|  |  | ╚═════════════════════════════════════╧═════════╧══════════════════╧═══════════╧═════════════════════════╝
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ╔═════════════════════════════════════╤═════════╤══════════════════╤═══════════╤═════════════════════════╗
 | 
						
						
						
							|  |  | ║ Slower tests                        │ Samples │           Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ PS512 - jsonwebtoken (async)        │    2500 │   7240.21 op/sec │  ± 0.89 % │                         ║
 | 
						
						
						
							|  |  | ║ PS512 - jsonwebtoken (sync)         │    2000 │   7449.38 op/sec │  ± 0.91 % │ + 2.89 %                ║
 | 
						
						
						
							|  |  | ║ PS512 - fast-jwt (async)            │    1500 │   8301.99 op/sec │  ± 0.81 % │ + 14.67 %               ║
 | 
						
						
						
							|  |  | ║ PS512 - jose (sync)                 │    4000 │  11944.57 op/sec │  ± 0.99 % │ + 64.98 %               ║
 | 
						
						
						
							|  |  | ║ PS512 - fast-jwt (sync)             │    1000 │  12881.96 op/sec │  ± 0.76 % │ + 77.92 %               ║
 | 
						
						
						
							|  |  | ║ PS512 - fast-jwt (async with cache) │   10000 │ 155603.59 op/sec │  ± 4.27 % │ + 2049.16 %             ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ Fastest test                        │ Samples │           Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ PS512 - fast-jwt (sync with cache)  │   10000 │ 172097.91 op/sec │  ± 4.58 % │ + 2276.97 %             ║
 | 
						
						
						
							|  |  | ╚═════════════════════════════════════╧═════════╧══════════════════╧═══════════╧═════════════════════════╝
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ╔═════════════════════════════════════╤═════════╤══════════════════╤═══════════╤═════════════════════════╗
 | 
						
						
						
							|  |  | ║ Slower tests                        │ Samples │           Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ EdDSA - fast-jwt (async)            │    1000 │   6370.58 op/sec │  ± 0.59 % │                         ║
 | 
						
						
						
							|  |  | ║ EdDSA - jose (sync)                 │    1000 │   6538.90 op/sec │  ± 0.83 % │ + 2.64 %                ║
 | 
						
						
						
							|  |  | ║ EdDSA - fast-jwt (sync)             │    1000 │   7078.93 op/sec │  ± 0.87 % │ + 11.12 %               ║
 | 
						
						
						
							|  |  | ║ EdDSA - fast-jwt (async with cache) │   10000 │ 177457.09 op/sec │  ± 5.36 % │ + 2685.57 %             ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ Fastest test                        │ Samples │           Result │ Tolerance │ Difference with slowest ║
 | 
						
						
						
							|  |  | ╟─────────────────────────────────────┼─────────┼──────────────────┼───────────┼─────────────────────────╢
 | 
						
						
						
							|  |  | ║ EdDSA - fast-jwt (sync with cache)  │   10000 │ 202628.41 op/sec │  ± 3.12 % │ + 3080.69 %             ║
 | 
						
						
						
							|  |  | ╚═════════════════════════════════════╧═════════╧══════════════════╧═══════════╧═════════════════════════╝
 | 
						
						
						
							|  |  | ```
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ## Contributing
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | See [CONTRIBUTING.md](./CONTRIBUTING.md)
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | ## License
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | Copyright NearForm Ltd 2020-2021. Licensed under the [Apache-2.0 license](http://www.apache.org/licenses/LICENSE-2.0).
 |