UNPKG

jwks-client

Version:

Library to retrieve public keys from a JWKS endpoint

150 lines (114 loc) 5.07 kB
# jwks-client [![pipeline status](https://gitlab.com/JacoKoster/node-jwks-client/badges/master/pipeline.svg)](https://gitlab.com/JacoKoster/node-jwks-client/commits/master) [![coverage report](https://gitlab.com/JacoKoster/node-jwks-client/badges/master/coverage.svg)](https://gitlab.com/JacoKoster/node-jwks-client/commits/master) [![Known Vulnerabilities](https://snyk.io/test/npm/jwks-client/badge.svg)](https://snyk.io/test/npm/jwks-client) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=jwks-client&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=jwks-client) [![Downloads](https://img.shields.io/npm/dw/jwks-client)](https://www.npmjs.com/package/jwks-client) [![License](https://img.shields.io/:license-mit-blue.svg?style=flat)](https://opensource.org/licenses/MIT) A library to retrieve signing keys from a JWKS (JSON Web Key Set) endpoint. This is a fork of the [jwks-rsa](https://www.npmjs.com/package/jwks-rsa)-package to support ECDSA-keys as well. Functionally it is almost the same, except for the generalised response, which always uses `publicKey` regardless of the key used. ```sh npm install --save jwks-client ``` ## Loading the Module ### ES Modules (ESM) ```js import JwksClient from 'jwks-client'; ``` ### CommonJS jwks-client from v2 is an ESM-only module - you are not able to import it with require(). If you cannot switch to ESM, please use v1 which remains compatible with CommonJS. Critical bug fixes will continue to be published for v1. ```sh npm install jwks-client@1 ``` Alternatively, you can use the async import() function from CommonJS to load node-fetch asynchronously: ```js const JwksClient = (...args) => import('jwks-client').then(({default: JwksClient}) => JwksClient(...args)); async function example() { const client = await JwksClient({ strictSsl: true, // Default value jwksUri: 'https://jacokoster.nl/.well-known/jwks.json' }); const kid = 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg'; client.getSigningKey(kid, (err, key) => { const signingKey = key.publicKey; }); } ``` ## Usage You'll provide the client with the JWKS endpoint which exposes your signing keys. Using the `getSigningKey` you can then get the signing key that matches a specific `kid`. ```js import JwksClient from 'jwks-client'; const client = new JwksClient({ strictSsl: true, // Default value jwksUri: 'https://jacokoster.nl/.well-known/jwks.json' }); const kid = 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg'; client.getSigningKey(kid, (err, key) => { const signingKey = key.publicKey; }); ``` ### Caching In order to prevent a call to be made each time a signing key needs to be retrieved you can also configure a cache as follows. If a signing key matching the `kid` is found, this will be cached and the next time this `kid` is requested the signing key will be served from the cache instead of calling back to the JWKS endpoint. ```js import JwksClient from 'jwks-client'; const client = new JwksClient({ cache: true, cacheMaxEntries: 5, // Default value cacheMaxAge: ms('10h'), // Default value jwksUri: 'https://jacokoster.nl/.well-known/jwks.json' }); const kid = 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg'; client.getSigningKey(kid, (err, key) => { const signingKey = key.publicKey; }); ``` ### Rate Limiting Even if caching is enabled the library will call the JWKS endpoint if the `kid` is not available in the cache, because a key rotation could have taken place. To prevent attackers to send many random `kid`s you can also configure rate limiting. This will allow you to limit the number of calls that are made to the JWKS endpoint per minute (because it would be highly unlikely that signing keys are rotated multiple times per minute). ```js import JwksClient from 'jwks-client'; const client = new JwksClient({ cache: true, rateLimit: true, jwksRequestsPerMinute: 10, // Default value jwksUri: 'https://jacokoster.nl/.well-known/jwks.json' }); const kid = 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg'; client.getSigningKey(kid, (err, key) => { const signingKey = key.publicKey; }); ``` ### Custom headers It's possible to include custom headers to the request done to the key-server. ```js import JwksClient from 'jwks-client'; const client = new JwksClient({ jwksUri: 'https://jacokoster.nl/.well-known/jwks.json', headers: { 'User-Agent': 'custom-request' } }); const kid = 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg'; client.getSigningKey(kid, (err, key) => { const signingKey = key.publicKey; }); ``` ## Running Tests ``` npm run test ``` ## Showing Trace Logs To show trace logs you can set the following environment variable: ``` DEBUG=jwks ``` Output: ```sh jwks Retrieving keys from http://my-authz-server/.well-known/jwks.json +5ms jwks Keys: +8ms [ { alg: 'RS256', kty: 'RSA', use: 'sig', x5c: [ 'pk1' ], kid: 'ABC' }, { alg: 'RS256', kty: 'RSA', use: 'sig', x5c: [], kid: '123' } ] ```