Skip to content

Commit

Permalink
full JWK/JWS support (#205)
Browse files Browse the repository at this point in the history
* start

* Support for all types of algorithms of signing

* Set new requirement for the package

* Support all signature algorithms on integration middlewares

* rebased, refactored

* Fix linting errors

Co-authored-by: ivn-cote <kotovivan@gmail.com>
Co-authored-by: David <david.patrick@auth0.com>
  • Loading branch information
3 people committed Jan 7, 2021
1 parent 818d061 commit 61d4343
Show file tree
Hide file tree
Showing 17 changed files with 411 additions and 432 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -7,7 +7,7 @@
[![Downloads][downloads-image]][downloads-url]
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Fnode-jwks-rsa.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fauth0%2Fnode-jwks-rsa?ref=badge_shield)

A library to retrieve RSA signing keys from a JWKS (JSON Web Key Set) endpoint.
A library to retrieve signing keys from a JWKS (JSON Web Key Set) endpoint.

> npm install --save jwks-rsa
Expand Down
2 changes: 0 additions & 2 deletions index.d.ts
Expand Up @@ -44,7 +44,6 @@ declare namespace JwksRsa {

interface CertSigningKey {
kid: string;
nbf: string;
getPublicKey(): string;
publicKey: string;
}
Expand All @@ -64,7 +63,6 @@ declare namespace JwksRsa {

interface RsaSigningKey {
kid: string;
nbf: string;
getPublicKey(): string;
rsaPublicKey: string;
}
Expand Down
593 changes: 334 additions & 259 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -10,7 +10,7 @@
"debug": "^4.1.0",
"http-proxy-agent": "^4.0.1",
"https-proxy-agent": "^5.0.0",
"jsonwebtoken": "^8.5.1",
"jose": "^2.0.2",
"limiter": "^1.1.5",
"lru-memoizer": "^2.1.2",
"ms": "^2.1.2",
Expand All @@ -31,6 +31,7 @@
"eslint-plugin-babel": "^5.3.0",
"express": "^4.17.1",
"express-jwt": "^6.0.0",
"jsonwebtoken": "^8.5.1",
"koa": "^2.12.1",
"koa-jwt": "^3.6.0",
"mocha": "^6.2.3",
Expand Down
3 changes: 2 additions & 1 deletion src/JwksClient.js
Expand Up @@ -6,6 +6,7 @@ import SigningKeyNotFoundError from './errors/SigningKeyNotFoundError';
import {
retrieveSigningKeys
} from './utils';

import {
cacheSigningKey,
rateLimitSigningKey,
Expand Down Expand Up @@ -33,7 +34,7 @@ export class JwksClient {
if (this.options.cache) {
this.getSigningKey = cacheSigningKey(this, options);
}

if (this.options.rateLimit || this.options.cache) {
this.getSigningKeyAsync = promisifyIt(this.getSigningKey, this);
}
Expand Down
15 changes: 15 additions & 0 deletions src/integrations/config.js
@@ -0,0 +1,15 @@
const allowedSignatureAlg = [
'RS256',
'RS384',
'RS512',
'PS256',
'PS384',
'PS512',
'ES256',
'ES256K',
'ES384',
'ES512',
'EdDSA'
];

export default allowedSignatureAlg;
4 changes: 2 additions & 2 deletions src/integrations/express.js
@@ -1,5 +1,6 @@
import { ArgumentError } from '../errors';
import { JwksClient } from '../JwksClient';
import supportedAlg from './config';

const handleSigningKeyError = (err, cb) => {
// If we didn't find a match, can't provide a key.
Expand All @@ -22,8 +23,7 @@ module.exports.expressJwtSecret = (options) => {
const onError = options.handleSigningKeyError || handleSigningKeyError;

return function secretProvider(req, header, payload, cb) {
// Only RS256 is supported.
if (!header || header.alg !== 'RS256') {
if (!header || !supportedAlg.includes(header.alg)) {
return cb(null, null);
}

Expand Down
6 changes: 3 additions & 3 deletions src/integrations/hapi.js
@@ -1,5 +1,6 @@
import { ArgumentError } from '../errors';
import { JwksClient } from '../JwksClient';
import supportedAlg from './config';

const handleSigningKeyError = (err, cb) => {
// If we didn't find a match, can't provide a key.
Expand Down Expand Up @@ -44,9 +45,8 @@ module.exports.hapiJwt2Key = (options) => {
return cb(new Error('Cannot find a signing certificate if there is no header'), null, null);
}

// Only RS256 is supported.
if (decoded.header.alg !== 'RS256') {
return cb(new Error('Unsupported algorithm ' + decoded.header.alg + ' supplied. node-jwks-rsa supports only RS256'), null, null);
if (!supportedAlg.includes(decoded.header.alg)) {
return cb(new Error('Unsupported algorithm ' + decoded.header.alg + ' supplied.'), null, null);
}

client.getSigningKey(decoded.header.kid, (err, key) => {
Expand Down
4 changes: 2 additions & 2 deletions src/integrations/koa.js
@@ -1,5 +1,6 @@
import { ArgumentError } from '../errors';
import { JwksClient } from '../JwksClient';
import supportedAlg from './config';

module.exports.koaJwtSecret = (options = {}) => {

Expand All @@ -13,8 +14,7 @@ module.exports.koaJwtSecret = (options = {}) => {

return new Promise((resolve, reject) => {

// Only RS256 is supported.
if (alg !== 'RS256') {
if (!supportedAlg.includes(alg)) {
return reject(new Error('Missing / invalid token algorithm'));
}

Expand Down
11 changes: 7 additions & 4 deletions src/integrations/passport.js
@@ -1,6 +1,7 @@
import jwt from 'jsonwebtoken';
import { JWT } from 'jose';
import { ArgumentError } from '../errors';
import { JwksClient } from '../JwksClient';
import supportedAlg from './config';

const handleSigningKeyError = (err, cb) => {
// If we didn't find a match, can't provide a key.
Expand All @@ -27,10 +28,12 @@ module.exports.passportJwtSecret = (options) => {
const onError = options.handleSigningKeyError || handleSigningKeyError;

return function secretProvider(req, rawJwtToken, cb) {
const decoded = jwt.decode(rawJwtToken, { complete: true });
let decoded;
try {
decoded = JWT.decode(rawJwtToken, { complete: true });
} catch (err) {}

// Only RS256 is supported.
if (!decoded || !decoded.header || decoded.header.alg !== 'RS256') {
if (!decoded || !supportedAlg.includes(decoded.header.alg)) {
return cb(null, null);
}

Expand Down
100 changes: 17 additions & 83 deletions src/utils.js
@@ -1,86 +1,20 @@
export function certToPEM(cert) {
cert = cert.match(/.{1,64}/g).join('\n');
cert = `-----BEGIN CERTIFICATE-----\n${cert}\n-----END CERTIFICATE-----\n`;
return cert;
}

function prepadSigned(hexStr) {
const msb = hexStr[0];
if (msb < '0' || msb > '7') {
return `00${hexStr}`;
}
return hexStr;
}

function toHex(number) {
const nstr = number.toString(16);
if (nstr.length % 2) {
return `0${nstr}`;
}
return nstr;
}

function encodeLengthHex(n) {
if (n <= 127) {
return toHex(n);
}
const nHex = toHex(n);
const lengthOfLengthByte = 128 + nHex.length / 2;
return toHex(lengthOfLengthByte) + nHex;
}

/*
* Source: http://stackoverflow.com/questions/18835132/xml-to-pem-in-node-js
*/
export function rsaPublicKeyToPEM(modulusB64, exponentB64) {
const modulus = Buffer.from(modulusB64, 'base64');
const exponent = Buffer.from(exponentB64, 'base64');
const modulusHex = prepadSigned(modulus.toString('hex'));
const exponentHex = prepadSigned(exponent.toString('hex'));
const modlen = modulusHex.length / 2;
const explen = exponentHex.length / 2;

const encodedModlen = encodeLengthHex(modlen);
const encodedExplen = encodeLengthHex(explen);
const encodedPubkey = '30' +
encodeLengthHex(modlen + explen + encodedModlen.length / 2 + encodedExplen.length / 2 + 2) +
'02' + encodedModlen + modulusHex +
'02' + encodedExplen + exponentHex;

const der = Buffer.from(encodedPubkey, 'hex')
.toString('base64');

let pem = '-----BEGIN RSA PUBLIC KEY-----\n';
pem += `${der.match(/.{1,64}/g).join('\n')}`;
pem += '\n-----END RSA PUBLIC KEY-----\n';
return pem;
}
import jose from 'jose';
import JwksError from './errors/JwksError';

export function retrieveSigningKeys(keys) {
return keys
.filter((key) => {
if(key.kty !== 'RSA') {
return false;
}
if(key.hasOwnProperty('use') && key.use !== 'sig') {
return false;
}
return ((key.x5c && key.x5c.length) || (key.n && key.e));
})
.map(key => {
const jwk = {
kid: key.kid,
alg: key.alg,
nbf: key.nbf
};
const hasCertificateChain = key.x5c && key.x5c.length;
if (hasCertificateChain) {
jwk.publicKey = certToPEM(key.x5c[0]);
jwk.getPublicKey = () => jwk.publicKey;
} else {
jwk.rsaPublicKey = rsaPublicKeyToPEM(key.n, key.e);
jwk.getPublicKey = () => jwk.rsaPublicKey;
}
return jwk;
});
let keystore = [];
try {
keystore = jose.JWKS.asKeyStore({ keys }, { ignoreErrors: true });
} catch (err) {
return cb(new JwksError(err.message));
}
return keystore.all({ use: 'sig' }).map((key) => {
return {
kid: key.kid,
alg: key.alg,
get publicKey() { return key.toPEM(false); },
get rsaPublicKey() { return key.toPEM(false); },
getPublicKey() { return key.toPEM(false); }
};
});
}
12 changes: 2 additions & 10 deletions tests/jwksClient.tests.js
Expand Up @@ -420,7 +420,6 @@ describe('JwksClient', () => {
alg: 'RS256',
kty: 'RSA',
use: 'sig',
nbf: 123,
x5c: [
'MIIDGzCCAgOgAwIBAgIJAPQM5+PwmOcPMA0GCSqGSIb3DQEBCwUAMCQxIjAgBgNVBAMMGXNhbmRyaW5vLWRldi5ldS5hdXRoMC5jb20wHhcNMTUwMzMxMDkwNTQ3WhcNMjgxMjA3MDkwNTQ3WjAkMSIwIAYDVQQDDBlzYW5kcmluby1kZXYuZXUuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/SECtT7H4rxKtX2HpGhSyeYTe3Vet8YQpjBAr+1TnQ1fcYfvfmnVRHvhmTwABktD1erF1lxFsrRw92yBDOHlL7lj1n2fcfLftSoStgvRHVg52kR+CkBVQ6/mF1lYkefIjik6YRMf55Eu4FqDyVG2dgd5EA8kNO4J8OPc7vAtZyXrRYOZjVXbEgyjje/V+OpMQxAHP2Er11TLuzJjioP0ICVqhAZdq2sLk7agoxn64md6fqOk4N+7lJkU4+412VD0qYwKxD7nGsEclYawKoZD9/xhCk2qfQ/HptIumrdQ5ox3Sq5t2a7VKa41dBUQ1MQtXG2iY7S9RlfcMIyQwGhOQIDAQABo1AwTjAdBgNVHQ4EFgQUHpS1fvO/54G2c1VpEDNUZRSl44gwHwYDVR0jBBgwFoAUHpS1fvO/54G2c1VpEDNUZRSl44gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAtm9I0nr6eXF5aq4yllfiqZcQ6mKrJLH9Rm4Jv+olniNynTcnpwprRVLToIawc8MmzIGZTtCn7u+dSxWf1UNE+SH7XgEnGtO74239vleEx1+Tf5viIdsnCxgvFiPdOqRlc9KcFSWd6a7RzcglnyU7GEx0K5GLv1wPA6qEM+3uwNwjAyVSu5dFw8kCfaSvlk5rXKRUzSoW9NVomw6+tADR8vMZS+4KThZ+4GH0rMN4KjIaRFxW8OMVYOn12uq33fLCd6MuPHW/rklxLbQBoHIU/ClNhbD0t6f00w9lHhPy4IP73rv7Oow0Ny6i70Iq0ijqj+kAtnrphlOvLFxqn6nCvQ=='
],
Expand Down Expand Up @@ -451,7 +450,6 @@ describe('JwksClient', () => {
);
expect(keys[1].publicKey).not.to.be.null;
expect(keys[1].getPublicKey()).to.equal(keys[1].publicKey);
expect(keys[1].nbf).to.equal(123);
done();
});
});
Expand All @@ -471,7 +469,6 @@ describe('JwksClient', () => {
},
{
kid: 'IdTokenSigningKeyContainer.v2',
nbf: 1459289287,
use: 'sig',
kty: 'RSA',
e: 'AQAB',
Expand All @@ -480,15 +477,13 @@ describe('JwksClient', () => {
},
{
kid: 'IdTokenSigningKeyContainer.v3',
nbf: 1459289287,
kty: 'RSA',
e: 'AQAB',
n:
's4W7xjkQZP3OwG7PfRgcYKn8eRYXHiz1iK503fS-K2FZo-Ublwwa2xFZWpsUU_jtoVCwIkaqZuo6xoKtlMYXXvfVHGuKBHEBVn8b8x_57BQWz1d0KdrNXxuMvtFe6RzMqiMqzqZrzae4UqVCkYqcR9gQx66Ehq7hPmCxJCkg7ajo7fu6E7dPd34KH2HSYRsaaEA_BcKTeb9H1XE_qEKjog68wUU9Ekfl3FBIRN-1Ah_BoktGFoXyi_jt0-L0-gKcL1BLmUlGzMusvRbjI_0-qj-mc0utGdRjY-xIN2yBj8vl4DODO-wMwfp-cqZbCd9TENyHaTb8iA27s-73L3ExOQ'
},
{
kid: 'IdTokenSigningKeyContainer.v4',
nbf: 1459289287,
use: 'enc',
kty: 'RSA',
e: 'AQAB',
Expand All @@ -512,7 +507,6 @@ describe('JwksClient', () => {
expect(keys[1].kid).to.equal('IdTokenSigningKeyContainer.v2');
expect(keys[1].rsaPublicKey).not.to.be.null;
expect(keys[1].getPublicKey()).to.equal(keys[1].rsaPublicKey);
expect(keys[1].nbf).to.equal(1459289287);
expect(keys[2].rsaPublicKey).not.to.be.null;
expect(keys[2].getPublicKey()).to.equal(keys[2].rsaPublicKey);
done();
Expand All @@ -525,7 +519,7 @@ describe('JwksClient', () => {
.reply(200, {
keys: [
{
kty: 'something',
kty: 'RSA',
use: 'else',
x5c: [
'MIIDDTCCAfWgAwIBAgIJAJVkuSv2H8mDMA0GCSqGSIb3DQEBBQUAMB0xGzAZBgNVBAMMEnNhbmRyaW5vLmF1dGgwLmNvbTAeFw0xNDA1MTQyMTIyMjZaFw0yODAxMjEyMTIyMjZaMB0xGzAZBgNVBAMMEnNhbmRyaW5vLmF1dGgwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL6jWASkHhXz5Ug6t5BsYBrXDIgrWu05f3oq2fE+5J5REKJiY0Ddc+Kda34ZwOptnUoef3JwKPDAckTJQDugweNNZPwOmFMRKj4xqEpxEkIX8C+zHs41Q6x54ZZy0xU+WvTGcdjzyZTZ/h0iOYisswFQT/s6750tZG0BOBtZ5qS/80tmWH7xFitgewdWteJaASE/eO1qMtdNsp9fxOtN5U/pZDUyFm3YRfOcODzVqp3wOz+dcKb7cdZN11EYGZOkjEekpcedzHCo9H4aOmdKCpytqL/9FXoihcBMg39s1OW3cfwfgf5/kvOJdcqR4PoATQTfsDVoeMWVB4XLGR6SC5kCAwEAAaNQME4wHQYDVR0OBBYEFHDYn9BQdup1CoeoFi0Rmf5xn/W9MB8GA1UdIwQYMBaAFHDYn9BQdup1CoeoFi0Rmf5xn/W9MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGLpQZdd2ICVnGjc6CYfT3VNoujKYWk7E0shGaCXFXptrZ8yaryfo6WAizTfgOpQNJH+Jz+QsCjvkRt6PBSYX/hb5OUDU2zNJN48/VOw57nzWdjI70H2Ar4oJLck36xkIRs/+QX+mSNCjZboRwh0LxanXeALHSbCgJkbzWbjVnfJEQUP9P/7NGf0MkO5I95C/Pz9g91y8gU+R3imGppLy9Zx+OwADFwKAEJak4JrNgcjHBQenakAXnXP6HG4hHH4MzO8LnLiKv8ZkKVL67da/80PcpO0miMNPaqBBMd2Cy6GzQYE0ag6k0nk+DMIFn7K+o21gjUuOEJqIbAvhbf2KcM='
Expand All @@ -537,9 +531,8 @@ describe('JwksClient', () => {
x5t: 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg'
},
{
kty: 'something',
kty: 'RSA',
use: 'else',
nbf: 123,
x5c: [
'MIIDGzCCAgOgAwIBAgIJAPQM5+PwmOcPMA0GCSqGSIb3DQEBCwUAMCQxIjAgBgNVBAMMGXNhbmRyaW5vLWRldi5ldS5hdXRoMC5jb20wHhcNMTUwMzMxMDkwNTQ3WhcNMjgxMjA3MDkwNTQ3WjAkMSIwIAYDVQQDDBlzYW5kcmluby1kZXYuZXUuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/SECtT7H4rxKtX2HpGhSyeYTe3Vet8YQpjBAr+1TnQ1fcYfvfmnVRHvhmTwABktD1erF1lxFsrRw92yBDOHlL7lj1n2fcfLftSoStgvRHVg52kR+CkBVQ6/mF1lYkefIjik6YRMf55Eu4FqDyVG2dgd5EA8kNO4J8OPc7vAtZyXrRYOZjVXbEgyjje/V+OpMQxAHP2Er11TLuzJjioP0ICVqhAZdq2sLk7agoxn64md6fqOk4N+7lJkU4+412VD0qYwKxD7nGsEclYawKoZD9/xhCk2qfQ/HptIumrdQ5ox3Sq5t2a7VKa41dBUQ1MQtXG2iY7S9RlfcMIyQwGhOQIDAQABo1AwTjAdBgNVHQ4EFgQUHpS1fvO/54G2c1VpEDNUZRSl44gwHwYDVR0jBBgwFoAUHpS1fvO/54G2c1VpEDNUZRSl44gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAtm9I0nr6eXF5aq4yllfiqZcQ6mKrJLH9Rm4Jv+olniNynTcnpwprRVLToIawc8MmzIGZTtCn7u+dSxWf1UNE+SH7XgEnGtO74239vleEx1+Tf5viIdsnCxgvFiPdOqRlc9KcFSWd6a7RzcglnyU7GEx0K5GLv1wPA6qEM+3uwNwjAyVSu5dFw8kCfaSvlk5rXKRUzSoW9NVomw6+tADR8vMZS+4KThZ+4GH0rMN4KjIaRFxW8OMVYOn12uq33fLCd6MuPHW/rklxLbQBoHIU/ClNhbD0t6f00w9lHhPy4IP73rv7Oow0Ny6i70Iq0ijqj+kAtnrphlOvLFxqn6nCvQ=='
],
Expand Down Expand Up @@ -659,7 +652,6 @@ describe('JwksClient', () => {
},
{
kid: 'IdTokenSigningKeyContainer.v2',
nbf: 1459289287,
use: 'sig',
kty: 'RSA',
e: 'AQAB',
Expand Down
1 change: 0 additions & 1 deletion tests/keys.js
Expand Up @@ -4,7 +4,6 @@ export const x5cSingle = {
alg: 'RS256',
kty: 'RSA',
use: 'sig',
nbf: 123,
x5c: [
'MIIDGzCCAgOgAwIBAgIJAPQM5+PwmOcPMA0GCSqGSIb3DQEBCwUAMCQxIjAgBgNVBAMMGXNhbmRyaW5vLWRldi5ldS5hdXRoMC5jb20wHhcNMTUwMzMxMDkwNTQ3WhcNMjgxMjA3MDkwNTQ3WjAkMSIwIAYDVQQDDBlzYW5kcmluby1kZXYuZXUuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/SECtT7H4rxKtX2HpGhSyeYTe3Vet8YQpjBAr+1TnQ1fcYfvfmnVRHvhmTwABktD1erF1lxFsrRw92yBDOHlL7lj1n2fcfLftSoStgvRHVg52kR+CkBVQ6/mF1lYkefIjik6YRMf55Eu4FqDyVG2dgd5EA8kNO4J8OPc7vAtZyXrRYOZjVXbEgyjje/V+OpMQxAHP2Er11TLuzJjioP0ICVqhAZdq2sLk7agoxn64md6fqOk4N+7lJkU4+412VD0qYwKxD7nGsEclYawKoZD9/xhCk2qfQ/HptIumrdQ5ox3Sq5t2a7VKa41dBUQ1MQtXG2iY7S9RlfcMIyQwGhOQIDAQABo1AwTjAdBgNVHQ4EFgQUHpS1fvO/54G2c1VpEDNUZRSl44gwHwYDVR0jBBgwFoAUHpS1fvO/54G2c1VpEDNUZRSl44gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAtm9I0nr6eXF5aq4yllfiqZcQ6mKrJLH9Rm4Jv+olniNynTcnpwprRVLToIawc8MmzIGZTtCn7u+dSxWf1UNE+SH7XgEnGtO74239vleEx1+Tf5viIdsnCxgvFiPdOqRlc9KcFSWd6a7RzcglnyU7GEx0K5GLv1wPA6qEM+3uwNwjAyVSu5dFw8kCfaSvlk5rXKRUzSoW9NVomw6+tADR8vMZS+4KThZ+4GH0rMN4KjIaRFxW8OMVYOn12uq33fLCd6MuPHW/rklxLbQBoHIU/ClNhbD0t6f00w9lHhPy4IP73rv7Oow0Ny6i70Iq0ijqj+kAtnrphlOvLFxqn6nCvQ=='
],
Expand Down
8 changes: 3 additions & 5 deletions tests/mocks/jwks.js
@@ -1,17 +1,15 @@
import nock from 'nock';
import jose from 'jose';

export function jwksEndpoint(host, certs) {
return nock(host)
.get('/.well-known/jwks.json')
.reply(200, {
keys: certs.map(cert => {
const parsed = jose.JWK.asKey(cert.pub).toJWK();
return {
alg: 'RS256',
kty: 'RSA',
...parsed,
use: 'sig',
x5c: [
/-----BEGIN CERTIFICATE-----([^-]*)-----END CERTIFICATE-----/g.exec(cert.pub)[1].replace(/[\n|\r\n]/g, '')
],
kid: cert.kid
};
})
Expand Down
2 changes: 1 addition & 1 deletion tests/mocks/jwks.json
@@ -1 +1 @@
{"keys":[{"alg":"RS256","kty":"RSA","use":"sig","x5c":["MIICsDCCAhmgAwIBAgIJAP0uzO56NPNDMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYwODAyMTIyMjMyWhcNMTYwOTAxMTIyMjMyWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQABo4GnMIGkMB0GA1UdDgQWBBR7ZjPnt+i/E8VUy4tinxi0+H5vbTB1BgNVHSMEbjBsgBR7ZjPnt+i/E8VUy4tinxi0+H5vbaFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAP0uzO56NPNDMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAnMA5ZAyEQgXrUl6JT/JFcg6HGXj9yTy71EEMVp3Md3B8WwDvs+di4JFcq8FKSoGtTY4Pb5WE9QVUAmwEsSQoETNYW3quRmYJCkpIHWnvUW/OAf2/Ejr6zXquhBC6WoCeKQuesMvo2qO1rStCUWahUh2/RQt9XozEWPWJ9Oe6a7c="],"kid":"abc"},{"alg":"RS256","kty":"RSA","use":"sig","x5c":["MIICsDCCAhmgAwIBAgIJAP0uzO56NPNDMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYwODAyMTIyMjMyWhcNMTYwOTAxMTIyMjMyWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQABo4GnMIGkMB0GA1UdDgQWBBR7ZjPnt+i/E8VUy4tinxi0+H5vbTB1BgNVHSMEbjBsgBR7ZjPnt+i/E8VUy4tinxi0+H5vbaFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAP0uzO56NPNDMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAnMA5ZAyEQgXrUl6JT/JFcg6HGXj9yTy71EEMVp3Md3B8WwDvs+di4JFcq8FKSoGtTY4Pb5WE9QVUAmwEsSQoETNYW3quRmYJCkpIHWnvUW/OAf2/Ejr6zXquhBC6WoCeKQuesMvo2qO1rStCUWahUh2/RQt9XozEWPWJ9Oe6a7c="],"kid":"xyz"}]}
{"keys":[{"alg":"RS256","kty":"RSA","use":"sig","e":"AQAB","n":"3ZWrUY0Y6IKN1qI4BhxR2C7oHVFgGPYkd38uGq1jQNSqEvJFcN93CYm16_G78FAFKWqwsJb3Wx-nbxDn6LtP4AhULB1H0K0g7_jLklDAHvI8yhOKlvoyvsUFPWtNxlJyh5JJXvkNKV_4Oo12e69f8QCuQ6NpEPl-cSvXIqUYBCs","x5c":["MIICsDCCAhmgAwIBAgIJAP0uzO56NPNDMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYwODAyMTIyMjMyWhcNMTYwOTAxMTIyMjMyWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQABo4GnMIGkMB0GA1UdDgQWBBR7ZjPnt+i/E8VUy4tinxi0+H5vbTB1BgNVHSMEbjBsgBR7ZjPnt+i/E8VUy4tinxi0+H5vbaFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAP0uzO56NPNDMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAnMA5ZAyEQgXrUl6JT/JFcg6HGXj9yTy71EEMVp3Md3B8WwDvs+di4JFcq8FKSoGtTY4Pb5WE9QVUAmwEsSQoETNYW3quRmYJCkpIHWnvUW/OAf2/Ejr6zXquhBC6WoCeKQuesMvo2qO1rStCUWahUh2/RQt9XozEWPWJ9Oe6a7c="],"kid":"abc"},{"alg":"RS256","kty":"RSA","use":"sig","e":"AQAB","n":"3ZWrUY0Y6IKN1qI4BhxR2C7oHVFgGPYkd38uGq1jQNSqEvJFcN93CYm16_G78FAFKWqwsJb3Wx-nbxDn6LtP4AhULB1H0K0g7_jLklDAHvI8yhOKlvoyvsUFPWtNxlJyh5JJXvkNKV_4Oo12e69f8QCuQ6NpEPl-cSvXIqUYBCs","x5c":["MIICsDCCAhmgAwIBAgIJAP0uzO56NPNDMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYwODAyMTIyMjMyWhcNMTYwOTAxMTIyMjMyWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQABo4GnMIGkMB0GA1UdDgQWBBR7ZjPnt+i/E8VUy4tinxi0+H5vbTB1BgNVHSMEbjBsgBR7ZjPnt+i/E8VUy4tinxi0+H5vbaFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAP0uzO56NPNDMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAnMA5ZAyEQgXrUl6JT/JFcg6HGXj9yTy71EEMVp3Md3B8WwDvs+di4JFcq8FKSoGtTY4Pb5WE9QVUAmwEsSQoETNYW3quRmYJCkpIHWnvUW/OAf2/Ejr6zXquhBC6WoCeKQuesMvo2qO1rStCUWahUh2/RQt9XozEWPWJ9Oe6a7c="],"kid":"xyz"}]}

0 comments on commit 61d4343

Please sign in to comment.