oauth4webapi 2.0.5 → 2.1.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 +1 -1
- package/build/index.d.ts +47 -9
- package/build/index.js +95 -53
- package/package.json +3 -3
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.1.0/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.d.ts
CHANGED
|
@@ -45,31 +45,67 @@ export type ClientAuthenticationMethod = 'client_secret_basic' | 'client_secret_
|
|
|
45
45
|
/**
|
|
46
46
|
* Supported JWS `alg` Algorithm identifiers.
|
|
47
47
|
*
|
|
48
|
-
* @example CryptoKey algorithm for the `PS256` JWS Algorithm
|
|
48
|
+
* @example CryptoKey algorithm for the `PS256`, `PS384`, or `PS512` JWS Algorithm Identifiers
|
|
49
49
|
*
|
|
50
50
|
* ```ts
|
|
51
|
-
* interface
|
|
51
|
+
* interface RSAPSSAlgorithm extends RsaHashedKeyAlgorithm {
|
|
52
52
|
* name: 'RSA-PSS'
|
|
53
|
+
* hash: { name: 'SHA-256' | 'SHA-384' | 'SHA-512' }
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
56
|
+
* interface PS256 extends RSAPSSAlgorithm {
|
|
53
57
|
* hash: { name: 'SHA-256' }
|
|
54
58
|
* }
|
|
59
|
+
*
|
|
60
|
+
* interface PS384 extends RSAPSSAlgorithm {
|
|
61
|
+
* hash: { name: 'SHA-384' }
|
|
62
|
+
* }
|
|
63
|
+
*
|
|
64
|
+
* interface PS512 extends RSAPSSAlgorithm {
|
|
65
|
+
* hash: { name: 'SHA-512' }
|
|
66
|
+
* }
|
|
55
67
|
* ```
|
|
56
68
|
*
|
|
57
|
-
* @example CryptoKey algorithm for the `ES256` JWS Algorithm
|
|
69
|
+
* @example CryptoKey algorithm for the `ES256`, `ES384`, or `ES512` JWS Algorithm Identifiers
|
|
58
70
|
*
|
|
59
71
|
* ```ts
|
|
60
|
-
* interface
|
|
72
|
+
* interface ECDSAAlgorithm extends EcKeyAlgorithm {
|
|
61
73
|
* name: 'ECDSA'
|
|
74
|
+
* namedCurve: 'P-256' | 'P-384' | 'P-521'
|
|
75
|
+
* }
|
|
76
|
+
*
|
|
77
|
+
* interface ES256 extends ECDSAAlgorithm {
|
|
62
78
|
* namedCurve: 'P-256'
|
|
63
79
|
* }
|
|
80
|
+
*
|
|
81
|
+
* interface ES384 extends ECDSAAlgorithm {
|
|
82
|
+
* namedCurve: 'P-384'
|
|
83
|
+
* }
|
|
84
|
+
*
|
|
85
|
+
* interface ES512 extends ECDSAAlgorithm {
|
|
86
|
+
* namedCurve: 'P-521'
|
|
87
|
+
* }
|
|
64
88
|
* ```
|
|
65
89
|
*
|
|
66
|
-
* @example CryptoKey algorithm for the `RS256` JWS Algorithm
|
|
90
|
+
* @example CryptoKey algorithm for the `RS256`, `RS384`, or `RS512` JWS Algorithm Identifiers
|
|
67
91
|
*
|
|
68
92
|
* ```ts
|
|
69
|
-
* interface
|
|
93
|
+
* interface ECDSAAlgorithm extends RsaHashedKeyAlgorithm {
|
|
70
94
|
* name: 'RSASSA-PKCS1-v1_5'
|
|
95
|
+
* hash: { name: 'SHA-256' | 'SHA-384' | 'SHA-512' }
|
|
96
|
+
* }
|
|
97
|
+
*
|
|
98
|
+
* interface RS256 extends ECDSAAlgorithm {
|
|
71
99
|
* hash: { name: 'SHA-256' }
|
|
72
100
|
* }
|
|
101
|
+
*
|
|
102
|
+
* interface RS384 extends ECDSAAlgorithm {
|
|
103
|
+
* hash: { name: 'SHA-384' }
|
|
104
|
+
* }
|
|
105
|
+
*
|
|
106
|
+
* interface RS512 extends ECDSAAlgorithm {
|
|
107
|
+
* hash: { name: 'SHA-512' }
|
|
108
|
+
* }
|
|
73
109
|
* ```
|
|
74
110
|
*
|
|
75
111
|
* @example CryptoKey algorithm for the `EdDSA` JWS Algorithm Identifier (Experimental)
|
|
@@ -79,12 +115,12 @@ export type ClientAuthenticationMethod = 'client_secret_basic' | 'client_secret_
|
|
|
79
115
|
* widely adopted. If the proposal changes this implementation will follow up with a minor release.
|
|
80
116
|
*
|
|
81
117
|
* ```ts
|
|
82
|
-
* interface
|
|
83
|
-
* name: 'Ed25519'
|
|
118
|
+
* interface EdDSA extends KeyAlgorithm {
|
|
119
|
+
* name: 'Ed25519' | 'Ed448'
|
|
84
120
|
* }
|
|
85
121
|
* ```
|
|
86
122
|
*/
|
|
87
|
-
export type JWSAlgorithm = 'PS256' | 'ES256' | 'RS256' | 'EdDSA';
|
|
123
|
+
export type JWSAlgorithm = 'PS256' | 'ES256' | 'RS256' | 'EdDSA' | 'ES384' | 'PS384' | 'RS384' | 'ES512' | 'PS512' | 'RS512';
|
|
88
124
|
/**
|
|
89
125
|
* Authorization Server Metadata
|
|
90
126
|
*
|
|
@@ -1082,6 +1118,8 @@ export interface GenerateKeyPairOptions {
|
|
|
1082
1118
|
extractable?: boolean;
|
|
1083
1119
|
/** (RSA algorithms only) The length, in bits, of the RSA modulus. Default is `2048`. */
|
|
1084
1120
|
modulusLength?: number;
|
|
1121
|
+
/** (EdDSA algorithms only) The EdDSA sub-type. Default is `Ed25519`. */
|
|
1122
|
+
crv?: 'Ed25519' | 'Ed448';
|
|
1085
1123
|
}
|
|
1086
1124
|
/**
|
|
1087
1125
|
* Generates a CryptoKeyPair for a given JWS `alg` Algorithm identifier.
|
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.1.0';
|
|
5
5
|
USER_AGENT = `${NAME}/${VERSION}`;
|
|
6
6
|
}
|
|
7
7
|
const encoder = new TextEncoder();
|
|
@@ -113,7 +113,18 @@ function isPrivateKey(key) {
|
|
|
113
113
|
function isPublicKey(key) {
|
|
114
114
|
return isCryptoKey(key) && key.type === 'public';
|
|
115
115
|
}
|
|
116
|
-
const SUPPORTED_JWS_ALGS = [
|
|
116
|
+
const SUPPORTED_JWS_ALGS = [
|
|
117
|
+
'PS256',
|
|
118
|
+
'ES256',
|
|
119
|
+
'RS256',
|
|
120
|
+
'PS384',
|
|
121
|
+
'ES384',
|
|
122
|
+
'RS384',
|
|
123
|
+
'PS512',
|
|
124
|
+
'ES512',
|
|
125
|
+
'RS512',
|
|
126
|
+
'EdDSA',
|
|
127
|
+
];
|
|
117
128
|
function processDpopNonce(response) {
|
|
118
129
|
const url = new URL(response.url);
|
|
119
130
|
if (response.headers.has('dpop-nonce')) {
|
|
@@ -263,6 +274,10 @@ function psAlg(key) {
|
|
|
263
274
|
switch (key.algorithm.hash.name) {
|
|
264
275
|
case 'SHA-256':
|
|
265
276
|
return 'PS256';
|
|
277
|
+
case 'SHA-384':
|
|
278
|
+
return 'PS384';
|
|
279
|
+
case 'SHA-512':
|
|
280
|
+
return 'PS512';
|
|
266
281
|
default:
|
|
267
282
|
throw new UnsupportedOperationError('unsupported RsaHashedKeyAlgorithm hash name');
|
|
268
283
|
}
|
|
@@ -271,6 +286,10 @@ function rsAlg(key) {
|
|
|
271
286
|
switch (key.algorithm.hash.name) {
|
|
272
287
|
case 'SHA-256':
|
|
273
288
|
return 'RS256';
|
|
289
|
+
case 'SHA-384':
|
|
290
|
+
return 'RS384';
|
|
291
|
+
case 'SHA-512':
|
|
292
|
+
return 'RS512';
|
|
274
293
|
default:
|
|
275
294
|
throw new UnsupportedOperationError('unsupported RsaHashedKeyAlgorithm hash name');
|
|
276
295
|
}
|
|
@@ -279,11 +298,15 @@ function esAlg(key) {
|
|
|
279
298
|
switch (key.algorithm.namedCurve) {
|
|
280
299
|
case 'P-256':
|
|
281
300
|
return 'ES256';
|
|
301
|
+
case 'P-384':
|
|
302
|
+
return 'ES384';
|
|
303
|
+
case 'P-521':
|
|
304
|
+
return 'ES512';
|
|
282
305
|
default:
|
|
283
306
|
throw new UnsupportedOperationError('unsupported EcKeyAlgorithm namedCurve');
|
|
284
307
|
}
|
|
285
308
|
}
|
|
286
|
-
function
|
|
309
|
+
function keyToJws(key) {
|
|
287
310
|
switch (key.algorithm.name) {
|
|
288
311
|
case 'RSA-PSS':
|
|
289
312
|
return psAlg(key);
|
|
@@ -292,6 +315,7 @@ function determineJWSAlgorithm(key) {
|
|
|
292
315
|
case 'ECDSA':
|
|
293
316
|
return esAlg(key);
|
|
294
317
|
case 'Ed25519':
|
|
318
|
+
case 'Ed448':
|
|
295
319
|
return 'EdDSA';
|
|
296
320
|
default:
|
|
297
321
|
throw new UnsupportedOperationError('unsupported CryptoKey algorithm name');
|
|
@@ -314,7 +338,7 @@ function clientAssertion(as, client) {
|
|
|
314
338
|
}
|
|
315
339
|
async function privateKeyJwt(as, client, key, kid) {
|
|
316
340
|
return jwt({
|
|
317
|
-
alg:
|
|
341
|
+
alg: keyToJws(key),
|
|
318
342
|
kid,
|
|
319
343
|
}, clientAssertion(as, client), key);
|
|
320
344
|
}
|
|
@@ -398,7 +422,7 @@ async function jwt(header, claimsSet, key) {
|
|
|
398
422
|
throw new TypeError('CryptoKey instances used for signing assertions must include "sign" in their "usages"');
|
|
399
423
|
}
|
|
400
424
|
const input = `${b64u(buf(JSON.stringify(header)))}.${b64u(buf(JSON.stringify(claimsSet)))}`;
|
|
401
|
-
const signature = b64u(await crypto.subtle.sign(
|
|
425
|
+
const signature = b64u(await crypto.subtle.sign(keyToSubtle(key), key, buf(input)));
|
|
402
426
|
return `${input}.${signature}`;
|
|
403
427
|
}
|
|
404
428
|
export async function issueRequestObject(as, client, parameters, privateKey) {
|
|
@@ -445,7 +469,7 @@ export async function issueRequestObject(as, client, parameters, privateKey) {
|
|
|
445
469
|
}
|
|
446
470
|
}
|
|
447
471
|
return jwt({
|
|
448
|
-
alg:
|
|
472
|
+
alg: keyToJws(key),
|
|
449
473
|
typ: 'oauth-authz-req+jwt',
|
|
450
474
|
kid,
|
|
451
475
|
}, claims, key);
|
|
@@ -466,7 +490,7 @@ async function dpopProofJwt(headers, options, url, htm, accessToken) {
|
|
|
466
490
|
}
|
|
467
491
|
const now = epochTime();
|
|
468
492
|
const proof = await jwt({
|
|
469
|
-
alg:
|
|
493
|
+
alg: keyToJws(privateKey),
|
|
470
494
|
typ: 'dpop+jwt',
|
|
471
495
|
jwk: await publicJwk(publicKey),
|
|
472
496
|
}, {
|
|
@@ -707,7 +731,9 @@ async function getPublicSigKeyFromIssuerJwksUri(as, options, header) {
|
|
|
707
731
|
}
|
|
708
732
|
switch (true) {
|
|
709
733
|
case alg === 'ES256' && jwk.crv !== 'P-256':
|
|
710
|
-
case alg === '
|
|
734
|
+
case alg === 'ES384' && jwk.crv !== 'P-384':
|
|
735
|
+
case alg === 'ES512' && jwk.crv !== 'P-521':
|
|
736
|
+
case alg === 'EdDSA' && !(jwk.crv === 'Ed25519' || jwk.crv === 'Ed448'):
|
|
711
737
|
return false;
|
|
712
738
|
}
|
|
713
739
|
return true;
|
|
@@ -1210,19 +1236,43 @@ function checkRsaKeyAlgorithm(algorithm) {
|
|
|
1210
1236
|
throw new OPE(`${algorithm.name} modulusLength must be at least 2048 bits`);
|
|
1211
1237
|
}
|
|
1212
1238
|
}
|
|
1213
|
-
function
|
|
1239
|
+
function ecdsaHashName(namedCurve) {
|
|
1240
|
+
switch (namedCurve) {
|
|
1241
|
+
case 'P-256':
|
|
1242
|
+
return 'SHA-256';
|
|
1243
|
+
case 'P-384':
|
|
1244
|
+
return 'SHA-384';
|
|
1245
|
+
case 'P-521':
|
|
1246
|
+
return 'SHA-512';
|
|
1247
|
+
default:
|
|
1248
|
+
throw new UnsupportedOperationError();
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
function keyToSubtle(key) {
|
|
1214
1252
|
switch (key.algorithm.name) {
|
|
1215
1253
|
case 'ECDSA':
|
|
1216
|
-
return { name: key.algorithm.name, hash: { name: 'SHA-256' } };
|
|
1217
|
-
case 'RSA-PSS':
|
|
1218
|
-
checkRsaKeyAlgorithm(key.algorithm);
|
|
1219
1254
|
return {
|
|
1220
1255
|
name: key.algorithm.name,
|
|
1221
|
-
|
|
1256
|
+
hash: { name: ecdsaHashName(key.algorithm.namedCurve) },
|
|
1222
1257
|
};
|
|
1258
|
+
case 'RSA-PSS': {
|
|
1259
|
+
checkRsaKeyAlgorithm(key.algorithm);
|
|
1260
|
+
switch (key.algorithm.hash.name) {
|
|
1261
|
+
case 'SHA-256':
|
|
1262
|
+
case 'SHA-384':
|
|
1263
|
+
case 'SHA-512':
|
|
1264
|
+
return {
|
|
1265
|
+
name: key.algorithm.name,
|
|
1266
|
+
saltLength: parseInt(key.algorithm.hash.name.slice(-3), 10) >> 3,
|
|
1267
|
+
};
|
|
1268
|
+
default:
|
|
1269
|
+
throw new UnsupportedOperationError();
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1223
1272
|
case 'RSASSA-PKCS1-v1_5':
|
|
1224
1273
|
checkRsaKeyAlgorithm(key.algorithm);
|
|
1225
1274
|
return { name: key.algorithm.name };
|
|
1275
|
+
case 'Ed448':
|
|
1226
1276
|
case 'Ed25519':
|
|
1227
1277
|
return { name: key.algorithm.name };
|
|
1228
1278
|
}
|
|
@@ -1255,7 +1305,7 @@ async function validateJwt(jws, checkAlg, getKey) {
|
|
|
1255
1305
|
if (getKey !== noSignatureCheck) {
|
|
1256
1306
|
const key = await getKey(header);
|
|
1257
1307
|
const input = `${protectedHeader}.${payload}`;
|
|
1258
|
-
const verified = await crypto.subtle.verify(
|
|
1308
|
+
const verified = await crypto.subtle.verify(keyToSubtle(key), key, signature, buf(input));
|
|
1259
1309
|
if (!verified) {
|
|
1260
1310
|
throw new OPE('JWT signature verification failed');
|
|
1261
1311
|
}
|
|
@@ -1416,26 +1466,38 @@ export function validateAuthResponse(as, client, parameters, expectedState) {
|
|
|
1416
1466
|
}
|
|
1417
1467
|
return new CallbackParameters(parameters);
|
|
1418
1468
|
}
|
|
1419
|
-
|
|
1420
|
-
const { ext, key_ops, use, ...key } = jwk;
|
|
1421
|
-
let algorithm;
|
|
1469
|
+
function algToSubtle(alg, crv) {
|
|
1422
1470
|
switch (alg) {
|
|
1423
1471
|
case 'PS256':
|
|
1424
|
-
|
|
1425
|
-
|
|
1472
|
+
case 'PS384':
|
|
1473
|
+
case 'PS512':
|
|
1474
|
+
return { name: 'RSA-PSS', hash: { name: `SHA-${alg.slice(-3)}` } };
|
|
1426
1475
|
case 'RS256':
|
|
1427
|
-
|
|
1428
|
-
|
|
1476
|
+
case 'RS384':
|
|
1477
|
+
case 'RS512':
|
|
1478
|
+
return { name: 'RSASSA-PKCS1-v1_5', hash: { name: `SHA-${alg.slice(-3)}` } };
|
|
1429
1479
|
case 'ES256':
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
case '
|
|
1433
|
-
|
|
1434
|
-
|
|
1480
|
+
case 'ES384':
|
|
1481
|
+
return { name: 'ECDSA', namedCurve: `P-${alg.slice(-3)}` };
|
|
1482
|
+
case 'ES512':
|
|
1483
|
+
return { name: 'ECDSA', namedCurve: 'P-521' };
|
|
1484
|
+
case 'EdDSA': {
|
|
1485
|
+
switch (crv) {
|
|
1486
|
+
case 'Ed25519':
|
|
1487
|
+
return { name: 'Ed25519' };
|
|
1488
|
+
case 'Ed448':
|
|
1489
|
+
return { name: 'Ed448' };
|
|
1490
|
+
default:
|
|
1491
|
+
throw new UnsupportedOperationError();
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1435
1494
|
default:
|
|
1436
1495
|
throw new UnsupportedOperationError();
|
|
1437
1496
|
}
|
|
1438
|
-
|
|
1497
|
+
}
|
|
1498
|
+
async function importJwk(alg, jwk) {
|
|
1499
|
+
const { ext, key_ops, use, ...key } = jwk;
|
|
1500
|
+
return crypto.subtle.importKey('jwk', key, algToSubtle(alg, jwk.crv), true, ['verify']);
|
|
1439
1501
|
}
|
|
1440
1502
|
export async function deviceAuthorizationRequest(as, client, parameters, options) {
|
|
1441
1503
|
assertAs(as);
|
|
@@ -1512,35 +1574,15 @@ export async function processDeviceCodeResponse(as, client, response) {
|
|
|
1512
1574
|
return processGenericAccessTokenResponse(as, client, response);
|
|
1513
1575
|
}
|
|
1514
1576
|
export async function generateKeyPair(alg, options) {
|
|
1515
|
-
let algorithm;
|
|
1516
1577
|
if (!validateString(alg)) {
|
|
1517
1578
|
throw new TypeError('"alg" must be a non-empty string');
|
|
1518
1579
|
}
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
|
1526
|
-
};
|
|
1527
|
-
break;
|
|
1528
|
-
case 'RS256':
|
|
1529
|
-
algorithm = {
|
|
1530
|
-
name: 'RSASSA-PKCS1-v1_5',
|
|
1531
|
-
hash: { name: 'SHA-256' },
|
|
1532
|
-
modulusLength: options?.modulusLength ?? 2048,
|
|
1533
|
-
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
|
1534
|
-
};
|
|
1535
|
-
break;
|
|
1536
|
-
case 'ES256':
|
|
1537
|
-
algorithm = { name: 'ECDSA', namedCurve: 'P-256' };
|
|
1538
|
-
break;
|
|
1539
|
-
case 'EdDSA':
|
|
1540
|
-
algorithm = { name: 'Ed25519' };
|
|
1541
|
-
break;
|
|
1542
|
-
default:
|
|
1543
|
-
throw new UnsupportedOperationError();
|
|
1580
|
+
const algorithm = algToSubtle(alg, alg === 'EdDSA' ? options?.crv ?? 'Ed25519' : undefined);
|
|
1581
|
+
if (alg.startsWith('PS') || alg.startsWith('RS')) {
|
|
1582
|
+
Object.assign(algorithm, {
|
|
1583
|
+
modulusLength: options?.modulusLength ?? 2048,
|
|
1584
|
+
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
|
1585
|
+
});
|
|
1544
1586
|
}
|
|
1545
1587
|
return (crypto.subtle.generateKey(algorithm, options?.extractable ?? false, ['sign', 'verify']));
|
|
1546
1588
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oauth4webapi",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "OAuth 2 / OpenID Connect for Web Platform API JavaScript runtimes",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"auth",
|
|
@@ -66,8 +66,8 @@
|
|
|
66
66
|
"@types/node": "^18.11.9",
|
|
67
67
|
"@types/qunit": "^2.19.3",
|
|
68
68
|
"ava": "^5.1.0",
|
|
69
|
-
"edge-runtime": "^2.0.
|
|
70
|
-
"esbuild": "^0.
|
|
69
|
+
"edge-runtime": "^2.0.4",
|
|
70
|
+
"esbuild": "^0.17.0",
|
|
71
71
|
"jose": "^4.11.1",
|
|
72
72
|
"patch-package": "^6.5.0",
|
|
73
73
|
"prettier": "^2.8.0",
|