openid-client 5.4.2 → 5.5.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/README.md CHANGED
@@ -42,10 +42,10 @@ openid-client.
42
42
  - self_signed_tls_client_auth
43
43
  - [RFC9101 - OAuth 2.0 JWT-Secured Authorization Request (JAR)][feature-jar]
44
44
  - [RFC9126 - OAuth 2.0 Pushed Authorization Requests (PAR)][feature-par]
45
+ - [RFC9449 - OAuth 2.0 Demonstration of Proof-of-Possession at the Application Layer (DPoP)][feature-dpop]
45
46
  - [OpenID Connect RP-Initiated Logout 1.0][feature-rp-logout]
46
47
  - [Financial-grade API Security Profile 1.0 - Part 2: Advanced (FAPI)][feature-fapi]
47
48
  - [JWT Secured Authorization Response Mode for OAuth 2.0 (JARM)][feature-jarm]
48
- - [OAuth 2.0 Demonstration of Proof-of-Possession at the Application Layer (DPoP) - draft 04][feature-dpop]
49
49
  - [OAuth 2.0 Authorization Server Issuer Identification][feature-iss]
50
50
 
51
51
  Updates to draft specifications are released as MINOR library versions,
@@ -282,7 +282,7 @@ See [Customizing (docs)][documentation-customizing].
282
282
  [feature-rp-logout]: https://openid.net/specs/openid-connect-rpinitiated-1_0.html
283
283
  [feature-jarm]: https://openid.net/specs/oauth-v2-jarm.html
284
284
  [feature-fapi]: https://openid.net/specs/openid-financial-api-part-2-1_0.html
285
- [feature-dpop]: https://tools.ietf.org/html/draft-ietf-oauth-dpop-04
285
+ [feature-dpop]: https://www.rfc-editor.org/rfc/rfc9449.html
286
286
  [feature-par]: https://www.rfc-editor.org/rfc/rfc9126.html
287
287
  [feature-jar]: https://www.rfc-editor.org/rfc/rfc9101.html
288
288
  [feature-iss]: https://www.rfc-editor.org/rfc/rfc9207.html
package/lib/client.js CHANGED
@@ -1612,6 +1612,66 @@ class BaseClient {
1612
1612
  const { payload } = await this.validateJWT(response, expectedAlg, ['iss', 'exp', 'aud']);
1613
1613
  return pickCb(payload);
1614
1614
  }
1615
+
1616
+ /**
1617
+ * @name dpopProof
1618
+ * @api private
1619
+ */
1620
+ async dpopProof(payload, privateKeyInput, accessToken) {
1621
+ if (!isPlainObject(payload)) {
1622
+ throw new TypeError('payload must be a plain object');
1623
+ }
1624
+
1625
+ let privateKey;
1626
+ if (isKeyObject(privateKeyInput)) {
1627
+ privateKey = privateKeyInput;
1628
+ } else {
1629
+ privateKey = crypto.createPrivateKey(privateKeyInput);
1630
+ }
1631
+
1632
+ if (privateKey.type !== 'private') {
1633
+ throw new TypeError('"DPoP" option must be a private key');
1634
+ }
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
+ }
1655
+
1656
+ if (!alg) {
1657
+ throw new TypeError('could not determine DPoP JWS Algorithm');
1658
+ }
1659
+
1660
+ return new jose.SignJWT({
1661
+ ath: accessToken
1662
+ ? base64url.encode(crypto.createHash('sha256').update(accessToken).digest())
1663
+ : undefined,
1664
+ ...payload,
1665
+ })
1666
+ .setProtectedHeader({
1667
+ alg,
1668
+ typ: 'dpop+jwt',
1669
+ jwk: await getJwk(privateKey, privateKeyInput),
1670
+ })
1671
+ .setIssuedAt()
1672
+ .setJti(random())
1673
+ .sign(privateKey);
1674
+ }
1615
1675
  }
1616
1676
 
1617
1677
  const RSPS = /^(?:RS|PS)(?:256|384|512)$/;
@@ -1706,83 +1766,6 @@ async function getJwk(privateKey, privateKeyInput) {
1706
1766
  return jwk;
1707
1767
  }
1708
1768
 
