oauth4webapi 2.0.2 → 2.0.4
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 +1 -1
- package/build/index.js +35 -26
- package/package.json +8 -9
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ import * as oauth2 from 'oauth4webapi'
|
|
|
39
39
|
**`example`** Deno import
|
|
40
40
|
|
|
41
41
|
```js
|
|
42
|
-
import * as oauth2 from 'https://deno.land/x/oauth4webapi@v2.0.
|
|
42
|
+
import * as oauth2 from 'https://deno.land/x/oauth4webapi@v2.0.4/mod.ts'
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
- Authorization Code Flow - OpenID Connect [source](examples/code.ts), or plain OAuth 2 [source](examples/oauth.ts)
|
package/build/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
let USER_AGENT;
|
|
2
2
|
if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
|
|
3
3
|
const NAME = 'oauth4webapi';
|
|
4
|
-
const VERSION = 'v2.0.
|
|
4
|
+
const VERSION = 'v2.0.3';
|
|
5
5
|
USER_AGENT = `${NAME}/${VERSION}`;
|
|
6
6
|
}
|
|
7
7
|
const encoder = new TextEncoder();
|
|
@@ -114,10 +114,6 @@ function isPublicKey(key) {
|
|
|
114
114
|
return isCryptoKey(key) && key.type === 'public';
|
|
115
115
|
}
|
|
116
116
|
const SUPPORTED_JWS_ALGS = ['PS256', 'ES256', 'RS256', 'EdDSA'];
|
|
117
|
-
function preserveBodyStream(response) {
|
|
118
|
-
assertReadableResponse(response);
|
|
119
|
-
return response.clone();
|
|
120
|
-
}
|
|
121
117
|
function processDpopNonce(response) {
|
|
122
118
|
const url = new URL(response.url);
|
|
123
119
|
if (response.headers.has('dpop-nonce')) {
|
|
@@ -205,9 +201,10 @@ export async function processDiscoveryResponse(expectedIssuerIdentifier, respons
|
|
|
205
201
|
if (response.status !== 200) {
|
|
206
202
|
throw new OPE('"response" is not a conform Authorization Server Metadata response');
|
|
207
203
|
}
|
|
204
|
+
assertReadableResponse(response);
|
|
208
205
|
let json;
|
|
209
206
|
try {
|
|
210
|
-
json = await
|
|
207
|
+
json = await response.json();
|
|
211
208
|
}
|
|
212
209
|
catch {
|
|
213
210
|
throw new OPE('failed to parse "response" body as JSON');
|
|
@@ -484,13 +481,15 @@ async function dpopProofJwt(headers, options, url, htm, accessToken) {
|
|
|
484
481
|
}, privateKey);
|
|
485
482
|
headers.set('dpop', proof);
|
|
486
483
|
}
|
|
487
|
-
|
|
484
|
+
let jwkCache;
|
|
488
485
|
async function publicJwk(key) {
|
|
489
|
-
|
|
490
|
-
|
|
486
|
+
jwkCache || (jwkCache = new WeakMap());
|
|
487
|
+
if (jwkCache.has(key)) {
|
|
488
|
+
return jwkCache.get(key);
|
|
491
489
|
}
|
|
492
490
|
const { kty, e, n, x, y, crv } = await crypto.subtle.exportKey('jwk', key);
|
|
493
|
-
const jwk =
|
|
491
|
+
const jwk = { kty, e, n, x, y, crv };
|
|
492
|
+
jwkCache.set(key, jwk);
|
|
494
493
|
return jwk;
|
|
495
494
|
}
|
|
496
495
|
export async function pushedAuthorizationRequest(as, client, parameters, options) {
|
|
@@ -590,9 +589,10 @@ export async function processPushedAuthorizationResponse(as, client, response) {
|
|
|
590
589
|
}
|
|
591
590
|
throw new OPE('"response" is not a conform Pushed Authorization Request Endpoint response');
|
|
592
591
|
}
|
|
592
|
+
assertReadableResponse(response);
|
|
593
593
|
let json;
|
|
594
594
|
try {
|
|
595
|
-
json = await
|
|
595
|
+
json = await response.json();
|
|
596
596
|
}
|
|
597
597
|
catch {
|
|
598
598
|
throw new OPE('failed to parse "response" body as JSON');
|
|
@@ -648,30 +648,31 @@ export async function userInfoRequest(as, client, accessToken, options) {
|
|
|
648
648
|
}
|
|
649
649
|
return protectedResourceRequest(accessToken, 'GET', url, headers, null, options);
|
|
650
650
|
}
|
|
651
|
-
|
|
651
|
+
let jwksCache;
|
|
652
652
|
async function getPublicSigKeyFromIssuerJwksUri(as, options, header) {
|
|
653
653
|
const { alg, kid } = header;
|
|
654
654
|
checkSupportedJwsAlg(alg);
|
|
655
655
|
let jwks;
|
|
656
656
|
let age;
|
|
657
|
-
|
|
657
|
+
jwksCache || (jwksCache = new WeakMap());
|
|
658
|
+
if (jwksCache.has(as)) {
|
|
658
659
|
;
|
|
659
|
-
({ jwks, age } = as
|
|
660
|
+
({ jwks, age } = jwksCache.get(as));
|
|
660
661
|
if (age >= 300) {
|
|
661
|
-
as
|
|
662
|
+
jwksCache.delete(as);
|
|
662
663
|
return getPublicSigKeyFromIssuerJwksUri(as, options, header);
|
|
663
664
|
}
|
|
664
665
|
}
|
|
665
666
|
else {
|
|
666
667
|
jwks = await jwksRequest(as, options).then(processJwksResponse);
|
|
667
668
|
age = 0;
|
|
668
|
-
as
|
|
669
|
+
jwksCache.set(as, {
|
|
669
670
|
jwks,
|
|
670
671
|
iat: epochTime(),
|
|
671
672
|
get age() {
|
|
672
673
|
return epochTime() - this.iat;
|
|
673
674
|
},
|
|
674
|
-
};
|
|
675
|
+
});
|
|
675
676
|
}
|
|
676
677
|
let kty;
|
|
677
678
|
switch (alg.slice(0, 2)) {
|
|
@@ -714,7 +715,7 @@ async function getPublicSigKeyFromIssuerJwksUri(as, options, header) {
|
|
|
714
715
|
const { 0: jwk, length } = candidates;
|
|
715
716
|
if (!length) {
|
|
716
717
|
if (age >= 60) {
|
|
717
|
-
as
|
|
718
|
+
jwksCache.delete(as);
|
|
718
719
|
return getPublicSigKeyFromIssuerJwksUri(as, options, header);
|
|
719
720
|
}
|
|
720
721
|
throw new OPE('error when selecting a JWT verification key, no applicable keys found');
|
|
@@ -743,7 +744,8 @@ export async function processUserInfoResponse(as, client, expectedSubject, respo
|
|
|
743
744
|
}
|
|
744
745
|
let json;
|
|
745
746
|
if (getContentType(response) === 'application/jwt') {
|
|
746
|
-
|
|
747
|
+
assertReadableResponse(response);
|
|
748
|
+
const { claims } = await validateJwt(await response.text(), checkSigningAlgorithm.bind(undefined, client.userinfo_signed_response_alg, as.userinfo_signing_alg_values_supported), noSignatureCheck)
|
|
747
749
|
.then(validateOptionalAudience.bind(undefined, client.client_id))
|
|
748
750
|
.then(validateOptionalIssuer.bind(undefined, as.issuer));
|
|
749
751
|
json = claims;
|
|
@@ -752,8 +754,9 @@ export async function processUserInfoResponse(as, client, expectedSubject, respo
|
|
|
752
754
|
if (client.userinfo_signed_response_alg) {
|
|
753
755
|
throw new OPE('JWT UserInfo Response expected');
|
|
754
756
|
}
|
|
757
|
+
assertReadableResponse(response);
|
|
755
758
|
try {
|
|
756
|
-
json = await
|
|
759
|
+
json = await response.json();
|
|
757
760
|
}
|
|
758
761
|
catch {
|
|
759
762
|
throw new OPE('failed to parse "response" body as JSON');
|
|
@@ -832,9 +835,10 @@ async function processGenericAccessTokenResponse(as, client, response, ignoreIdT
|
|
|
832
835
|
}
|
|
833
836
|
throw new OPE('"response" is not a conform Token Endpoint response');
|
|
834
837
|
}
|
|
838
|
+
assertReadableResponse(response);
|
|
835
839
|
let json;
|
|
836
840
|
try {
|
|
837
|
-
json = await
|
|
841
|
+
json = await response.json();
|
|
838
842
|
}
|
|
839
843
|
catch {
|
|
840
844
|
throw new OPE('failed to parse "response" body as JSON');
|
|
@@ -1100,7 +1104,8 @@ export async function processIntrospectionResponse(as, client, response) {
|
|
|
1100
1104
|
}
|
|
1101
1105
|
let json;
|
|
1102
1106
|
if (getContentType(response) === 'application/token-introspection+jwt') {
|
|
1103
|
-
|
|
1107
|
+
assertReadableResponse(response);
|
|
1108
|
+
const { claims } = await validateJwt(await response.text(), checkSigningAlgorithm.bind(undefined, client.introspection_signed_response_alg, as.introspection_signing_alg_values_supported), noSignatureCheck)
|
|
1104
1109
|
.then(checkJwtType.bind(undefined, 'token-introspection+jwt'))
|
|
1105
1110
|
.then(validatePresence.bind(undefined, ['aud', 'iat', 'iss']))
|
|
1106
1111
|
.then(validateIssuer.bind(undefined, as.issuer))
|
|
@@ -1111,8 +1116,9 @@ export async function processIntrospectionResponse(as, client, response) {
|
|
|
1111
1116
|
}
|
|
1112
1117
|
}
|
|
1113
1118
|
else {
|
|
1119
|
+
assertReadableResponse(response);
|
|
1114
1120
|
try {
|
|
1115
|
-
json = await
|
|
1121
|
+
json = await response.json();
|
|
1116
1122
|
}
|
|
1117
1123
|
catch {
|
|
1118
1124
|
throw new OPE('failed to parse "response" body as JSON');
|
|
@@ -1149,9 +1155,10 @@ async function processJwksResponse(response) {
|
|
|
1149
1155
|
if (response.status !== 200) {
|
|
1150
1156
|
throw new OPE('"response" is not a conform JSON Web Key Set response');
|
|
1151
1157
|
}
|
|
1158
|
+
assertReadableResponse(response);
|
|
1152
1159
|
let json;
|
|
1153
1160
|
try {
|
|
1154
|
-
json = await
|
|
1161
|
+
json = await response.json();
|
|
1155
1162
|
}
|
|
1156
1163
|
catch {
|
|
1157
1164
|
throw new OPE('failed to parse "response" body as JSON');
|
|
@@ -1169,8 +1176,9 @@ async function processJwksResponse(response) {
|
|
|
1169
1176
|
}
|
|
1170
1177
|
async function handleOAuthBodyError(response) {
|
|
1171
1178
|
if (response.status > 399 && response.status < 500) {
|
|
1179
|
+
assertReadableResponse(response);
|
|
1172
1180
|
try {
|
|
1173
|
-
const json = await
|
|
1181
|
+
const json = await response.json();
|
|
1174
1182
|
if (isJsonObject(json) && typeof json.error === 'string' && json.error.length) {
|
|
1175
1183
|
if (json.error_description !== undefined && typeof json.error_description !== 'string') {
|
|
1176
1184
|
delete json.error_description;
|
|
@@ -1458,9 +1466,10 @@ export async function processDeviceAuthorizationResponse(as, client, response) {
|
|
|
1458
1466
|
}
|
|
1459
1467
|
throw new OPE('"response" is not a conform Device Authorization Endpoint response');
|
|
1460
1468
|
}
|
|
1469
|
+
assertReadableResponse(response);
|
|
1461
1470
|
let json;
|
|
1462
1471
|
try {
|
|
1463
|
-
json = await
|
|
1472
|
+
json = await response.json();
|
|
1464
1473
|
}
|
|
1465
1474
|
catch {
|
|
1466
1475
|
throw new OPE('failed to parse "response" body as JSON');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oauth4webapi",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.4",
|
|
4
4
|
"description": "OAuth 2 / OpenID Connect for Web Platform API JavaScript runtimes",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"auth",
|
|
@@ -52,7 +52,6 @@
|
|
|
52
52
|
"docs": "patch-package && typedoc",
|
|
53
53
|
"format": "npm run _format -- --write",
|
|
54
54
|
"format-check": "npm run _format -- --check",
|
|
55
|
-
"prepack": "npm run format && npm run docs && ./examples/.update-diffs.sh && git diff --quiet && npm run test && npm run build",
|
|
56
55
|
"tap:browsers": "./tap/.browsers.sh",
|
|
57
56
|
"tap:bun": "./tap/.bun.sh",
|
|
58
57
|
"tap:deno": "./tap/.deno.sh",
|
|
@@ -63,21 +62,21 @@
|
|
|
63
62
|
"test": "bash -c 'source .node_flags.sh && ava'"
|
|
64
63
|
},
|
|
65
64
|
"devDependencies": {
|
|
66
|
-
"@esbuild-kit/esm-loader": "^2.5.
|
|
65
|
+
"@esbuild-kit/esm-loader": "^2.5.1",
|
|
67
66
|
"@types/node": "^18.11.9",
|
|
68
67
|
"@types/qunit": "^2.19.3",
|
|
69
68
|
"ava": "^5.1.0",
|
|
70
69
|
"edge-runtime": "^2.0.2",
|
|
71
|
-
"esbuild": "^0.15.
|
|
72
|
-
"jose": "^4.11.
|
|
70
|
+
"esbuild": "^0.15.15",
|
|
71
|
+
"jose": "^4.11.1",
|
|
73
72
|
"patch-package": "^6.5.0",
|
|
74
|
-
"prettier": "^2.
|
|
73
|
+
"prettier": "^2.8.0",
|
|
75
74
|
"prettier-plugin-jsdoc": "^0.4.2",
|
|
76
75
|
"qunit": "^2.19.3",
|
|
77
76
|
"timekeeper": "^2.2.0",
|
|
78
|
-
"typedoc": "^0.23.
|
|
77
|
+
"typedoc": "^0.23.21",
|
|
79
78
|
"typedoc-plugin-markdown": "^3.13.6",
|
|
80
|
-
"typescript": "^4.
|
|
81
|
-
"undici": "^5.
|
|
79
|
+
"typescript": "^4.9.3",
|
|
80
|
+
"undici": "^5.13.0"
|
|
82
81
|
}
|
|
83
82
|
}
|