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 +2 -2
- package/lib/client.js +60 -77
- package/lib/helpers/client.js +2 -2
- package/package.json +4 -4
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://
|
|
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) {
|
package/lib/helpers/client.js
CHANGED
|
@@ -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 (
|
|
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 (
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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",
|