openid-client 5.5.0 → 5.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -4,6 +4,7 @@ const crypto = require('crypto');
4
4
  const { strict: assert } = require('assert');
5
5
  const querystring = require('querystring');
6
6
  const url = require('url');
7
+ const { URL, URLSearchParams } = require('url');
7
8
 
8
9
  const jose = require('jose');
9
10
  const tokenHash = require('oidc-token-hash');
@@ -62,6 +63,12 @@ function authorizationHeaderValue(token, tokenType = 'Bearer') {
62
63
  return `${tokenType} ${token}`;
63
64
  }
64
65
 
66
+ function getSearchParams(input) {
67
+ const parsed = url.parse(input);
68
+ if (!parsed.search) return {};
69
+ return querystring.parse(parsed.search.substring(1));
70
+ }
71
+
65
72
  function verifyPresence(payload, jwt, prop) {
66
73
  if (payload[prop] === undefined) {
67
74
  throw new RPError({
@@ -251,13 +258,21 @@ class BaseClient {
251
258
  throw new TypeError('params must be a plain object');
252
259
  }
253
260
  assertIssuerConfiguration(this.issuer, 'authorization_endpoint');
254
- const target = url.parse(this.issuer.authorization_endpoint, true);
255
- target.search = null;
256
- target.query = {
257
- ...target.query,
258
- ...authorizationParams.call(this, params),
259
- };
260
- return url.format(target);
261
+ const target = new URL(this.issuer.authorization_endpoint);
262
+
263
+ for (const [name, value] of Object.entries(authorizationParams.call(this, params))) {
264
+ if (Array.isArray(value)) {
265
+ target.searchParams.delete(name);
266
+ for (const member of value) {
267
+ target.searchParams.append(name, member);
268
+ }
269
+ } else {
270
+ target.searchParams.set(name, value);
271
+ }
272
+ }
273
+
274
+ // TODO: is the replace needed?
275
+ return target.href.replace('+', '%20');
261
276
  }
262
277
 
263
278
  authorizationPost(params = {}) {
@@ -297,10 +312,9 @@ class BaseClient {
297
312
  id_token_hint = id_token_hint.id_token;
298
313
  }
299
314
 
300
- const target = url.parse(this.issuer.end_session_endpoint, true);
301
- target.search = null;
302
- defaults(
303
- target.query,
315
+ const target = url.parse(this.issuer.end_session_endpoint);
316
+ const query = defaults(
317
+ getSearchParams(this.issuer.end_session_endpoint),
304
318
  params,
305
319
  {
306
320
  post_logout_redirect_uri,
@@ -309,12 +323,15 @@ class BaseClient {
309
323
  { id_token_hint },
310
324
  );
311
325
 
312
- Object.entries(target.query).forEach(([key, value]) => {
326
+ Object.entries(query).forEach(([key, value]) => {
313
327
  if (value === null || value === undefined) {
314
- delete target.query[key];
328
+ delete query[key];
315
329
  }
316
330
  });
317
331
 
332
+ target.search = null;
333
+ target.query = query;
334
+
318
335
  return url.format(target);
319
336
  }
320
337
 
@@ -331,7 +348,7 @@ class BaseClient {
331
348
  if (isIncomingMessage) {
332
349
  switch (input.method) {
333
350
  case 'GET':
334
- return pickCb(url.parse(input.url, true).query);
351
+ return pickCb(getSearchParams(input.url));
335
352
  case 'POST':
336
353
  if (input.body === undefined) {
337
354
  throw new TypeError(
@@ -356,7 +373,7 @@ class BaseClient {
356
373
  throw new TypeError('invalid IncomingMessage method');
357
374
  }
358
375
  } else {
359
- return pickCb(url.parse(input, true).query);
376
+ return pickCb(getSearchParams(input));
360
377
  }
361
378
  }
362
379
 
@@ -703,11 +720,15 @@ class BaseClient {
703
720
  if (expectedAlg.match(/^(?:RSA|ECDH)/)) {
704
721
  const keystore = await keystores.get(this);
705
722
 
706
- for (const { keyObject: key } of keystore.all({
707
- ...jose.decodeProtectedHeader(jwe),
723
+ const protectedHeader = jose.decodeProtectedHeader(jwe);
724
+
725
+ for (const key of keystore.all({
726
+ ...protectedHeader,
708
727
  use: 'enc',
709
728
  })) {
710
- plaintext = await jose.compactDecrypt(jwe, key).then(getPlaintext, () => {});
729
+ plaintext = await jose
730
+ .compactDecrypt(jwe, await key.keyObject(protectedHeader.alg))
731
+ .then(getPlaintext, () => {});
711
732
  if (plaintext) break;
712
733
  }
713
734
  } else {
@@ -1016,7 +1037,13 @@ class BaseClient {
1016
1037
  assert(isPlainObject(payload.sub_jwk));
1017
1038
  const key = await jose.importJWK(payload.sub_jwk, header.alg);
1018
1039
  assert.equal(key.type, 'public');
1019
- keys = [{ keyObject: key }];
1040
+ keys = [
1041
+ {
1042
+ keyObject() {
1043
+ return key;
1044
+ },
1045
+ },
1046
+ ];
1020
1047
  } catch (err) {
1021
1048
  throw new RPError({
1022
1049
  message: 'failed to use sub_jwk claim as an asymmetric JSON Web Key',
@@ -1041,7 +1068,7 @@ class BaseClient {
1041
1068
 
1042
1069
  for (const key of keys) {
1043
1070
  const verified = await jose
1044
- .compactVerify(jwt, key instanceof Uint8Array ? key : key.keyObject)
1071
+ .compactVerify(jwt, key instanceof Uint8Array ? key : await key.keyObject(header.alg))
1045
1072
  .catch(() => {});
1046
1073
  if (verified) {
1047
1074
  return {
@@ -1195,12 +1222,12 @@ class BaseClient {
1195
1222
  targetUrl = this.issuer.mtls_endpoint_aliases.userinfo_endpoint;
1196
1223
  }
1197
1224
 
1198
- targetUrl = new url.URL(targetUrl || this.issuer.userinfo_endpoint);
1225
+ targetUrl = new URL(targetUrl || this.issuer.userinfo_endpoint);
1199
1226
 
1200
1227
  if (via === 'body') {
1201
1228
  options.headers.Authorization = undefined;
1202
1229
  options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
1203
- options.body = new url.URLSearchParams();
1230
+ options.body = new URLSearchParams();
1204
1231
  options.body.append(
1205
1232
  'access_token',
1206
1233
  accessToken instanceof TokenSet ? accessToken.access_token : accessToken,
@@ -1220,7 +1247,7 @@ class BaseClient {
1220
1247
  });
1221
1248
  } else {
1222
1249
  // POST && via header
1223
- options.body = new url.URLSearchParams();
1250
+ options.body = new URLSearchParams();
1224
1251
  options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
1225
1252
  Object.entries(params).forEach(([key, value]) => {
1226
1253
  options.body.append(key, value);
@@ -1515,7 +1542,7 @@ class BaseClient {
1515
1542
  ...header,
1516
1543
  kid: symmetric ? undefined : key.jwk.kid,
1517
1544
  })
1518
- .sign(symmetric ? key : key.keyObject);
1545
+ .sign(symmetric ? key : await key.keyObject(signingAlgorithm));
1519
1546
  }
1520
1547
 
1521
1548
  if (!eKeyManagement) {
@@ -1539,7 +1566,7 @@ class BaseClient {
1539
1566
  ...fields,
1540
1567
  kid: key instanceof Uint8Array ? undefined : key.jwk.kid,
1541
1568
  })
1542
- .encrypt(key instanceof Uint8Array ? key : key.keyObject);
1569
+ .encrypt(key instanceof Uint8Array ? key : await key.keyObject(fields.alg));
1543
1570
  }
1544
1571
 
1545
1572
  async pushedAuthorizationRequest(params = {}, { clientAssertionPayload } = {}) {
@@ -1625,33 +1652,18 @@ class BaseClient {
1625
1652
  let privateKey;
1626
1653
  if (isKeyObject(privateKeyInput)) {
1627
1654
  privateKey = privateKeyInput;
1628
- } else {
1655
+ } else if (privateKeyInput[Symbol.toStringTag] === 'CryptoKey') {
1656
+ privateKey = privateKeyInput;
1657
+ } else if (jose.cryptoRuntime === 'node:crypto') {
1629
1658
  privateKey = crypto.createPrivateKey(privateKeyInput);
1659
+ } else {
1660
+ throw new TypeError('unrecognized crypto runtime');
1630
1661
  }
1631
1662
 
1632
1663
  if (privateKey.type !== 'private') {
1633
1664
  throw new TypeError('"DPoP" option must be a private key');
1634
1665
  }
1635
- let alg;
1636
- switch (privateKey.asymmetricKeyType) {
1637
- case 'ed25519':
1638
- case 'ed448':
1639
- alg = 'EdDSA';
1640
- break;
1641
- case 'ec':
1642
- alg = determineEcAlgorithm(privateKey, privateKeyInput);
1643
- break;
1644
- case 'rsa':
1645
- case rsaPssParams && 'rsa-pss':
1646
- alg = determineRsaAlgorithm(
1647
- privateKey,
1648
- privateKeyInput,
1649
- this.issuer.dpop_signing_alg_values_supported,
1650
- );
1651
- break;
1652
- default:
1653
- throw new TypeError('unsupported DPoP private key asymmetric key type');
1654
- }
1666
+ let alg = determineDPoPAlgorithm.call(this, privateKey, privateKeyInput);
1655
1667
 
1656
1668
  if (!alg) {
1657
1669
  throw new TypeError('could not determine DPoP JWS Algorithm');
@@ -1674,81 +1686,138 @@ class BaseClient {
1674
1686
  }
1675
1687
  }
1676
1688
 
1677
- const RSPS = /^(?:RS|PS)(?:256|384|512)$/;
1678
- function determineRsaAlgorithm(privateKey, privateKeyInput, valuesSupported) {
1679
- if (
1680
- typeof privateKeyInput === 'object' &&
1681
- typeof privateKeyInput.key === 'object' &&
1682
- privateKeyInput.key.alg
1683
- ) {
1684
- return privateKeyInput.key.alg;
1689
+ function determineDPoPAlgorithmFromCryptoKey(cryptoKey) {
1690
+ switch (cryptoKey.algorithm.name) {
1691
+ case 'Ed25519':
1692
+ case 'Ed448':
1693
+ return 'EdDSA';
1694
+ case 'ECDSA': {
1695
+ switch (cryptoKey.algorithm.namedCurve) {
1696
+ case 'P-256':
1697
+ return 'ES256';
1698
+ case 'P-384':
1699
+ return 'ES384';
1700
+ case 'P-521':
1701
+ return 'ES512';
1702
+ default:
1703
+ break;
1704
+ }
1705
+ break;
1706
+ }
1707
+ case 'RSASSA-PKCS1-v1_5':
1708
+ return `RS${cryptoKey.algorithm.hash.name.slice(4)}`;
1709
+ case 'RSA-PSS':
1710
+ return `PS${cryptoKey.algorithm.hash.name.slice(4)}`;
1711
+ default:
1712
+ throw new TypeError('unsupported DPoP private key');
1685
1713
  }
1714
+ }
1686
1715
 
1687
- if (Array.isArray(valuesSupported)) {
1688
- let candidates = valuesSupported.filter(RegExp.prototype.test.bind(RSPS));
1689
- if (privateKey.asymmetricKeyType === 'rsa-pss') {
1690
- candidates = candidates.filter((value) => value.startsWith('PS'));
1716
+ let determineDPoPAlgorithm;
1717
+ if (jose.cryptoRuntime === 'node:crypto') {
1718
+ determineDPoPAlgorithm = function (privateKey, privateKeyInput) {
1719
+ if (privateKeyInput[Symbol.toStringTag] === 'CryptoKey') {
1720
+ return determineDPoPAlgorithmFromCryptoKey(privateKey);
1691
1721
  }
1692
- return ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS384'].find((preferred) =>
1693
- candidates.includes(preferred),
1694
- );
1695
- }
1696
1722
 
1697
- return 'PS256';
1698
- }
1723
+ switch (privateKey.asymmetricKeyType) {
1724
+ case 'ed25519':
1725
+ case 'ed448':
1726
+ return 'EdDSA';
1727
+ case 'ec':
1728
+ return determineEcAlgorithm(privateKey, privateKeyInput);
1729
+ case 'rsa':
1730
+ case rsaPssParams && 'rsa-pss':
1731
+ return determineRsaAlgorithm(
1732
+ privateKey,
1733
+ privateKeyInput,
1734
+ this.issuer.dpop_signing_alg_values_supported,
1735
+ );
1736
+ default:
1737
+ throw new TypeError('unsupported DPoP private key');
1738
+ }
1739
+ };
1699
1740
 
1700
- const p256 = Buffer.from([42, 134, 72, 206, 61, 3, 1, 7]);
1701
- const p384 = Buffer.from([43, 129, 4, 0, 34]);
1702
- const p521 = Buffer.from([43, 129, 4, 0, 35]);
1703
- const secp256k1 = Buffer.from([43, 129, 4, 0, 10]);
1741
+ const RSPS = /^(?:RS|PS)(?:256|384|512)$/;
1742
+ function determineRsaAlgorithm(privateKey, privateKeyInput, valuesSupported) {
1743
+ if (
1744
+ typeof privateKeyInput === 'object' &&
1745
+ privateKeyInput.format === 'jwk' &&
1746
+ privateKeyInput.key &&
1747
+ privateKeyInput.key.alg
1748
+ ) {
1749
+ return privateKeyInput.key.alg;
1750
+ }
1704
1751
 
1705
- function determineEcAlgorithm(privateKey, privateKeyInput) {
1706
- // If input was a JWK
1707
- switch (
1708
- typeof privateKeyInput === 'object' &&
1709
- typeof privateKeyInput.key === 'object' &&
1710
- privateKeyInput.key.crv
1711
- ) {
1712
- case 'P-256':
1752
+ if (Array.isArray(valuesSupported)) {
1753
+ let candidates = valuesSupported.filter(RegExp.prototype.test.bind(RSPS));
1754
+ if (privateKey.asymmetricKeyType === 'rsa-pss') {
1755
+ candidates = candidates.filter((value) => value.startsWith('PS'));
1756
+ }
1757
+ return ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS384'].find((preferred) =>
1758
+ candidates.includes(preferred),
1759
+ );
1760
+ }
1761
+
1762
+ return 'PS256';
1763
+ }
1764
+
1765
+ const p256 = Buffer.from([42, 134, 72, 206, 61, 3, 1, 7]);
1766
+ const p384 = Buffer.from([43, 129, 4, 0, 34]);
1767
+ const p521 = Buffer.from([43, 129, 4, 0, 35]);
1768
+ const secp256k1 = Buffer.from([43, 129, 4, 0, 10]);
1769
+
1770
+ function determineEcAlgorithm(privateKey, privateKeyInput) {
1771
+ // If input was a JWK
1772
+ switch (
1773
+ typeof privateKeyInput === 'object' &&
1774
+ typeof privateKeyInput.key === 'object' &&
1775
+ privateKeyInput.key.crv
1776
+ ) {
1777
+ case 'P-256':
1778
+ return 'ES256';
1779
+ case 'secp256k1':
1780
+ return 'ES256K';
1781
+ case 'P-384':
1782
+ return 'ES384';
1783
+ case 'P-512':
1784
+ return 'ES512';
1785
+ default:
1786
+ break;
1787
+ }
1788
+
1789
+ const buf = privateKey.export({ format: 'der', type: 'pkcs8' });
1790
+ const i = buf[1] < 128 ? 17 : 18;
1791
+ const len = buf[i];
1792
+ const curveOid = buf.slice(i + 1, i + 1 + len);
1793
+ if (curveOid.equals(p256)) {
1713
1794
  return 'ES256';
1714
- case 'secp256k1':
1715
- return 'ES256K';
1716
- case 'P-384':
1795
+ }
1796
+
1797
+ if (curveOid.equals(p384)) {
1717
1798
  return 'ES384';
1718
- case 'P-512':
1799
+ }
1800
+ if (curveOid.equals(p521)) {
1719
1801
  return 'ES512';
1720
- default:
1721
- break;
1722
- }
1723
-
1724
- const buf = privateKey.export({ format: 'der', type: 'pkcs8' });
1725
- const i = buf[1] < 128 ? 17 : 18;
1726
- const len = buf[i];
1727
- const curveOid = buf.slice(i + 1, i + 1 + len);
1728
- if (curveOid.equals(p256)) {
1729
- return 'ES256';
1730
- }
1802
+ }
1731
1803
 
1732
- if (curveOid.equals(p384)) {
1733
- return 'ES384';
1734
- }
1735
- if (curveOid.equals(p521)) {
1736
- return 'ES512';
1737
- }
1804
+ if (curveOid.equals(secp256k1)) {
1805
+ return 'ES256K';
1806
+ }
1738
1807
 
1739
- if (curveOid.equals(secp256k1)) {
1740
- return 'ES256K';
1808
+ throw new TypeError('unsupported DPoP private key curve');
1741
1809
  }
1742
-
1743
- throw new TypeError('unsupported DPoP private key curve');
1810
+ } else {
1811
+ determineDPoPAlgorithm = determineDPoPAlgorithmFromCryptoKey;
1744
1812
  }
1745
1813
 
1746
1814
  const jwkCache = new WeakMap();
1747
- async function getJwk(privateKey, privateKeyInput) {
1815
+ async function getJwk(keyObject, privateKeyInput) {
1748
1816
  if (
1817
+ jose.cryptoRuntime === 'node:crypto' &&
1749
1818
  typeof privateKeyInput === 'object' &&
1750
1819
  typeof privateKeyInput.key === 'object' &&
1751
- privateKeyInput.key.crv
1820
+ privateKeyInput.format === 'jwk'
1752
1821
  ) {
1753
1822
  return pick(privateKeyInput.key, 'kty', 'crv', 'x', 'y', 'e', 'n');
1754
1823
  }
@@ -1757,9 +1826,9 @@ async function getJwk(privateKey, privateKeyInput) {
1757
1826
  return jwkCache.get(privateKeyInput);
1758
1827
  }
1759
1828
 
1760
- const jwk = pick(await jose.exportJWK(privateKey), 'kty', 'crv', 'x', 'y', 'e', 'n');
1829
+ const jwk = pick(await jose.exportJWK(keyObject), 'kty', 'crv', 'x', 'y', 'e', 'n');
1761
1830
 
1762
- if (isKeyObject(privateKeyInput)) {
1831
+ if (isKeyObject(privateKeyInput) || jose.cryptoRuntime === 'WebCryptoAPI') {
1763
1832
  jwkCache.set(privateKeyInput, jwk);
1764
1833
  }
1765
1834
 
@@ -1776,4 +1845,5 @@ module.exports = (issuer, aadIssValidation = false) =>
1776
1845
  return issuer;
1777
1846
  }
1778
1847
  };
1848
+
1779
1849
  module.exports.BaseClient = BaseClient;
@@ -70,7 +70,7 @@ async function clientAssertion(endpoint, payload) {
70
70
 
71
71
  return new jose.CompactSign(Buffer.from(JSON.stringify(payload)))
72
72
  .setProtectedHeader({ alg, kid: key.jwk && key.jwk.kid })
73
- .sign(key.keyObject);
73
+ .sign(await key.keyObject(alg));
74
74
  }
75
75
 
76
76
  async function authFor(endpoint, { clientAssertionPayload } = {}) {
@@ -2,7 +2,6 @@ const jose = require('jose');
2
2
 
3
3
  const clone = require('./deep_clone');
4
4
  const isPlainObject = require('./is_plain_object');
5
- const isKeyObject = require('./is_key_object');
6
5
 
7
6
  const internal = Symbol();
8
7
 
@@ -51,7 +50,7 @@ function getKtyFromAlg(alg) {
51
50
 
52
51
  function getAlgorithms(use, alg, kty, crv) {
53
52
  // Ed25519, Ed448, and secp256k1 always have "alg"
54
- // OKP always has use
53
+ // OKP always has "use"
55
54
  if (alg) {
56
55
  return new Set([alg]);
57
56
  }
@@ -65,7 +64,20 @@ function getAlgorithms(use, alg, kty, crv) {
65
64
  }
66
65
 
67
66
  if (use === 'sig' || use === undefined) {
68
- algs = algs.concat([`ES${crv.slice(-3)}`.replace('21', '12')]);
67
+ switch (crv) {
68
+ case 'P-256':
69
+ case 'P-384':
70
+ algs = algs.concat([`ES${crv.slice(-3)}`.replace('21', '12')]);
71
+ break;
72
+ case 'P-521':
73
+ algs = algs.concat(['ES512']);
74
+ break;
75
+ case 'secp256k1':
76
+ if (jose.cryptoRuntime === 'node:crypto') {
77
+ algs = algs.concat(['ES256K']);
78
+ }
79
+ break;
80
+ }
69
81
  }
70
82
 
71
83
  return new Set(algs);
@@ -77,7 +89,10 @@ function getAlgorithms(use, alg, kty, crv) {
77
89
  let algs = [];
78
90
 
79
91
  if (use === 'enc' || use === undefined) {
80
- algs = algs.concat(['RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512', 'RSA1_5']);
92
+ algs = algs.concat(['RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512']);
93
+ if (jose.cryptoRuntime === 'node:crypto') {
94
+ algs = algs.concat(['RSA1_5']);
95
+ }
81
96
  }
82
97
 
83
98
  if (use === 'sig' || use === undefined) {
@@ -225,36 +240,25 @@ module.exports = class KeyStore {
225
240
  }
226
241
  }
227
242
 
228
- const keyObject = await jose.importJWK(jwk, alg || fauxAlg(jwk.kty)).catch(() => {});
229
-
230
- if (!keyObject) continue;
231
-
232
- if (keyObject instanceof Uint8Array || keyObject.type === 'secret') {
233
- if (onlyPrivate) {
234
- throw new Error('jwks must only contain private keys');
235
- }
236
- continue;
237
- }
238
-
239
- if (!isKeyObject(keyObject)) {
240
- throw new Error('what?!');
241
- }
242
-
243
- if (onlyPrivate && keyObject.type !== 'private') {
243
+ if (onlyPrivate && (jwk.kty === 'oct' || !jwk.d)) {
244
244
  throw new Error('jwks must only contain private keys');
245
245
  }
246
246
 
247
- if (onlyPublic && keyObject.type !== 'public') {
248
- continue;
249
- }
250
-
251
- if (kty === 'RSA' && keyObject.asymmetricKeySize < 2048) {
247
+ if (onlyPublic && (jwk.d || jwk.k)) {
252
248
  continue;
253
249
  }
254
250
 
255
251
  keys.push({
256
252
  jwk: { ...jwk, alg, use },
257
- keyObject,
253
+ async keyObject(alg) {
254
+ if (this[alg]) {
255
+ return this[alg];
256
+ }
257
+
258
+ const keyObject = await jose.importJWK(this.jwk, alg);
259
+ this[alg] = keyObject;
260
+ return keyObject;
261
+ },
258
262
  get algorithms() {
259
263
  Object.defineProperty(this, 'algorithms', {
260
264
  value: getAlgorithms(this.jwk.use, this.jwk.alg, this.jwk.kty, this.jwk.crv),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openid-client",
3
- "version": "5.5.0",
3
+ "version": "5.6.0",
4
4
  "description": "OpenID Connect Relying Party (RP, Client) implementation for Node.js runtime, supports passportjs",
5
5
  "keywords": [
6
6
  "auth",
@@ -45,23 +45,22 @@
45
45
  "test": "mocha test/**/*.test.js"
46
46
  },
47
47
  "dependencies": {
48
- "jose": "^4.14.4",
48
+ "jose": "^4.15.1",
49
49
  "lru-cache": "^6.0.0",
50
50
  "object-hash": "^2.2.0",
51
51
  "oidc-token-hash": "^5.0.3"
52
52
  },
53
53
  "devDependencies": {
54
- "@types/node": "^16.18.31",
55
- "@types/passport": "^1.0.12",
54
+ "@types/node": "^16.18.55",
55
+ "@types/passport": "^1.0.13",
56
56
  "base64url": "^3.0.1",
57
- "chai": "^4.3.7",
58
- "jose2": "npm:jose@^2.0.6",
57
+ "chai": "^4.3.10",
59
58
  "mocha": "^10.2.0",
60
- "nock": "^13.3.1",
59
+ "nock": "^13.3.3",
61
60
  "prettier": "^2.8.8",
62
61
  "readable-mock-req": "^0.2.2",
63
62
  "sinon": "^9.2.4",
64
- "timekeeper": "^2.2.0"
63
+ "timekeeper": "^2.3.1"
65
64
  },
66
65
  "standard-version": {
67
66
  "scripts": {