@logto/connector-apple 1.0.1 → 1.0.3

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.
Files changed (4) hide show
  1. package/LICENSE +0 -6
  2. package/README.md +1 -71
  3. package/lib/index.js +187 -480
  4. package/package.json +4 -4
package/LICENSE CHANGED
@@ -1,9 +1,3 @@
1
- Portions of this software are licensed as follows:
2
-
3
- * All content that resides under the "packages/cloud" directory of this repository, if that directory exists, is licensed under the license defined in "packages/cloud/LICENSE" (Elastic-2.0).
4
- * All third party components incorporated into this software are licensed under the original license provided by the owner of the applicable component.
5
- * Content outside of the above mentioned directories or restrictions above is available under the "MPL-2.0" license as defined below.
6
-
7
1
  Mozilla Public License Version 2.0
8
2
  ==================================
9
3
 
package/README.md CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  The official Logto connector for Apple social sign-in.
4
4
 
5
- Apple 社交登录 Logto 官方连接器 [中文文档](#apple-连接器)
6
-
7
5
  **Table of contents**
8
6
 
9
7
  - [Apple connector](#apple-connector)
@@ -12,12 +10,6 @@ Apple 社交登录 Logto 官方连接器 [中文文档](#apple-连接器)
12
10
  - [Create an identifier](#create-an-identifier)
13
11
  - [Enable Sign in with Apple for your identifier](#enable-sign-in-with-apple-for-your-identifier)
14
12
  - [Test Apple connector](#test-apple-connector)
15
- - [Apple 连接器](#apple-连接器)
16
- - [开始上手](#开始上手)
17
- - [为你的应用启用「通过 Apple 登录」](#为你的应用启用通过-apple-登录)
18
- - [创建一个 identifier](#创建一个-identifier)
19
- - [为你的 identifier 启用「通过 Apple 登录」](#为你的-identifier-启用通过-apple-登录)
20
- - [测试 Apple 连接器](#测试-apple-连接器)
21
13
 
22
14
  ## Get started
23
15
 
@@ -77,66 +69,4 @@ Click "Next" then "Done" to close the modal. Click "Continue" on the top-right c
77
69
 
78
70
  ## Test Apple connector
79
71
 
80
- That's it. The Apple connector should be available in both web and native apps. Don't forget to [Enable connector in sign-in experience](https://docs.logto.io/docs/tutorials/get-started/enable-social-sign-in#enable-connector-in-sign-in-experience).
81
-
82
- # Apple 连接器
83
-
84
- ## 开始上手
85
-
86
- 如果你还不知道连接器的概念,或者还不知道如何将本连接器添加至你的「登录体验」,请先参见 [Logto 教程](https://docs.logto.io/zh-cn/docs/tutorials/get-started/enable-social-sign-in)。
87
-
88
- > ℹ️ **Note**
89
- >
90
- > 如果你的应用有其他的社交登录方式,AppStore 要求必须同时有 Apple 登录。
91
- > 如果同时提供 Android 应用,在 Android 设备上同时提供 Apple 登录会让用户体验很棒。
92
-
93
- 在继续前,你需要加入 [Apple Developer Program](https://developer.apple.com/programs/)。
94
-
95
- ### 为你的应用启用「通过 Apple 登录」
96
-
97
- > ⚠️ **Caution**
98
- >
99
- > 即使你只想在 web 应用中实现「通过 Apple 登录」,你仍需要拥有一个拥抱 AppStore 生态的应用(即:有一个有效的 App ID)。
100
-
101
- 你可以通过 Xcode -> Project settings -> Signing & Capabilities 来启用,或者访问 [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources/identifiers/list/bundleId)。
102
-
103
- ![Enable Sign in with Apple](/packages/connector-apple/docs/enable-sign-in-with-apple-in-xcode.png)
104
-
105
- 参见 [Apple 官方文档](https://developer.apple.com/documentation/sign_in_with_apple/configuring_your_environment_for_sign_in_with_apple) 里的「Enable an App ID」章节以了解更多。
106
-
107
- ### 创建一个 identifier
108
-
109
- 1. 访问 [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources/identifiers/list/serviceId),并点按在「Identifier」旁边的「+」按钮。
110
- 2. 在「Register a new identifier」页面,选择「Services IDs」并点按「Continue」。
111
- 3. 填写「Description」与「Identifier」(例如 `Logto Test` 和 `io.logto.test`),并点按「Continue」。
112
- 4. 再次检查相关信息并点按「Register」。
113
-
114
- ### 为你的 identifier 启用「通过 Apple 登录」
115
-
116
- 点按你刚刚创建的 identifier。在详情页勾选「Sign in with Apple」并点按「Configure」。
117
-
118
- ![Enable Sign in with Apple](/packages/connector-apple/docs/enable-sign-in-with-apple.png)
119
-
120
- 在打开的对话框中,选择刚刚启用了「通过 Apple 登录」的 App ID。
121
-
122
- 输入你的 Logto 实例域名(不含协议和端口),例如 `your.logto.domain`;并输入「Return URL」(即 Redirect URI)。Return URL 的值是 Logto URL 加上 `/callback/${connector_id}`,例如 `https://your.logto.domain/callback/apple-universal`。在管理控制台创建了 Apple 连接器之后,在详情页可以找到生成的随机 `connector_id`。
123
-
124
- ![domain-and-url](/packages/connector-apple/docs/domain-and-url.png)
125
-
126
- 点按「Next」以及「Done」以关闭对话框。点按右上角的「Continue」,接着点按「Save」以保存你的配置。
127
-
128
- > ⚠️ **Caution**
129
- >
130
- > Apple _不允许_ HTTP 协议或 `localhost` 域名作为 Return URL。
131
- >
132
- > 如果你想在本地进行测试,你需要编辑 `/etc/hosts` 文件以映射 localhost 到一个自定义域名,并设置一个本地的 HTTPS 环境。[mkcert](https://github.com/FiloSottile/mkcert) 可以帮助你设置本地 HTTPS。
133
-
134
- > ℹ️ **Note**
135
- >
136
- > 本连接器暂时不支持自定义 `scope`(例如 name,email)。因为在 `scope` 非空时,Apple 要求 `response_mode` 为 `form_post`,与现在连接器的设计不兼容。
137
- >
138
- > 我们将稍后解决这个问题。
139
-
140
- ## 测试 Apple 连接器
141
-
142
- 大功告成。Apple 连接器应该在 web 和原生应用中都可用了。别忘了 [在登录体验中启用本连接器](https://docs.logto.io/zh-cn/docs/tutorials/get-started/enable-social-sign-in/#%E5%9C%A8%E7%99%BB%E5%BD%95%E4%BD%93%E9%AA%8C%E4%B8%AD%E5%90%AF%E7%94%A8%E8%BF%9E%E6%8E%A5%E5%99%A8)。
72
+ That's it. The Apple connector should be available in both web and native apps. Don't forget to [Enable connector in sign-in experience](https://docs.logto.io/docs/tutorials/get-started/passwordless-sign-in-by-adding-connectors#enable-social-sign-in).
package/lib/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { ConnectorPlatform, ConnectorConfigFormItemType, ConnectorType, validateConfig, ConnectorError, ConnectorErrorCodes } from '@logto/connector-kit';
2
- import * as crypto from 'crypto';
3
- import { randomFillSync, KeyObject, createPublicKey, createPrivateKey, createSecretKey, constants } from 'crypto';
2
+ import * as crypto from 'node:crypto';
3
+ import crypto__default, { KeyObject, createPrivateKey, createPublicKey, constants, createSecretKey } from 'node:crypto';
4
4
  import { z } from 'zod';
5
- import { Buffer as Buffer$1 } from 'buffer';
6
- import * as util from 'util';
7
- import { promisify } from 'util';
8
- import * as http from 'http';
9
- import * as https from 'https';
10
- import { once } from 'events';
5
+ import * as http from 'node:http';
6
+ import * as https from 'node:https';
7
+ import { once } from 'node:events';
8
+ import { Buffer as Buffer$1 } from 'node:buffer';
9
+ import * as util from 'node:util';
10
+ import { promisify } from 'node:util';
11
11
 
12
12
  // https://github.com/facebook/jest/issues/7547
13
13
  const assert = (value, error) => {
@@ -20,22 +20,22 @@ const assert = (value, error) => {
20
20
 
21
21
  const POOL_SIZE_MULTIPLIER = 128;
22
22
  let pool, poolOffset;
23
- let fillPool = bytes => {
23
+ function fillPool(bytes) {
24
24
  if (!pool || pool.length < bytes) {
25
25
  pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
26
- randomFillSync(pool);
26
+ crypto__default.getRandomValues(pool);
27
27
  poolOffset = 0;
28
28
  } else if (poolOffset + bytes > pool.length) {
29
- randomFillSync(pool);
29
+ crypto__default.getRandomValues(pool);
30
30
  poolOffset = 0;
31
31
  }
32
32
  poolOffset += bytes;
33
- };
34
- let random = bytes => {
33
+ }
34
+ function random(bytes) {
35
35
  fillPool((bytes -= 0));
36
36
  return pool.subarray(poolOffset - bytes, poolOffset)
37
- };
38
- let customRandom = (alphabet, defaultSize, getRandom) => {
37
+ }
38
+ function customRandom(alphabet, defaultSize, getRandom) {
39
39
  let mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1;
40
40
  let step = Math.ceil((1.6 * mask * defaultSize) / alphabet.length);
41
41
  return (size = defaultSize) => {
@@ -49,14 +49,33 @@ let customRandom = (alphabet, defaultSize, getRandom) => {
49
49
  }
50
50
  }
51
51
  }
52
- };
53
- let customAlphabet = (alphabet, size = 21) =>
54
- customRandom(alphabet, size, random);
52
+ }
53
+ function customAlphabet(alphabet, size = 21) {
54
+ return customRandom(alphabet, size, random)
55
+ }
55
56
 
56
57
  const lowercaseAlphabet = '0123456789abcdefghijklmnopqrstuvwxyz';
57
58
  const alphabet = `${lowercaseAlphabet}ABCDEFGHIJKLMNOPQRSTUVWXYZ`;
58
- const buildIdGenerator = (size, includingUppercase = false) => customAlphabet(includingUppercase ? alphabet : lowercaseAlphabet, size);
59
- const generateStandardId = buildIdGenerator(21);
59
+ const buildIdGenerator = (size, includingUppercase = true) => customAlphabet(includingUppercase ? alphabet : lowercaseAlphabet, size);
60
+ /**
61
+ * Generate a standard id with 21 characters, including lowercase letters and numbers.
62
+ *
63
+ * @see {@link lowercaseAlphabet}
64
+ */
65
+ const generateStandardId = buildIdGenerator(21, false);
66
+ /**
67
+ * Generate a standard short id with 12 characters, including lowercase letters and numbers.
68
+ *
69
+ * @see {@link lowercaseAlphabet}
70
+ */
71
+ buildIdGenerator(12, false);
72
+ /**
73
+ * Generate a standard secret with 32 characters, including uppercase letters, lowercase
74
+ * letters, and numbers.
75
+ *
76
+ * @see {@link alphabet}
77
+ */
78
+ buildIdGenerator(32);
60
79
 
61
80
  const encoder = new TextEncoder();
62
81
  const decoder = new TextDecoder();
@@ -78,141 +97,109 @@ function normalize(input) {
78
97
  }
79
98
  return encoded;
80
99
  }
81
- if (Buffer$1.isEncoding('base64url')) ;
82
- const decode = (input) => Buffer$1.from(normalize(input), 'base64');
100
+ const decode = (input) => new Uint8Array(Buffer$1.from(normalize(input), 'base64'));
83
101
 
84
102
  class JOSEError extends Error {
103
+ static get code() {
104
+ return 'ERR_JOSE_GENERIC';
105
+ }
106
+ code = 'ERR_JOSE_GENERIC';
85
107
  constructor(message) {
86
- var _a;
87
108
  super(message);
88
- this.code = 'ERR_JOSE_GENERIC';
89
109
  this.name = this.constructor.name;
90
- (_a = Error.captureStackTrace) === null || _a === void 0 ? void 0 : _a.call(Error, this, this.constructor);
91
- }
92
- static get code() {
93
- return 'ERR_JOSE_GENERIC';
110
+ Error.captureStackTrace?.(this, this.constructor);
94
111
  }
95
112
  }
96
113
  class JWTClaimValidationFailed extends JOSEError {
114
+ static get code() {
115
+ return 'ERR_JWT_CLAIM_VALIDATION_FAILED';
116
+ }
117
+ code = 'ERR_JWT_CLAIM_VALIDATION_FAILED';
118
+ claim;
119
+ reason;
97
120
  constructor(message, claim = 'unspecified', reason = 'unspecified') {
98
121
  super(message);
99
- this.code = 'ERR_JWT_CLAIM_VALIDATION_FAILED';
100
122
  this.claim = claim;
101
123
  this.reason = reason;
102
124
  }
103
- static get code() {
104
- return 'ERR_JWT_CLAIM_VALIDATION_FAILED';
105
- }
106
125
  }
107
126
  class JWTExpired extends JOSEError {
127
+ static get code() {
128
+ return 'ERR_JWT_EXPIRED';
129
+ }
130
+ code = 'ERR_JWT_EXPIRED';
131
+ claim;
132
+ reason;
108
133
  constructor(message, claim = 'unspecified', reason = 'unspecified') {
109
134
  super(message);
110
- this.code = 'ERR_JWT_EXPIRED';
111
135
  this.claim = claim;
112
136
  this.reason = reason;
113
137
  }
114
- static get code() {
115
- return 'ERR_JWT_EXPIRED';
116
- }
117
138
  }
118
139
  class JOSEAlgNotAllowed extends JOSEError {
119
- constructor() {
120
- super(...arguments);
121
- this.code = 'ERR_JOSE_ALG_NOT_ALLOWED';
122
- }
123
140
  static get code() {
124
141
  return 'ERR_JOSE_ALG_NOT_ALLOWED';
125
142
  }
143
+ code = 'ERR_JOSE_ALG_NOT_ALLOWED';
126
144
  }
127
145
  class JOSENotSupported extends JOSEError {
128
- constructor() {
129
- super(...arguments);
130
- this.code = 'ERR_JOSE_NOT_SUPPORTED';
131
- }
132
146
  static get code() {
133
147
  return 'ERR_JOSE_NOT_SUPPORTED';
134
148
  }
149
+ code = 'ERR_JOSE_NOT_SUPPORTED';
135
150
  }
136
151
  class JWSInvalid extends JOSEError {
137
- constructor() {
138
- super(...arguments);
139
- this.code = 'ERR_JWS_INVALID';
140
- }
141
152
  static get code() {
142
153
  return 'ERR_JWS_INVALID';
143
154
  }
155
+ code = 'ERR_JWS_INVALID';
144
156
  }
145
157
  class JWTInvalid extends JOSEError {
146
- constructor() {
147
- super(...arguments);
148
- this.code = 'ERR_JWT_INVALID';
149
- }
150
158
  static get code() {
151
159
  return 'ERR_JWT_INVALID';
152
160
  }
161
+ code = 'ERR_JWT_INVALID';
153
162
  }
154
163
  class JWKSInvalid extends JOSEError {
155
- constructor() {
156
- super(...arguments);
157
- this.code = 'ERR_JWKS_INVALID';
158
- }
159
164
  static get code() {
160
165
  return 'ERR_JWKS_INVALID';
161
166
  }
167
+ code = 'ERR_JWKS_INVALID';
162
168
  }
163
169
  class JWKSNoMatchingKey extends JOSEError {
164
- constructor() {
165
- super(...arguments);
166
- this.code = 'ERR_JWKS_NO_MATCHING_KEY';
167
- this.message = 'no applicable key found in the JSON Web Key Set';
168
- }
169
170
  static get code() {
170
171
  return 'ERR_JWKS_NO_MATCHING_KEY';
171
172
  }
173
+ code = 'ERR_JWKS_NO_MATCHING_KEY';
174
+ message = 'no applicable key found in the JSON Web Key Set';
172
175
  }
173
176
  class JWKSMultipleMatchingKeys extends JOSEError {
174
- constructor() {
175
- super(...arguments);
176
- this.code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS';
177
- this.message = 'multiple matching keys found in the JSON Web Key Set';
178
- }
177
+ [Symbol.asyncIterator];
179
178
  static get code() {
180
179
  return 'ERR_JWKS_MULTIPLE_MATCHING_KEYS';
181
180
  }
181
+ code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS';
182
+ message = 'multiple matching keys found in the JSON Web Key Set';
182
183
  }
183
184
  class JWKSTimeout extends JOSEError {
184
- constructor() {
185
- super(...arguments);
186
- this.code = 'ERR_JWKS_TIMEOUT';
187
- this.message = 'request timed out';
188
- }
189
185
  static get code() {
190
186
  return 'ERR_JWKS_TIMEOUT';
191
187
  }
188
+ code = 'ERR_JWKS_TIMEOUT';
189
+ message = 'request timed out';
192
190
  }
193
191
  class JWSSignatureVerificationFailed extends JOSEError {
194
- constructor() {
195
- super(...arguments);
196
- this.code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED';
197
- this.message = 'signature verification failed';
198
- }
199
192
  static get code() {
200
193
  return 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED';
201
194
  }
195
+ code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED';
196
+ message = 'signature verification failed';
202
197
  }
203
198
 
204
- var isKeyObject = util.types.isKeyObject
205
- ? (obj) => util.types.isKeyObject(obj)
206
- : (obj) => obj != null && obj instanceof KeyObject;
199
+ var isKeyObject = (obj) => util.types.isKeyObject(obj);
207
200
 
208
- const isCryptoKey = util.types.isCryptoKey
209
- ? (key) => util.types.isCryptoKey(key)
210
- :
211
- (key) => false;
212
-
213
- function isCloudflareWorkers() {
214
- return false;
215
- }
201
+ const webcrypto = crypto.webcrypto;
202
+ const isCryptoKey = (key) => util.types.isCryptoKey(key);
216
203
 
217
204
  function unusable(name, prop = 'algorithm.name') {
218
205
  return new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
@@ -286,11 +273,6 @@ function checkSigCryptoKey(key, alg, ...usages) {
286
273
  throw unusable(`SHA-${expected}`, 'algorithm.hash');
287
274
  break;
288
275
  }
289
- case isCloudflareWorkers() : {
290
- if (!isAlgorithm(key.algorithm, 'NODE-ED25519'))
291
- throw unusable('NODE-ED25519');
292
- break;
293
- }
294
276
  case 'EdDSA': {
295
277
  if (key.algorithm.name !== 'Ed25519' && key.algorithm.name !== 'Ed448') {
296
278
  throw unusable('Ed25519 or Ed448');
@@ -347,7 +329,7 @@ function withAlg(alg, actual, ...types) {
347
329
 
348
330
  var isKeyLike = (key) => isKeyObject(key) || isCryptoKey(key);
349
331
  const types = ['KeyObject'];
350
- if (parseInt(process.versions.node) >= 16) {
332
+ if (globalThis.CryptoKey || webcrypto?.CryptoKey) {
351
333
  types.push('CryptoKey');
352
334
  }
353
335
 
@@ -390,11 +372,6 @@ function isObject(input) {
390
372
  return Object.getPrototypeOf(input) === proto;
391
373
  }
392
374
 
393
- const p256 = Buffer$1.from([42, 134, 72, 206, 61, 3, 1, 7]);
394
- const p384 = Buffer$1.from([43, 129, 4, 0, 34]);
395
- const p521 = Buffer$1.from([43, 129, 4, 0, 35]);
396
- const secp256k1 = Buffer$1.from([43, 129, 4, 0, 10]);
397
- const weakMap$1 = new WeakMap();
398
375
  const namedCurveToJOSE = (namedCurve) => {
399
376
  switch (namedCurve) {
400
377
  case 'prime256v1':
@@ -410,7 +387,6 @@ const namedCurveToJOSE = (namedCurve) => {
410
387
  }
411
388
  };
412
389
  const getNamedCurve = (kee, raw) => {
413
- var _a;
414
390
  let key;
415
391
  if (isCryptoKey(kee)) {
416
392
  key = KeyObject.from(kee);
@@ -432,315 +408,38 @@ const getNamedCurve = (kee, raw) => {
432
408
  case 'x448':
433
409
  return `X${key.asymmetricKeyType.slice(1)}`;
434
410
  case 'ec': {
435
- if (weakMap$1.has(key)) {
436
- return weakMap$1.get(key);
437
- }
438
- let namedCurve = (_a = key.asymmetricKeyDetails) === null || _a === void 0 ? void 0 : _a.namedCurve;
439
- if (!namedCurve && key.type === 'private') {
440
- namedCurve = getNamedCurve(createPublicKey(key), true);
441
- }
442
- else if (!namedCurve) {
443
- const buf = key.export({ format: 'der', type: 'spki' });
444
- const i = buf[1] < 128 ? 14 : 15;
445
- const len = buf[i];
446
- const curveOid = buf.slice(i + 1, i + 1 + len);
447
- if (curveOid.equals(p256)) {
448
- namedCurve = 'prime256v1';
449
- }
450
- else if (curveOid.equals(p384)) {
451
- namedCurve = 'secp384r1';
452
- }
453
- else if (curveOid.equals(p521)) {
454
- namedCurve = 'secp521r1';
455
- }
456
- else if (curveOid.equals(secp256k1)) {
457
- namedCurve = 'secp256k1';
458
- }
459
- else {
460
- throw new JOSENotSupported('Unsupported key curve for this operation');
461
- }
462
- }
463
- if (raw)
411
+ let namedCurve = key.asymmetricKeyDetails.namedCurve;
412
+ if (raw) {
464
413
  return namedCurve;
465
- const curve = namedCurveToJOSE(namedCurve);
466
- weakMap$1.set(key, curve);
467
- return curve;
414
+ }
415
+ return namedCurveToJOSE(namedCurve);
468
416
  }
469
417
  default:
470
418
  throw new TypeError('Invalid asymmetric key type for this operation');
471
419
  }
472
420
  };
473
- function setCurve(keyObject, curve) {
474
- weakMap$1.set(keyObject, curve);
475
- }
476
421
 
477
- const weakMap = new WeakMap();
478
- const getLength = (buf, index) => {
479
- let len = buf.readUInt8(1);
480
- if ((len & 0x80) === 0) {
481
- if (index === 0) {
482
- return len;
483
- }
484
- return getLength(buf.subarray(2 + len), index - 1);
485
- }
486
- const num = len & 0x7f;
487
- len = 0;
488
- for (let i = 0; i < num; i++) {
489
- len <<= 8;
490
- const j = buf.readUInt8(2 + i);
491
- len |= j;
492
- }
493
- if (index === 0) {
494
- return len;
495
- }
496
- return getLength(buf.subarray(2 + len), index - 1);
497
- };
498
- const getLengthOfSeqIndex = (sequence, index) => {
499
- const len = sequence.readUInt8(1);
500
- if ((len & 0x80) === 0) {
501
- return getLength(sequence.subarray(2), index);
502
- }
503
- const num = len & 0x7f;
504
- return getLength(sequence.subarray(2 + num), index);
505
- };
506
- const getModulusLength = (key) => {
507
- var _a, _b;
508
- if (weakMap.has(key)) {
509
- return weakMap.get(key);
510
- }
511
- const modulusLength = (_b = (_a = key.asymmetricKeyDetails) === null || _a === void 0 ? void 0 : _a.modulusLength) !== null && _b !== void 0 ? _b : (getLengthOfSeqIndex(key.export({ format: 'der', type: 'pkcs1' }), key.type === 'private' ? 1 : 0) -
512
- 1) <<
513
- 3;
514
- weakMap.set(key, modulusLength);
515
- return modulusLength;
516
- };
517
- const setModulusLength = (keyObject, modulusLength) => {
518
- weakMap.set(keyObject, modulusLength);
519
- };
520
- var checkModulusLength = (key, alg) => {
521
- if (getModulusLength(key) < 2048) {
422
+ var checkKeyLength = (key, alg) => {
423
+ const { modulusLength } = key.asymmetricKeyDetails;
424
+ if (typeof modulusLength !== 'number' || modulusLength < 2048) {
522
425
  throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
523
426
  }
524
427
  };
525
428
 
526
- const tagInteger = 0x02;
527
- const tagBitStr = 0x03;
528
- const tagOctStr = 0x04;
529
- const tagSequence = 0x30;
530
- const bZero = Buffer$1.from([0x00]);
531
- const bTagInteger = Buffer$1.from([tagInteger]);
532
- const bTagBitStr = Buffer$1.from([tagBitStr]);
533
- const bTagSequence = Buffer$1.from([tagSequence]);
534
- const bTagOctStr = Buffer$1.from([tagOctStr]);
535
- const encodeLength = (len) => {
536
- if (len < 128)
537
- return Buffer$1.from([len]);
538
- const buffer = Buffer$1.alloc(5);
539
- buffer.writeUInt32BE(len, 1);
540
- let offset = 1;
541
- while (buffer[offset] === 0)
542
- offset++;
543
- buffer[offset - 1] = 0x80 | (5 - offset);
544
- return buffer.slice(offset - 1);
545
- };
546
- const oids = new Map([
547
- ['P-256', Buffer$1.from('06 08 2A 86 48 CE 3D 03 01 07'.replace(/ /g, ''), 'hex')],
548
- ['secp256k1', Buffer$1.from('06 05 2B 81 04 00 0A'.replace(/ /g, ''), 'hex')],
549
- ['P-384', Buffer$1.from('06 05 2B 81 04 00 22'.replace(/ /g, ''), 'hex')],
550
- ['P-521', Buffer$1.from('06 05 2B 81 04 00 23'.replace(/ /g, ''), 'hex')],
551
- ['ecPublicKey', Buffer$1.from('06 07 2A 86 48 CE 3D 02 01'.replace(/ /g, ''), 'hex')],
552
- ['X25519', Buffer$1.from('06 03 2B 65 6E'.replace(/ /g, ''), 'hex')],
553
- ['X448', Buffer$1.from('06 03 2B 65 6F'.replace(/ /g, ''), 'hex')],
554
- ['Ed25519', Buffer$1.from('06 03 2B 65 70'.replace(/ /g, ''), 'hex')],
555
- ['Ed448', Buffer$1.from('06 03 2B 65 71'.replace(/ /g, ''), 'hex')],
556
- ]);
557
- class DumbAsn1Encoder {
558
- constructor() {
559
- this.length = 0;
560
- this.elements = [];
561
- }
562
- oidFor(oid) {
563
- const bOid = oids.get(oid);
564
- if (!bOid) {
565
- throw new JOSENotSupported('Invalid or unsupported OID');
566
- }
567
- this.elements.push(bOid);
568
- this.length += bOid.length;
569
- }
570
- zero() {
571
- this.elements.push(bTagInteger, Buffer$1.from([0x01]), bZero);
572
- this.length += 3;
573
- }
574
- one() {
575
- this.elements.push(bTagInteger, Buffer$1.from([0x01]), Buffer$1.from([0x01]));
576
- this.length += 3;
577
- }
578
- unsignedInteger(integer) {
579
- if (integer[0] & 0x80) {
580
- const len = encodeLength(integer.length + 1);
581
- this.elements.push(bTagInteger, len, bZero, integer);
582
- this.length += 2 + len.length + integer.length;
583
- }
584
- else {
585
- let i = 0;
586
- while (integer[i] === 0 && (integer[i + 1] & 0x80) === 0)
587
- i++;
588
- const len = encodeLength(integer.length - i);
589
- this.elements.push(bTagInteger, encodeLength(integer.length - i), integer.slice(i));
590
- this.length += 1 + len.length + integer.length - i;
591
- }
592
- }
593
- octStr(octStr) {
594
- const len = encodeLength(octStr.length);
595
- this.elements.push(bTagOctStr, encodeLength(octStr.length), octStr);
596
- this.length += 1 + len.length + octStr.length;
597
- }
598
- bitStr(bitS) {
599
- const len = encodeLength(bitS.length + 1);
600
- this.elements.push(bTagBitStr, encodeLength(bitS.length + 1), bZero, bitS);
601
- this.length += 1 + len.length + bitS.length + 1;
602
- }
603
- add(seq) {
604
- this.elements.push(seq);
605
- this.length += seq.length;
606
- }
607
- end(tag = bTagSequence) {
608
- const len = encodeLength(this.length);
609
- return Buffer$1.concat([tag, len, ...this.elements], 1 + len.length + this.length);
610
- }
611
- }
612
-
613
- const [major$2, minor$2] = process.version
614
- .slice(1)
615
- .split('.')
616
- .map((str) => parseInt(str, 10));
617
- const jwkImportSupported = major$2 >= 16 || (major$2 === 15 && minor$2 >= 12);
618
429
  const parse = (jwk) => {
619
- if (jwkImportSupported && jwk.kty !== 'oct') {
620
- return jwk.d
621
- ? createPrivateKey({ format: 'jwk', key: jwk })
622
- : createPublicKey({ format: 'jwk', key: jwk });
623
- }
624
- switch (jwk.kty) {
625
- case 'oct': {
626
- return createSecretKey(decode(jwk.k));
627
- }
628
- case 'RSA': {
629
- const enc = new DumbAsn1Encoder();
630
- const isPrivate = jwk.d !== undefined;
631
- const modulus = Buffer$1.from(jwk.n, 'base64');
632
- const exponent = Buffer$1.from(jwk.e, 'base64');
633
- if (isPrivate) {
634
- enc.zero();
635
- enc.unsignedInteger(modulus);
636
- enc.unsignedInteger(exponent);
637
- enc.unsignedInteger(Buffer$1.from(jwk.d, 'base64'));
638
- enc.unsignedInteger(Buffer$1.from(jwk.p, 'base64'));
639
- enc.unsignedInteger(Buffer$1.from(jwk.q, 'base64'));
640
- enc.unsignedInteger(Buffer$1.from(jwk.dp, 'base64'));
641
- enc.unsignedInteger(Buffer$1.from(jwk.dq, 'base64'));
642
- enc.unsignedInteger(Buffer$1.from(jwk.qi, 'base64'));
643
- }
644
- else {
645
- enc.unsignedInteger(modulus);
646
- enc.unsignedInteger(exponent);
647
- }
648
- const der = enc.end();
649
- const createInput = {
650
- key: der,
651
- format: 'der',
652
- type: 'pkcs1',
653
- };
654
- const keyObject = isPrivate ? createPrivateKey(createInput) : createPublicKey(createInput);
655
- setModulusLength(keyObject, modulus.length << 3);
656
- return keyObject;
657
- }
658
- case 'EC': {
659
- const enc = new DumbAsn1Encoder();
660
- const isPrivate = jwk.d !== undefined;
661
- const pub = Buffer$1.concat([
662
- Buffer$1.alloc(1, 4),
663
- Buffer$1.from(jwk.x, 'base64'),
664
- Buffer$1.from(jwk.y, 'base64'),
665
- ]);
666
- if (isPrivate) {
667
- enc.zero();
668
- const enc$1 = new DumbAsn1Encoder();
669
- enc$1.oidFor('ecPublicKey');
670
- enc$1.oidFor(jwk.crv);
671
- enc.add(enc$1.end());
672
- const enc$2 = new DumbAsn1Encoder();
673
- enc$2.one();
674
- enc$2.octStr(Buffer$1.from(jwk.d, 'base64'));
675
- const enc$3 = new DumbAsn1Encoder();
676
- enc$3.bitStr(pub);
677
- const f2 = enc$3.end(Buffer$1.from([0xa1]));
678
- enc$2.add(f2);
679
- const f = enc$2.end();
680
- const enc$4 = new DumbAsn1Encoder();
681
- enc$4.add(f);
682
- const f3 = enc$4.end(Buffer$1.from([0x04]));
683
- enc.add(f3);
684
- const der = enc.end();
685
- const keyObject = createPrivateKey({ key: der, format: 'der', type: 'pkcs8' });
686
- setCurve(keyObject, jwk.crv);
687
- return keyObject;
688
- }
689
- const enc$1 = new DumbAsn1Encoder();
690
- enc$1.oidFor('ecPublicKey');
691
- enc$1.oidFor(jwk.crv);
692
- enc.add(enc$1.end());
693
- enc.bitStr(pub);
694
- const der = enc.end();
695
- const keyObject = createPublicKey({ key: der, format: 'der', type: 'spki' });
696
- setCurve(keyObject, jwk.crv);
697
- return keyObject;
698
- }
699
- case 'OKP': {
700
- const enc = new DumbAsn1Encoder();
701
- const isPrivate = jwk.d !== undefined;
702
- if (isPrivate) {
703
- enc.zero();
704
- const enc$1 = new DumbAsn1Encoder();
705
- enc$1.oidFor(jwk.crv);
706
- enc.add(enc$1.end());
707
- const enc$2 = new DumbAsn1Encoder();
708
- enc$2.octStr(Buffer$1.from(jwk.d, 'base64'));
709
- const f = enc$2.end(Buffer$1.from([0x04]));
710
- enc.add(f);
711
- const der = enc.end();
712
- return createPrivateKey({ key: der, format: 'der', type: 'pkcs8' });
713
- }
714
- const enc$1 = new DumbAsn1Encoder();
715
- enc$1.oidFor(jwk.crv);
716
- enc.add(enc$1.end());
717
- enc.bitStr(Buffer$1.from(jwk.x, 'base64'));
718
- const der = enc.end();
719
- return createPublicKey({ key: der, format: 'der', type: 'spki' });
720
- }
721
- default:
722
- throw new JOSENotSupported('Invalid or unsupported JWK "kty" (Key Type) Parameter value');
723
- }
430
+ return (jwk.d ? createPrivateKey : createPublicKey)({ format: 'jwk', key: jwk });
724
431
  };
725
432
 
726
- async function importJWK(jwk, alg, octAsKeyObject) {
727
- var _a;
433
+ async function importJWK(jwk, alg) {
728
434
  if (!isObject(jwk)) {
729
435
  throw new TypeError('JWK must be an object');
730
436
  }
731
- alg || (alg = jwk.alg);
732
- if (typeof alg !== 'string' || !alg) {
733
- throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
734
- }
437
+ alg ||= jwk.alg;
735
438
  switch (jwk.kty) {
736
439
  case 'oct':
737
440
  if (typeof jwk.k !== 'string' || !jwk.k) {
738
441
  throw new TypeError('missing "k" (Key Value) Parameter value');
739
442
  }
740
- octAsKeyObject !== null && octAsKeyObject !== void 0 ? octAsKeyObject : (octAsKeyObject = jwk.ext !== true);
741
- if (octAsKeyObject) {
742
- return parse({ ...jwk, alg, ext: (_a = jwk.ext) !== null && _a !== void 0 ? _a : false });
743
- }
744
443
  return decode(jwk.k);
745
444
  case 'RSA':
746
445
  if (jwk.oth !== undefined) {
@@ -863,12 +562,6 @@ function dsaDigest(alg) {
863
562
  }
864
563
  }
865
564
 
866
- const [major$1, minor$1] = process.version
867
- .slice(1)
868
- .split('.')
869
- .map((str) => parseInt(str, 10));
870
- const electron = 'electron' in process.versions;
871
- const rsaPssParams = !electron && (major$1 >= 17 || (major$1 === 16 && minor$1 >= 9));
872
565
  const PSS = {
873
566
  padding: constants.RSA_PKCS1_PSS_PADDING,
874
567
  saltLength: constants.RSA_PSS_SALTLEN_DIGEST,
@@ -892,11 +585,11 @@ function keyForCrypto(alg, key) {
892
585
  if (key.asymmetricKeyType !== 'rsa') {
893
586
  throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa');
894
587
  }
895
- checkModulusLength(key, alg);
588
+ checkKeyLength(key, alg);
896
589
  return key;
897
- case rsaPssParams && 'PS256':
898
- case rsaPssParams && 'PS384':
899
- case rsaPssParams && 'PS512':
590
+ case 'PS256':
591
+ case 'PS384':
592
+ case 'PS512':
900
593
  if (key.asymmetricKeyType === 'rsa-pss') {
901
594
  const { hashAlgorithm, mgf1HashAlgorithm, saltLength } = key.asymmetricKeyDetails;
902
595
  const length = parseInt(alg.slice(-3), 10);
@@ -911,15 +604,7 @@ function keyForCrypto(alg, key) {
911
604
  else if (key.asymmetricKeyType !== 'rsa') {
912
605
  throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa or rsa-pss');
913
606
  }
914
- checkModulusLength(key, alg);
915
- return { key, ...PSS };
916
- case !rsaPssParams && 'PS256':
917
- case !rsaPssParams && 'PS384':
918
- case !rsaPssParams && 'PS512':
919
- if (key.asymmetricKeyType !== 'rsa') {
920
- throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa');
921
- }
922
- checkModulusLength(key, alg);
607
+ checkKeyLength(key, alg);
923
608
  return { key, ...PSS };
924
609
  case 'ES256':
925
610
  case 'ES256K':
@@ -970,13 +655,7 @@ function getSignVerifyKey(alg, key, usage) {
970
655
  throw new TypeError(invalidKeyInput(key, ...types, 'Uint8Array'));
971
656
  }
972
657
 
973
- let oneShotSign;
974
- if (crypto.sign.length > 3) {
975
- oneShotSign = promisify(crypto.sign);
976
- }
977
- else {
978
- oneShotSign = crypto.sign;
979
- }
658
+ const oneShotSign = promisify(crypto.sign);
980
659
  const sign = async (alg, key, data) => {
981
660
  const keyObject = getSignVerifyKey(alg, key, 'sign');
982
661
  if (alg.startsWith('HS')) {
@@ -987,18 +666,7 @@ const sign = async (alg, key, data) => {
987
666
  return oneShotSign(dsaDigest(alg), data, keyForCrypto(alg, keyObject));
988
667
  };
989
668
 
990
- const [major, minor] = process.version
991
- .slice(1)
992
- .split('.')
993
- .map((str) => parseInt(str, 10));
994
- const oneShotCallbackSupported = major >= 16 || (major === 15 && minor >= 13);
995
- let oneShotVerify;
996
- if (crypto.verify.length > 4 && oneShotCallbackSupported) {
997
- oneShotVerify = promisify(crypto.verify);
998
- }
999
- else {
1000
- oneShotVerify = crypto.verify;
1001
- }
669
+ const oneShotVerify = promisify(crypto.verify);
1002
670
  const verify = async (alg, key, signature, data) => {
1003
671
  const keyObject = getSignVerifyKey(alg, key, 'verify');
1004
672
  if (alg.startsWith('HS')) {
@@ -1022,7 +690,6 @@ const verify = async (alg, key, signature, data) => {
1022
690
  };
1023
691
 
1024
692
  async function flattenedVerify(jws, key, options) {
1025
- var _a;
1026
693
  if (!isObject(jws)) {
1027
694
  throw new JWSInvalid('Flattened JWS must be an object');
1028
695
  }
@@ -1058,7 +725,7 @@ async function flattenedVerify(jws, key, options) {
1058
725
  ...parsedProt,
1059
726
  ...jws.header,
1060
727
  };
1061
- const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader);
728
+ const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options?.crit, parsedProt, joseHeader);
1062
729
  let b64 = true;
1063
730
  if (extensions.has('b64')) {
1064
731
  b64 = parsedProt.b64;
@@ -1072,7 +739,7 @@ async function flattenedVerify(jws, key, options) {
1072
739
  }
1073
740
  const algorithms = options && validateAlgorithms('algorithms', options.algorithms);
1074
741
  if (algorithms && !algorithms.has(alg)) {
1075
- throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter not allowed');
742
+ throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed');
1076
743
  }
1077
744
  if (b64) {
1078
745
  if (typeof jws.payload !== 'string') {
@@ -1088,15 +755,26 @@ async function flattenedVerify(jws, key, options) {
1088
755
  resolvedKey = true;
1089
756
  }
1090
757
  checkKeyType(alg, key, 'verify');
1091
- const data = concat(encoder.encode((_a = jws.protected) !== null && _a !== void 0 ? _a : ''), encoder.encode('.'), typeof jws.payload === 'string' ? encoder.encode(jws.payload) : jws.payload);
1092
- const signature = decode(jws.signature);
758
+ const data = concat(encoder.encode(jws.protected ?? ''), encoder.encode('.'), typeof jws.payload === 'string' ? encoder.encode(jws.payload) : jws.payload);
759
+ let signature;
760
+ try {
761
+ signature = decode(jws.signature);
762
+ }
763
+ catch {
764
+ throw new JWSInvalid('Failed to base64url decode the signature');
765
+ }
1093
766
  const verified = await verify(alg, key, signature, data);
1094
767
  if (!verified) {
1095
768
  throw new JWSSignatureVerificationFailed();
1096
769
  }
1097
770
  let payload;
1098
771
  if (b64) {
1099
- payload = decode(jws.payload);
772
+ try {
773
+ payload = decode(jws.payload);
774
+ }
775
+ catch {
776
+ throw new JWSInvalid('Failed to base64url decode the payload');
777
+ }
1100
778
  }
1101
779
  else if (typeof jws.payload === 'string') {
1102
780
  payload = encoder.encode(jws.payload);
@@ -1209,15 +887,26 @@ var jwtPayload = (protectedHeader, encodedPayload, options = {}) => {
1209
887
  if (!isObject(payload)) {
1210
888
  throw new JWTInvalid('JWT Claims Set must be a top-level JSON object');
1211
889
  }
1212
- const { issuer } = options;
890
+ const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;
891
+ if (maxTokenAge !== undefined)
892
+ requiredClaims.push('iat');
893
+ if (audience !== undefined)
894
+ requiredClaims.push('aud');
895
+ if (subject !== undefined)
896
+ requiredClaims.push('sub');
897
+ if (issuer !== undefined)
898
+ requiredClaims.push('iss');
899
+ for (const claim of new Set(requiredClaims.reverse())) {
900
+ if (!(claim in payload)) {
901
+ throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, claim, 'missing');
902
+ }
903
+ }
1213
904
  if (issuer && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {
1214
905
  throw new JWTClaimValidationFailed('unexpected "iss" claim value', 'iss', 'check_failed');
1215
906
  }
1216
- const { subject } = options;
1217
907
  if (subject && payload.sub !== subject) {
1218
908
  throw new JWTClaimValidationFailed('unexpected "sub" claim value', 'sub', 'check_failed');
1219
909
  }
1220
- const { audience } = options;
1221
910
  if (audience &&
1222
911
  !checkAudiencePresence(payload.aud, typeof audience === 'string' ? [audience] : audience)) {
1223
912
  throw new JWTClaimValidationFailed('unexpected "aud" claim value', 'aud', 'check_failed');
@@ -1238,7 +927,7 @@ var jwtPayload = (protectedHeader, encodedPayload, options = {}) => {
1238
927
  }
1239
928
  const { currentDate } = options;
1240
929
  const now = epoch(currentDate || new Date());
1241
- if ((payload.iat !== undefined || options.maxTokenAge) && typeof payload.iat !== 'number') {
930
+ if ((payload.iat !== undefined || maxTokenAge) && typeof payload.iat !== 'number') {
1242
931
  throw new JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid');
1243
932
  }
1244
933
  if (payload.nbf !== undefined) {
@@ -1257,9 +946,9 @@ var jwtPayload = (protectedHeader, encodedPayload, options = {}) => {
1257
946
  throw new JWTExpired('"exp" claim timestamp check failed', 'exp', 'check_failed');
1258
947
  }
1259
948
  }
1260
- if (options.maxTokenAge) {
949
+ if (maxTokenAge) {
1261
950
  const age = now - payload.iat;
1262
- const max = typeof options.maxTokenAge === 'number' ? options.maxTokenAge : secs(options.maxTokenAge);
951
+ const max = typeof maxTokenAge === 'number' ? maxTokenAge : secs(maxTokenAge);
1263
952
  if (age - tolerance > max) {
1264
953
  throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', 'iat', 'check_failed');
1265
954
  }
@@ -1271,9 +960,8 @@ var jwtPayload = (protectedHeader, encodedPayload, options = {}) => {
1271
960
  };
1272
961
 
1273
962
  async function jwtVerify(jwt, key, options) {
1274
- var _a;
1275
963
  const verified = await compactVerify(jwt, key, options);
1276
- if (((_a = verified.protectedHeader.crit) === null || _a === void 0 ? void 0 : _a.includes('b64')) && verified.protectedHeader.b64 === false) {
964
+ if (verified.protectedHeader.crit?.includes('b64') && verified.protectedHeader.b64 === false) {
1277
965
  throw new JWTInvalid('JWTs MUST NOT use unencoded payload');
1278
966
  }
1279
967
  const payload = jwtPayload(verified.protectedHeader, verified.payload, options);
@@ -1313,15 +1001,16 @@ function clone(obj) {
1313
1001
  return JSON.parse(JSON.stringify(obj));
1314
1002
  }
1315
1003
  class LocalJWKSet {
1004
+ _jwks;
1005
+ _cached = new WeakMap();
1316
1006
  constructor(jwks) {
1317
- this._cached = new WeakMap();
1318
1007
  if (!isJWKSLike(jwks)) {
1319
1008
  throw new JWKSInvalid('JSON Web Key Set malformed');
1320
1009
  }
1321
1010
  this._jwks = clone(jwks);
1322
1011
  }
1323
1012
  async getKey(protectedHeader, token) {
1324
- const { alg, kid } = { ...protectedHeader, ...token.header };
1013
+ const { alg, kid } = { ...protectedHeader, ...token?.header };
1325
1014
  const kty = getKtyFromAlg(alg);
1326
1015
  const candidates = this._jwks.keys.filter((jwk) => {
1327
1016
  let candidate = kty === jwk.kty;
@@ -1363,18 +1052,33 @@ class LocalJWKSet {
1363
1052
  throw new JWKSNoMatchingKey();
1364
1053
  }
1365
1054
  else if (length !== 1) {
1366
- throw new JWKSMultipleMatchingKeys();
1055
+ const error = new JWKSMultipleMatchingKeys();
1056
+ const { _cached } = this;
1057
+ error[Symbol.asyncIterator] = async function* () {
1058
+ for (const jwk of candidates) {
1059
+ try {
1060
+ yield await importWithAlgCache(_cached, jwk, alg);
1061
+ }
1062
+ catch {
1063
+ continue;
1064
+ }
1065
+ }
1066
+ };
1067
+ throw error;
1367
1068
  }
1368
- const cached = this._cached.get(jwk) || this._cached.set(jwk, {}).get(jwk);
1369
- if (cached[alg] === undefined) {
1370
- const keyObject = await importJWK({ ...jwk, ext: true }, alg);
1371
- if (keyObject instanceof Uint8Array || keyObject.type !== 'public') {
1372
- throw new JWKSInvalid('JSON Web Key Set members must be public keys');
1373
- }
1374
- cached[alg] = keyObject;
1069
+ return importWithAlgCache(this._cached, jwk, alg);
1070
+ }
1071
+ }
1072
+ async function importWithAlgCache(cache, jwk, alg) {
1073
+ const cached = cache.get(jwk) || cache.set(jwk, {}).get(jwk);
1074
+ if (cached[alg] === undefined) {
1075
+ const key = await importJWK({ ...jwk, ext: true }, alg);
1076
+ if (key instanceof Uint8Array || key.type !== 'public') {
1077
+ throw new JWKSInvalid('JSON Web Key Set members must be public keys');
1375
1078
  }
1376
- return cached[alg];
1079
+ cached[alg] = key;
1377
1080
  }
1081
+ return cached[alg];
1378
1082
  }
1379
1083
 
1380
1084
  const fetchJwks = async (url, timeout, options) => {
@@ -1415,7 +1119,19 @@ const fetchJwks = async (url, timeout, options) => {
1415
1119
  }
1416
1120
  };
1417
1121
 
1122
+ function isCloudflareWorkers() {
1123
+ return (typeof WebSocketPair !== 'undefined' ||
1124
+ (typeof navigator !== 'undefined' && navigator.userAgent === 'Cloudflare-Workers') ||
1125
+ (typeof EdgeRuntime !== 'undefined' && EdgeRuntime === 'vercel'));
1126
+ }
1418
1127
  class RemoteJWKSet extends LocalJWKSet {
1128
+ _url;
1129
+ _timeoutDuration;
1130
+ _cooldownDuration;
1131
+ _cacheMaxAge;
1132
+ _jwksTimestamp;
1133
+ _pendingFetch;
1134
+ _options;
1419
1135
  constructor(url, options) {
1420
1136
  super({ keys: [] });
1421
1137
  this._jwks = undefined;
@@ -1423,12 +1139,12 @@ class RemoteJWKSet extends LocalJWKSet {
1423
1139
  throw new TypeError('url must be an instance of URL');
1424
1140
  }
1425
1141
  this._url = new URL(url.href);
1426
- this._options = { agent: options === null || options === void 0 ? void 0 : options.agent, headers: options === null || options === void 0 ? void 0 : options.headers };
1142
+ this._options = { agent: options?.agent, headers: options?.headers };
1427
1143
  this._timeoutDuration =
1428
- typeof (options === null || options === void 0 ? void 0 : options.timeoutDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.timeoutDuration : 5000;
1144
+ typeof options?.timeoutDuration === 'number' ? options?.timeoutDuration : 5000;
1429
1145
  this._cooldownDuration =
1430
- typeof (options === null || options === void 0 ? void 0 : options.cooldownDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.cooldownDuration : 30000;
1431
- this._cacheMaxAge = typeof (options === null || options === void 0 ? void 0 : options.cacheMaxAge) === 'number' ? options === null || options === void 0 ? void 0 : options.cacheMaxAge : 600000;
1146
+ typeof options?.cooldownDuration === 'number' ? options?.cooldownDuration : 30000;
1147
+ this._cacheMaxAge = typeof options?.cacheMaxAge === 'number' ? options?.cacheMaxAge : 600000;
1432
1148
  }
1433
1149
  coolingDown() {
1434
1150
  return typeof this._jwksTimestamp === 'number'
@@ -1459,38 +1175,29 @@ class RemoteJWKSet extends LocalJWKSet {
1459
1175
  }
1460
1176
  async reload() {
1461
1177
  if (this._pendingFetch && isCloudflareWorkers()) {
1462
- return new Promise((resolve) => {
1463
- const isDone = () => {
1464
- if (this._pendingFetch === undefined) {
1465
- resolve();
1466
- }
1467
- else {
1468
- setTimeout(isDone, 5);
1469
- }
1470
- };
1471
- isDone();
1472
- });
1473
- }
1474
- if (!this._pendingFetch) {
1475
- this._pendingFetch = fetchJwks(this._url, this._timeoutDuration, this._options)
1476
- .then((json) => {
1477
- if (!isJWKSLike(json)) {
1478
- throw new JWKSInvalid('JSON Web Key Set malformed');
1479
- }
1480
- this._jwks = { keys: json.keys };
1481
- this._jwksTimestamp = Date.now();
1482
- this._pendingFetch = undefined;
1483
- })
1484
- .catch((err) => {
1485
- this._pendingFetch = undefined;
1486
- throw err;
1487
- });
1178
+ this._pendingFetch = undefined;
1488
1179
  }
1180
+ this._pendingFetch ||= fetchJwks(this._url, this._timeoutDuration, this._options)
1181
+ .then((json) => {
1182
+ if (!isJWKSLike(json)) {
1183
+ throw new JWKSInvalid('JSON Web Key Set malformed');
1184
+ }
1185
+ this._jwks = { keys: json.keys };
1186
+ this._jwksTimestamp = Date.now();
1187
+ this._pendingFetch = undefined;
1188
+ })
1189
+ .catch((err) => {
1190
+ this._pendingFetch = undefined;
1191
+ throw err;
1192
+ });
1489
1193
  await this._pendingFetch;
1490
1194
  }
1491
1195
  }
1492
1196
  function createRemoteJWKSet(url, options) {
1493
- return RemoteJWKSet.prototype.getKey.bind(new RemoteJWKSet(url, options));
1197
+ const set = new RemoteJWKSet(url, options);
1198
+ return async function (protectedHeader, token) {
1199
+ return set.getKey(protectedHeader, token);
1200
+ };
1494
1201
  }
1495
1202
 
1496
1203
  // https://appleid.apple.com/.well-known/openid-configuration
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@logto/connector-apple",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Apple web connector implementation.",
5
5
  "dependencies": {
6
- "@logto/connector-kit": "^1.1.1",
7
- "@logto/shared": "^2.0.0",
8
- "jose": "^4.3.8"
6
+ "@logto/connector-kit": "^2.0.0",
7
+ "@logto/shared": "^3.0.0",
8
+ "jose": "^5.0.0"
9
9
  },
10
10
  "main": "./lib/index.js",
11
11
  "module": "./lib/index.js",