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 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.5/mod.ts'
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 Identifier
48
+ * @example CryptoKey algorithm for the `PS256`, `PS384`, or `PS512` JWS Algorithm Identifiers
49
49
  *
50
50
  * ```ts
51
- * interface Ps256Algorithm extends RsaHashedKeyAlgorithm {
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 Identifier
69
+ * @example CryptoKey algorithm for the `ES256`, `ES384`, or `ES512` JWS Algorithm Identifiers
58
70
  *
59
71
  * ```ts
60
- * interface Es256Algorithm extends EcKeyAlgorithm {
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 Identifier
90
+ * @example CryptoKey algorithm for the `RS256`, `RS384`, or `RS512` JWS Algorithm Identifiers
67
91
  *
68
92
  * ```ts
69
- * interface Rs256Algorithm extends RsaHashedKeyAlgorithm {
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 EdDSAAlgorithm extends KeyAlgorithm {
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';
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 = ['PS256', 'ES256', 'RS256', 'EdDSA'];
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 determineJWSAlgorithm(key) {
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: determineJWSAlgorithm(key),
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(subtleAlgorithm(key), key, buf(input)));
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: determineJWSAlgorithm(key),
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: determineJWSAlgorithm(privateKey),
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 === 'EdDSA' && jwk.crv !== 'Ed25519':
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 subtleAlgorithm(key) {
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
- saltLength: 256 >> 3,
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(subtleAlgorithm(key), key, signature, buf(input));
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
- async function importJwk(alg, jwk) {
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
- algorithm = { name: 'RSA-PSS', hash: { name: 'SHA-256' } };
1425
- break;
1472
+ case 'PS384':
1473
+ case 'PS512':
1474
+ return { name: 'RSA-PSS', hash: { name: `SHA-${alg.slice(-3)}` } };
1426
1475
  case 'RS256':
1427
- algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-256' } };
1428
- break;
1476
+ case 'RS384':
1477
+ case 'RS512':
1478
+ return { name: 'RSASSA-PKCS1-v1_5', hash: { name: `SHA-${alg.slice(-3)}` } };
1429
1479
  case 'ES256':
1430
- algorithm = { name: 'ECDSA', namedCurve: 'P-256' };
1431
- break;
1432
- case 'EdDSA':
1433
- algorithm = { name: 'Ed25519' };
1434
- break;
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
- return crypto.subtle.importKey('jwk', key, algorithm, true, ['verify']);
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
- switch (alg) {
1520
- case 'PS256':
1521
- algorithm = {
1522
- name: 'RSA-PSS',
1523
- hash: { name: 'SHA-256' },
1524
- modulusLength: options?.modulusLength ?? 2048,
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.5",
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.2",
70
- "esbuild": "^0.16.1",
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",