1709
- /**
1710
- * @name dpopProof
1711
- * @api private
1712
- */
1713
- async function dpopProof(payload, privateKeyInput, accessToken) {
1714
- if (!isPlainObject(payload)) {
1715
- throw new TypeError('payload must be a plain object');
1716
- }
1717
-
1718
- let privateKey;
1719
- if (isKeyObject(privateKeyInput)) {
1720
- privateKey = privateKeyInput;
1721
- } else {
1722
- privateKey = crypto.createPrivateKey(privateKeyInput);
1723
- }
1724
-
1725
- if (privateKey.type !== 'private') {
1726
- throw new TypeError('"DPoP" option must be a private key');
1727
- }
1728
- let alg;
1729
- switch (privateKey.asymmetricKeyType) {
1730
- case 'ed25519':
1731
- case 'ed448':
1732
- alg = 'EdDSA';
1733
- break;
1734
- case 'ec':
1735
- alg = determineEcAlgorithm(privateKey, privateKeyInput);
1736
- break;
1737
- case 'rsa':
1738
- case rsaPssParams && 'rsa-pss':
1739
- alg = determineRsaAlgorithm(
1740
- privateKey,
1741
- privateKeyInput,
1742
- this.issuer.dpop_signing_alg_values_supported,
1743
- );
1744
- break;
1745
- default:
1746
- throw new TypeError('unsupported DPoP private key asymmetric key type');
1747
- }
1748
-
1749
- if (!alg) {
1750
- throw new TypeError('could not determine DPoP JWS Algorithm');
1751
- }
1752
-
1753
- return new jose.SignJWT({
1754
- ath: accessToken
1755
- ? base64url.encode(crypto.createHash('sha256').update(accessToken).digest())
1756
- : undefined,
1757
- ...payload,
1758
- })
1759
- .setProtectedHeader({
1760
- alg,
1761
- typ: 'dpop+jwt',
1762
- jwk: await getJwk(privateKey, privateKeyInput),
1763
- })
1764
- .setIssuedAt()
1765
- .setJti(random())
1766
- .sign(privateKey);
1767
- }
1768
-
1769
- Object.defineProperty(BaseClient.prototype, 'dpopProof', {
1770
- enumerable: true,
1771
- configurable: true,
1772
- value(...args) {
1773
- process.emitWarning(
1774
- 'The DPoP APIs implements an IETF draft (https://www.ietf.org/archive/id/draft-ietf-oauth-dpop-04.html). Breaking draft implementations are included as minor versions of the openid-client library, therefore, the ~ semver operator should be used and close attention be payed to library changelog as well as the drafts themselves.',
1775
- 'DraftWarning',
1776
- );
1777
- Object.defineProperty(BaseClient.prototype, 'dpopProof', {
1778
- enumerable: true,
1779
- configurable: true,
1780
- value: dpopProof,
1781
- });
1782
- return this.dpopProof(...args);
1783
- },
1784
- });
1785
-
1786
1769
  module.exports = (issuer, aadIssValidation = false) =>
1787
1770
  class Client extends BaseClient {
1788
1771
  constructor(...args) {
@@ -81,7 +81,7 @@ async function authFor(endpoint, { clientAssertionPayload } = {}) {
81
81
  case 'none':
82
82
  return { form: { client_id: this.client_id } };
83
83
  case 'client_secret_post':
84
- if (!this.client_secret) {
84
+ if (typeof this.client_secret !== 'string') {
85
85
  throw new TypeError(
86
86
  'client_secret_post client authentication method requires a client_secret',
87
87
  );
@@ -120,7 +120,7 @@ async function authFor(endpoint, { clientAssertionPayload } = {}) {
120
120
  // > Appendix B, and the encoded value is used as the username; the client
121
121
  // > password is encoded using the same algorithm and used as the
122
122
  // > password.
123
- if (!this.client_secret) {
123
+ if (typeof this.client_secret !== 'string') {
124
124
  throw new TypeError(
125
125
  'client_secret_basic client authentication method requires a client_secret',
126
126
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openid-client",
3
- "version": "5.4.2",
3
+ "version": "5.5.0",
4
4
  "description": "OpenID Connect Relying Party (RP, Client) implementation for Node.js runtime, supports passportjs",
5
5
  "keywords": [
6
6
  "auth",
@@ -45,19 +45,19 @@
45
45
  "test": "mocha test/**/*.test.js"
46
46
  },
47
47
  "dependencies": {
48
- "jose": "^4.14.1",
48
+ "jose": "^4.14.4",
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.24",
54
+ "@types/node": "^16.18.31",
55
55
  "@types/passport": "^1.0.12",
56
56
  "base64url": "^3.0.1",
57
57
  "chai": "^4.3.7",
58
58
  "jose2": "npm:jose@^2.0.6",
59
59
  "mocha": "^10.2.0",
60
- "nock": "^13.3.0",
60
+ "nock": "^13.3.1",
61
61
  "prettier": "^2.8.8",
62
62
  "readable-mock-req": "^0.2.2",
63
63
  "sinon": "^9.2.4",