nearform / fast-jwt

Fast JSON Web Token implementation
https://nearform.github.io/fast-jwt/
Other
347 stars 30 forks source link
hacktoberfest jwt jwt-token

fast-jwt

Package Version CI

Fast JSON Web Token implementation.

Installation

Just run:

npm install fast-jwt

Usage

createSigner

Create a signer function by calling createSigner and providing one or more of the following options:

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:

{
  key: '<YOUR_RSA_ENCRYPTED_PRIVATE_KEY>',
  passphrase: '<PASSPHRASE_THAT_WAS_USED_TO_ENCRYPT_THE_PRIVATE_KEY>'
}

Example

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:

The decoder is a function which accepts a token (as Buffer or string) and returns the payload or the sections of the token.

Examples

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:

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

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

Creating a certificate

Many different algorithms are supported and appropriate certificates can be created through various external applications. Here is one example to create RSA certificates with openssl.

PRIVATE_PEM="./jwt-private.pem"
PUBLIC_PEM="./jwt-public.pem"

ssh-keygen -t rsa -b 2048 -m PEM -f "$PRIVATE_PEM" -q -N ""
openssl rsa -in "$PRIVATE_PEM" -pubout -outform PEM -out "$PUBLIC_PEM" 2>/dev/null
rm "$PRIVATE_PEM.pub"

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, 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 exported by TOKEN_ERROR_CODES.

JWKS

JWKS is supported via 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

License

Licensed under the Apache-2.0 license.