AJ ONeal 0f0d0807a0 | ||
---|---|---|
README.md | ||
keyfetch-test.js | ||
keyfetch.js | ||
package-lock.json | ||
package.json |
README.md
keyfetch
Lightweight support for fetching JWKs.
Fetches JSON native JWKs and exposes them as PEMs that can be consumed by the jsonwebtoken
package
(and node's native RSA and ECDSA crypto APIs).
Features
Works great for
jsonwebtoken
(Auth0)- OIDC (OpenID Connect)
- .well-known/jwks.json (Auth0)
- Other JWKs URLs
Crypto Support
- JWT verification
- RSA (all variants)
- EC / ECDSA (NIST variants P-256, P-384)
- esoteric variants (excluded to keep the code featherweight and secure)
Install
npm install --save keyfetch
Usage
Retrieve a key list of keys:
var keyfetch = require('keyfetch');
keyfetch.oidcJwks("https://example.com/").then(function (results) {
results.forEach(function (result) {
console.log(result.jwk);
console.log(result.thumprint);
console.log(result.pem);
});
});
Quick JWT verification:
var keyfetch = require('keyfetch');
var jwt = '...';
keyfetch.verify({ jwt: jwt }).then(function (decoded) {
console.log(decoded);
});
Verify a JWT with jsonwebtoken
:
var keyfetch = require('keyfetch');
var jwt = require('jsonwebtoken');
var auth = "..."; // some JWT
var token = jwt.decode(auth, { json: true, complete: true })
if (!isTrustedIssuer(token.payload.iss)) {
throw new Error("untrusted issuer");
}
keyfetch.oidcJwk(
token.header.kid
, token.payload.iss
).then(function (result) {
console.log(result.jwk);
console.log(result.thumprint);
console.log(result.pem);
jwt.verify(jwt, pem);
});
Note: You might implement isTrustedIssuer
one of these:
function isTrustedIssuer(iss) {
return -1 !== [ 'https://partner.com/', 'https://auth0.com/'].indexOf(iss);
}
function isTrustedIssuer(iss) {
return /^https:/.test(iss) && // must be a secure domain
/(\.|^)example\.com$/.test(iss); // can be example.com or any subdomain
}
API
All API calls will return the RFC standard JWK SHA256 thumbprint as well as a PEM version of the key.
Note: When specifying id
, it may be either kid
(as in token.header.kid
)
or thumbprint
(as in result.thumbprint
).
JWKs URLs
Retrieves keys from a URL such as https://example.com/jwks/
with the format { keys: [ { kid, kty, exp, ... } ] }
and returns the array of keys (as well as thumbprint and jwk-to-pem).
keyfetch.jwks(jwksUrl)
// Promises [ { jwk, thumbprint, pem } ] or fails
keyfetch.jwk(id, jwksUrl)
// Promises { jwk, thumbprint, pem } or fails
Auth0
If https://example.com/
is used as issuerUrl
it will resolve to
https://example.com/.well-known/jwks.json
and return the keys.
keyfetch.wellKnownJwks(issuerUrl)
// Promises [ { jwk, thumbprint, pem } ] or fails
keyfetch.wellKnownJwk(id, issuerUrl)
// Promises { jwk, thumbprint, pem } or fails
OIDC
If https://example.com/
is used as issuerUrl
then it will first resolve to
https://example.com/.well-known/openid-configuration
and then follow jwks_uri
to return the keys.
keyfetch.oidcJwks(issuerUrl)
// Promises [ { jwk, thumbprint, pem } ] or fails
keyfetch.oidcJwk(id, issuerUrl)
// Promises { jwk, thumbprint, pem } or fails
Verify JWT
keyfetch.verify({ jwt: jwk, strategy: 'oidc' })
// Promises a decoded JWT { headers, payload, signature } or fails
strategy
may beoidc
(default) ,auth0
, or a direct JWKs url.
Cache Settings
keyfetch.init({
// set all keys at least 1 hour (regardless of jwk.exp)
mincache: 1 * 60 * 60
// expire each key after 3 days (regardless of jwk.exp)
, maxcache: 3 * 24 * 60 * 60
// re-fetch a key up to 15 minutes before it expires (only if used)
, staletime: 15 * 60
})
There is no background task to cleanup expired keys as of yet. For now you can limit the number of keys fetched by having a simple whitelist.