@arcblock/jwt 1.29.21 → 1.29.22

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/esm/index.d.mts CHANGED
@@ -35,6 +35,28 @@ type JwtVerifyOptions = Partial<{
35
35
  */
36
36
  declare function sign(signer: string, sk?: BytesType, payload?: {}, doSign?: boolean, version?: string): Promise<string>;
37
37
  declare function signV2(signer: string, sk?: BytesType, payload?: any): Promise<string>;
38
+ type PasskeyAssertion = {
39
+ authenticatorData: string;
40
+ clientDataJSON: string;
41
+ signature: string;
42
+ };
43
+ /**
44
+ * Compute the WebAuthn challenge for an unsigned JWT token.
45
+ * Always uses SHA3 hash-before-sign (v1.1.0 semantics, required for passkey).
46
+ *
47
+ * @param unsignedToken - the unsigned token (headerB64.bodyB64), may also accept 3-part tokens (ignores third segment)
48
+ * @returns hex-encoded SHA3 hash suitable as WebAuthn challenge
49
+ */
50
+ declare function getChallenge(unsignedToken: string): string;
51
+ /**
52
+ * Assemble a complete JWT from an unsigned token and a passkey assertion.
53
+ * The assertion is JSON-serialized and base64-encoded as the JWT's third segment.
54
+ *
55
+ * @param unsignedToken - the unsigned token (headerB64.bodyB64)
56
+ * @param assertion - WebAuthn assertion with base64url-encoded fields
57
+ * @returns complete 3-part JWT string
58
+ */
59
+ declare function assemble(unsignedToken: string, assertion: PasskeyAssertion): string;
38
60
  declare function decode(token: string, bodyOnly?: true): JwtBody;
39
61
  declare function decode(token: string, bodyOnly?: false): JwtToken;
40
62
  /**
@@ -88,6 +110,23 @@ declare function signDelegationToken(signer: string, sk: BytesType, payload: {
88
110
  nbf?: string;
89
111
  exp?: string;
90
112
  }): Promise<string>;
113
+ /**
114
+ * Create an unsigned delegation token for passkey two-phase signing.
115
+ * Unlike signDelegationToken, this does not sign (passkey has no sk), and pk is passed directly.
116
+ */
117
+ declare function signDelegationTokenUnsigned(signer: string, pk: BytesType, payload: {
118
+ sub: string;
119
+ ops: string[];
120
+ deny?: string[];
121
+ delegation?: string;
122
+ iat?: string;
123
+ nbf?: string;
124
+ exp?: string;
125
+ }): Promise<string>;
126
+ /**
127
+ * Assemble a complete delegation token from an unsigned token and a passkey assertion.
128
+ */
129
+ declare function assembleDelegationToken(unsignedToken: string, assertion: PasskeyAssertion): string;
91
130
  declare function decodeDelegationToken(token: string): DelegationToken;
92
131
  declare function verifyDelegationToken(token: string): Promise<boolean>;
93
132
  declare function checkDelegationTokenScope(scope: string, {
@@ -98,4 +137,4 @@ declare function checkDelegationTokenScope(scope: string, {
98
137
  deny?: string[];
99
138
  }): boolean;
100
139
  //#endregion
101
- export { DelegationToken, DelegationTokenBody, DelegationTokenHeader, JwtBody, JwtHeader, JwtToken, JwtVerifyOptions, checkDelegationTokenScope, decode, decodeDelegationToken, sign, signDelegationToken, signV2, verify, verifyDelegationToken };
140
+ export { DelegationToken, DelegationTokenBody, DelegationTokenHeader, JwtBody, JwtHeader, JwtToken, JwtVerifyOptions, PasskeyAssertion, assemble, assembleDelegationToken, checkDelegationTokenScope, decode, decodeDelegationToken, getChallenge, sign, signDelegationToken, signDelegationTokenUnsigned, signV2, verify, verifyDelegationToken };
package/esm/index.mjs CHANGED
@@ -72,6 +72,32 @@ async function sign(signer, sk, payload = {}, doSign = true, version = "1.0.0")
72
72
  async function signV2(signer, sk, payload = {}) {
73
73
  return sign(signer, sk, payload, !!sk, "1.1.0");
74
74
  }
75
+ /**
76
+ * Compute the WebAuthn challenge for an unsigned JWT token.
77
+ * Always uses SHA3 hash-before-sign (v1.1.0 semantics, required for passkey).
78
+ *
79
+ * @param unsignedToken - the unsigned token (headerB64.bodyB64), may also accept 3-part tokens (ignores third segment)
80
+ * @returns hex-encoded SHA3 hash suitable as WebAuthn challenge
81
+ */
82
+ function getChallenge(unsignedToken) {
83
+ if (!unsignedToken) throw new Error("Cannot compute challenge from empty token");
84
+ const parts = unsignedToken.split(".");
85
+ return hasher(toHex(`${parts[0]}.${parts[1]}`));
86
+ }
87
+ /**
88
+ * Assemble a complete JWT from an unsigned token and a passkey assertion.
89
+ * The assertion is JSON-serialized and base64-encoded as the JWT's third segment.
90
+ *
91
+ * @param unsignedToken - the unsigned token (headerB64.bodyB64)
92
+ * @param assertion - WebAuthn assertion with base64url-encoded fields
93
+ * @returns complete 3-part JWT string
94
+ */
95
+ function assemble(unsignedToken, assertion) {
96
+ if (!unsignedToken) throw new Error("Cannot assemble JWT from empty token");
97
+ if (unsignedToken.split(".").length !== 2) throw new Error("Cannot assemble JWT: expected unsigned token with exactly 2 parts (headerB64.bodyB64)");
98
+ if (!assertion || !assertion.authenticatorData || !assertion.clientDataJSON || !assertion.signature) throw new Error("Cannot assemble JWT: assertion must contain authenticatorData, clientDataJSON, and signature");
99
+ return `${unsignedToken}.${toBase64(JSON.stringify(assertion))}`;
100
+ }
75
101
  function decode(token, bodyOnly = true) {
76
102
  const [headerB64, bodyB64, sigB64] = token.split(".");
77
103
  const header = JSON.parse(fromBase64(headerB64).toString());
@@ -154,14 +180,27 @@ async function verify(token, signerPk, options) {
154
180
  return false;
155
181
  }
156
182
  }
183
+ const alg = header.alg.toLowerCase();
184
+ if (alg === "passkey") {
185
+ const [, , sigB64] = token.split(".");
186
+ const assertionRaw = JSON.parse(fromBase64(sigB64).toString());
187
+ if (!assertionRaw.authenticatorData || !assertionRaw.clientDataJSON || !assertionRaw.signature) {
188
+ debug("verify.error.incompletePasskeyAssertion");
189
+ return false;
190
+ }
191
+ const challenge = hasher(toHex(`${headerB64}.${bodyB64}`));
192
+ const extra = JSON.stringify({
193
+ authenticatorData: assertionRaw.authenticatorData,
194
+ clientDataJSON: assertionRaw.clientDataJSON
195
+ });
196
+ return await getSigner(types.KeyType.PASSKEY).verify(challenge, assertionRaw.signature, signerPk, extra);
197
+ }
157
198
  const signers = {
158
199
  secp256k1: getSigner(types.KeyType.SECP256K1),
159
200
  es256k: getSigner(types.KeyType.SECP256K1),
160
201
  ed25519: getSigner(types.KeyType.ED25519),
161
- ethereum: getSigner(types.KeyType.ETHEREUM),
162
- passkey: getSigner(types.KeyType.PASSKEY)
202
+ ethereum: getSigner(types.KeyType.ETHEREUM)
163
203
  };
164
- const alg = header.alg.toLowerCase();
165
204
  if (signers[alg]) {
166
205
  const msgHex = toHex(`${headerB64}.${bodyB64}`);
167
206
  const coercedBodyVersion = body.version ? semver.coerce(body.version) : null;
@@ -190,6 +229,10 @@ const delegationTokenHeaders = {
190
229
  [types.KeyType.ETHEREUM]: {
191
230
  alg: "Ethereum",
192
231
  typ: "DelegationToken"
232
+ },
233
+ [types.KeyType.PASSKEY]: {
234
+ alg: "Passkey",
235
+ typ: "DelegationToken"
193
236
  }
194
237
  };
195
238
  async function signDelegationToken(signer, sk, payload) {
@@ -223,6 +266,45 @@ async function signDelegationToken(signer, sk, payload) {
223
266
  toBase64(getSigner(type.pk).sign(msgHash, sk))
224
267
  ].join(".");
225
268
  }
269
+ /**
270
+ * Create an unsigned delegation token for passkey two-phase signing.
271
+ * Unlike signDelegationToken, this does not sign (passkey has no sk), and pk is passed directly.
272
+ */
273
+ async function signDelegationTokenUnsigned(signer, pk, payload) {
274
+ if (isValid(signer) === false) throw new Error("Cannot sign DelegationToken with invalid signer");
275
+ const type = toTypeInfo(signer);
276
+ if (type.pk === void 0) throw new Error("Cannot determine key type from signer");
277
+ const header = delegationTokenHeaders[type.pk];
278
+ const headerB64 = toBase64(stringify(header));
279
+ const delegationSignerMethod = extractMethod(signer) || "abt";
280
+ const now = Math.floor(Date.now() / 1e3);
281
+ const pkHex = typeof pk === "string" ? pk : toHex(pk);
282
+ const body = {
283
+ iss: toDid(signer, delegationSignerMethod),
284
+ sub: payload.sub,
285
+ iat: payload.iat || String(now),
286
+ nbf: payload.nbf || String(now),
287
+ exp: payload.exp || String(now + 300),
288
+ version: DELEGATION_TOKEN_VERSION,
289
+ ops: payload.ops,
290
+ pk: pkHex
291
+ };
292
+ if (payload.deny && payload.deny.length > 0) {
293
+ for (const d of payload.deny) if (!d.startsWith("fg:")) throw new Error(`Invalid deny pattern "${d}": must start with "fg:"`);
294
+ body.deny = payload.deny;
295
+ }
296
+ if (payload.delegation) body.delegation = payload.delegation;
297
+ return `${headerB64}.${toBase64(stringify(body))}`;
298
+ }
299
+ /**
300
+ * Assemble a complete delegation token from an unsigned token and a passkey assertion.
301
+ */
302
+ function assembleDelegationToken(unsignedToken, assertion) {
303
+ if (!unsignedToken) throw new Error("Cannot assemble DelegationToken from empty token");
304
+ if (unsignedToken.split(".").length !== 2) throw new Error("Cannot assemble DelegationToken: expected unsigned token with exactly 2 parts (headerB64.bodyB64)");
305
+ if (!assertion || !assertion.authenticatorData || !assertion.clientDataJSON || !assertion.signature) throw new Error("Cannot assemble DelegationToken: assertion must contain authenticatorData, clientDataJSON, and signature");
306
+ return `${unsignedToken}.${toBase64(JSON.stringify(assertion))}`;
307
+ }
226
308
  function decodeDelegationToken(token) {
227
309
  const parts = token.split(".");
228
310
  if (parts.length !== 3) throw new Error("Invalid delegation token format: expected 3 parts");
@@ -265,13 +347,27 @@ async function verifyDelegationToken(token) {
265
347
  debug("delegationToken.verify.error.futureIat");
266
348
  return false;
267
349
  }
350
+ const alg = header.alg.toLowerCase();
351
+ if (alg === "passkey") {
352
+ const [, , sigB64] = token.split(".");
353
+ const assertionRaw = JSON.parse(fromBase64(sigB64).toString());
354
+ if (!assertionRaw.authenticatorData || !assertionRaw.clientDataJSON || !assertionRaw.signature) {
355
+ debug("delegationToken.verify.error.incompletePasskeyAssertion");
356
+ return false;
357
+ }
358
+ const challenge = hasher(toHex(`${headerB64}.${bodyB64}`));
359
+ const extra = JSON.stringify({
360
+ authenticatorData: assertionRaw.authenticatorData,
361
+ clientDataJSON: assertionRaw.clientDataJSON
362
+ });
363
+ return await getSigner(types.KeyType.PASSKEY).verify(challenge, assertionRaw.signature, body.pk, extra);
364
+ }
268
365
  const signers = {
269
366
  ed25519: getSigner(types.KeyType.ED25519),
270
367
  es256k: getSigner(types.KeyType.SECP256K1),
271
368
  secp256k1: getSigner(types.KeyType.SECP256K1),
272
369
  ethereum: getSigner(types.KeyType.ETHEREUM)
273
370
  };
274
- const alg = header.alg.toLowerCase();
275
371
  if (!signers[alg]) {
276
372
  debug("delegationToken.verify.error.unknownAlg");
277
373
  return false;
@@ -289,4 +385,4 @@ function checkDelegationTokenScope(scope, { ops, deny }) {
289
385
  }
290
386
 
291
387
  //#endregion
292
- export { checkDelegationTokenScope, decode, decodeDelegationToken, sign, signDelegationToken, signV2, verify, verifyDelegationToken };
388
+ export { assemble, assembleDelegationToken, checkDelegationTokenScope, decode, decodeDelegationToken, getChallenge, sign, signDelegationToken, signDelegationTokenUnsigned, signV2, verify, verifyDelegationToken };
package/lib/index.cjs CHANGED
@@ -76,6 +76,32 @@ async function sign(signer, sk, payload = {}, doSign = true, version = "1.0.0")
76
76
  async function signV2(signer, sk, payload = {}) {
77
77
  return sign(signer, sk, payload, !!sk, "1.1.0");
78
78
  }
79
+ /**
80
+ * Compute the WebAuthn challenge for an unsigned JWT token.
81
+ * Always uses SHA3 hash-before-sign (v1.1.0 semantics, required for passkey).
82
+ *
83
+ * @param unsignedToken - the unsigned token (headerB64.bodyB64), may also accept 3-part tokens (ignores third segment)
84
+ * @returns hex-encoded SHA3 hash suitable as WebAuthn challenge
85
+ */
86
+ function getChallenge(unsignedToken) {
87
+ if (!unsignedToken) throw new Error("Cannot compute challenge from empty token");
88
+ const parts = unsignedToken.split(".");
89
+ return hasher((0, _ocap_util.toHex)(`${parts[0]}.${parts[1]}`));
90
+ }
91
+ /**
92
+ * Assemble a complete JWT from an unsigned token and a passkey assertion.
93
+ * The assertion is JSON-serialized and base64-encoded as the JWT's third segment.
94
+ *
95
+ * @param unsignedToken - the unsigned token (headerB64.bodyB64)
96
+ * @param assertion - WebAuthn assertion with base64url-encoded fields
97
+ * @returns complete 3-part JWT string
98
+ */
99
+ function assemble(unsignedToken, assertion) {
100
+ if (!unsignedToken) throw new Error("Cannot assemble JWT from empty token");
101
+ if (unsignedToken.split(".").length !== 2) throw new Error("Cannot assemble JWT: expected unsigned token with exactly 2 parts (headerB64.bodyB64)");
102
+ if (!assertion || !assertion.authenticatorData || !assertion.clientDataJSON || !assertion.signature) throw new Error("Cannot assemble JWT: assertion must contain authenticatorData, clientDataJSON, and signature");
103
+ return `${unsignedToken}.${(0, _ocap_util.toBase64)(JSON.stringify(assertion))}`;
104
+ }
79
105
  function decode(token, bodyOnly = true) {
80
106
  const [headerB64, bodyB64, sigB64] = token.split(".");
81
107
  const header = JSON.parse((0, _ocap_util.fromBase64)(headerB64).toString());
@@ -158,14 +184,27 @@ async function verify(token, signerPk, options) {
158
184
  return false;
159
185
  }
160
186
  }
187
+ const alg = header.alg.toLowerCase();
188
+ if (alg === "passkey") {
189
+ const [, , sigB64] = token.split(".");
190
+ const assertionRaw = JSON.parse((0, _ocap_util.fromBase64)(sigB64).toString());
191
+ if (!assertionRaw.authenticatorData || !assertionRaw.clientDataJSON || !assertionRaw.signature) {
192
+ debug$1("verify.error.incompletePasskeyAssertion");
193
+ return false;
194
+ }
195
+ const challenge = hasher((0, _ocap_util.toHex)(`${headerB64}.${bodyB64}`));
196
+ const extra = JSON.stringify({
197
+ authenticatorData: assertionRaw.authenticatorData,
198
+ clientDataJSON: assertionRaw.clientDataJSON
199
+ });
200
+ return await (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.PASSKEY).verify(challenge, assertionRaw.signature, signerPk, extra);
201
+ }
161
202
  const signers = {
162
203
  secp256k1: (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.SECP256K1),
163
204
  es256k: (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.SECP256K1),
164
205
  ed25519: (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.ED25519),
165
- ethereum: (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.ETHEREUM),
166
- passkey: (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.PASSKEY)
206
+ ethereum: (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.ETHEREUM)
167
207
  };
168
- const alg = header.alg.toLowerCase();
169
208
  if (signers[alg]) {
170
209
  const msgHex = (0, _ocap_util.toHex)(`${headerB64}.${bodyB64}`);
171
210
  const coercedBodyVersion = body.version ? semver.default.coerce(body.version) : null;
@@ -194,6 +233,10 @@ const delegationTokenHeaders = {
194
233
  [_ocap_mcrypto.types.KeyType.ETHEREUM]: {
195
234
  alg: "Ethereum",
196
235
  typ: "DelegationToken"
236
+ },
237
+ [_ocap_mcrypto.types.KeyType.PASSKEY]: {
238
+ alg: "Passkey",
239
+ typ: "DelegationToken"
197
240
  }
198
241
  };
199
242
  async function signDelegationToken(signer, sk, payload) {
@@ -227,6 +270,45 @@ async function signDelegationToken(signer, sk, payload) {
227
270
  (0, _ocap_util.toBase64)((0, _ocap_mcrypto.getSigner)(type.pk).sign(msgHash, sk))
228
271
  ].join(".");
229
272
  }
273
+ /**
274
+ * Create an unsigned delegation token for passkey two-phase signing.
275
+ * Unlike signDelegationToken, this does not sign (passkey has no sk), and pk is passed directly.
276
+ */
277
+ async function signDelegationTokenUnsigned(signer, pk, payload) {
278
+ if ((0, _arcblock_did.isValid)(signer) === false) throw new Error("Cannot sign DelegationToken with invalid signer");
279
+ const type = (0, _arcblock_did.toTypeInfo)(signer);
280
+ if (type.pk === void 0) throw new Error("Cannot determine key type from signer");
281
+ const header = delegationTokenHeaders[type.pk];
282
+ const headerB64 = (0, _ocap_util.toBase64)((0, json_stable_stringify.default)(header));
283
+ const delegationSignerMethod = (0, _arcblock_did.extractMethod)(signer) || "abt";
284
+ const now = Math.floor(Date.now() / 1e3);
285
+ const pkHex = typeof pk === "string" ? pk : (0, _ocap_util.toHex)(pk);
286
+ const body = {
287
+ iss: (0, _arcblock_did.toDid)(signer, delegationSignerMethod),
288
+ sub: payload.sub,
289
+ iat: payload.iat || String(now),
290
+ nbf: payload.nbf || String(now),
291
+ exp: payload.exp || String(now + 300),
292
+ version: DELEGATION_TOKEN_VERSION,
293
+ ops: payload.ops,
294
+ pk: pkHex
295
+ };
296
+ if (payload.deny && payload.deny.length > 0) {
297
+ for (const d of payload.deny) if (!d.startsWith("fg:")) throw new Error(`Invalid deny pattern "${d}": must start with "fg:"`);
298
+ body.deny = payload.deny;
299
+ }
300
+ if (payload.delegation) body.delegation = payload.delegation;
301
+ return `${headerB64}.${(0, _ocap_util.toBase64)((0, json_stable_stringify.default)(body))}`;
302
+ }
303
+ /**
304
+ * Assemble a complete delegation token from an unsigned token and a passkey assertion.
305
+ */
306
+ function assembleDelegationToken(unsignedToken, assertion) {
307
+ if (!unsignedToken) throw new Error("Cannot assemble DelegationToken from empty token");
308
+ if (unsignedToken.split(".").length !== 2) throw new Error("Cannot assemble DelegationToken: expected unsigned token with exactly 2 parts (headerB64.bodyB64)");
309
+ if (!assertion || !assertion.authenticatorData || !assertion.clientDataJSON || !assertion.signature) throw new Error("Cannot assemble DelegationToken: assertion must contain authenticatorData, clientDataJSON, and signature");
310
+ return `${unsignedToken}.${(0, _ocap_util.toBase64)(JSON.stringify(assertion))}`;
311
+ }
230
312
  function decodeDelegationToken(token) {
231
313
  const parts = token.split(".");
232
314
  if (parts.length !== 3) throw new Error("Invalid delegation token format: expected 3 parts");
@@ -269,13 +351,27 @@ async function verifyDelegationToken(token) {
269
351
  debug$1("delegationToken.verify.error.futureIat");
270
352
  return false;
271
353
  }
354
+ const alg = header.alg.toLowerCase();
355
+ if (alg === "passkey") {
356
+ const [, , sigB64] = token.split(".");
357
+ const assertionRaw = JSON.parse((0, _ocap_util.fromBase64)(sigB64).toString());
358
+ if (!assertionRaw.authenticatorData || !assertionRaw.clientDataJSON || !assertionRaw.signature) {
359
+ debug$1("delegationToken.verify.error.incompletePasskeyAssertion");
360
+ return false;
361
+ }
362
+ const challenge = hasher((0, _ocap_util.toHex)(`${headerB64}.${bodyB64}`));
363
+ const extra = JSON.stringify({
364
+ authenticatorData: assertionRaw.authenticatorData,
365
+ clientDataJSON: assertionRaw.clientDataJSON
366
+ });
367
+ return await (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.PASSKEY).verify(challenge, assertionRaw.signature, body.pk, extra);
368
+ }
272
369
  const signers = {
273
370
  ed25519: (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.ED25519),
274
371
  es256k: (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.SECP256K1),
275
372
  secp256k1: (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.SECP256K1),
276
373
  ethereum: (0, _ocap_mcrypto.getSigner)(_ocap_mcrypto.types.KeyType.ETHEREUM)
277
374
  };
278
- const alg = header.alg.toLowerCase();
279
375
  if (!signers[alg]) {
280
376
  debug$1("delegationToken.verify.error.unknownAlg");
281
377
  return false;
@@ -293,11 +389,15 @@ function checkDelegationTokenScope(scope, { ops, deny }) {
293
389
  }
294
390
 
295
391
  //#endregion
392
+ exports.assemble = assemble;
393
+ exports.assembleDelegationToken = assembleDelegationToken;
296
394
  exports.checkDelegationTokenScope = checkDelegationTokenScope;
297
395
  exports.decode = decode;
298
396
  exports.decodeDelegationToken = decodeDelegationToken;
397
+ exports.getChallenge = getChallenge;
299
398
  exports.sign = sign;
300
399
  exports.signDelegationToken = signDelegationToken;
400
+ exports.signDelegationTokenUnsigned = signDelegationTokenUnsigned;
301
401
  exports.signV2 = signV2;
302
402
  exports.verify = verify;
303
403
  exports.verifyDelegationToken = verifyDelegationToken;
package/lib/index.d.cts CHANGED
@@ -35,6 +35,28 @@ type JwtVerifyOptions = Partial<{
35
35
  */
36
36
  declare function sign(signer: string, sk?: BytesType, payload?: {}, doSign?: boolean, version?: string): Promise<string>;
37
37
  declare function signV2(signer: string, sk?: BytesType, payload?: any): Promise<string>;
38
+ type PasskeyAssertion = {
39
+ authenticatorData: string;
40
+ clientDataJSON: string;
41
+ signature: string;
42
+ };
43
+ /**
44
+ * Compute the WebAuthn challenge for an unsigned JWT token.
45
+ * Always uses SHA3 hash-before-sign (v1.1.0 semantics, required for passkey).
46
+ *
47
+ * @param unsignedToken - the unsigned token (headerB64.bodyB64), may also accept 3-part tokens (ignores third segment)
48
+ * @returns hex-encoded SHA3 hash suitable as WebAuthn challenge
49
+ */
50
+ declare function getChallenge(unsignedToken: string): string;
51
+ /**
52
+ * Assemble a complete JWT from an unsigned token and a passkey assertion.
53
+ * The assertion is JSON-serialized and base64-encoded as the JWT's third segment.
54
+ *
55
+ * @param unsignedToken - the unsigned token (headerB64.bodyB64)
56
+ * @param assertion - WebAuthn assertion with base64url-encoded fields
57
+ * @returns complete 3-part JWT string
58
+ */
59
+ declare function assemble(unsignedToken: string, assertion: PasskeyAssertion): string;
38
60
  declare function decode(token: string, bodyOnly?: true): JwtBody;
39
61
  declare function decode(token: string, bodyOnly?: false): JwtToken;
40
62
  /**
@@ -88,6 +110,23 @@ declare function signDelegationToken(signer: string, sk: BytesType, payload: {
88
110
  nbf?: string;
89
111
  exp?: string;
90
112
  }): Promise<string>;
113
+ /**
114
+ * Create an unsigned delegation token for passkey two-phase signing.
115
+ * Unlike signDelegationToken, this does not sign (passkey has no sk), and pk is passed directly.
116
+ */
117
+ declare function signDelegationTokenUnsigned(signer: string, pk: BytesType, payload: {
118
+ sub: string;
119
+ ops: string[];
120
+ deny?: string[];
121
+ delegation?: string;
122
+ iat?: string;
123
+ nbf?: string;
124
+ exp?: string;
125
+ }): Promise<string>;
126
+ /**
127
+ * Assemble a complete delegation token from an unsigned token and a passkey assertion.
128
+ */
129
+ declare function assembleDelegationToken(unsignedToken: string, assertion: PasskeyAssertion): string;
91
130
  declare function decodeDelegationToken(token: string): DelegationToken;
92
131
  declare function verifyDelegationToken(token: string): Promise<boolean>;
93
132
  declare function checkDelegationTokenScope(scope: string, {
@@ -98,4 +137,4 @@ declare function checkDelegationTokenScope(scope: string, {
98
137
  deny?: string[];
99
138
  }): boolean;
100
139
  //#endregion
101
- export { DelegationToken, DelegationTokenBody, DelegationTokenHeader, JwtBody, JwtHeader, JwtToken, JwtVerifyOptions, checkDelegationTokenScope, decode, decodeDelegationToken, sign, signDelegationToken, signV2, verify, verifyDelegationToken };
140
+ export { DelegationToken, DelegationTokenBody, DelegationTokenHeader, JwtBody, JwtHeader, JwtToken, JwtVerifyOptions, PasskeyAssertion, assemble, assembleDelegationToken, checkDelegationTokenScope, decode, decodeDelegationToken, getChallenge, sign, signDelegationToken, signDelegationTokenUnsigned, signV2, verify, verifyDelegationToken };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@arcblock/jwt",
3
3
  "description": "JSON Web Token variant for arcblock DID solutions",
4
4
  "type": "module",
5
- "version": "1.29.21",
5
+ "version": "1.29.22",
6
6
  "author": {
7
7
  "name": "wangshijun",
8
8
  "email": "shijun@arcblock.io",
@@ -19,15 +19,15 @@
19
19
  "access": "public"
20
20
  },
21
21
  "dependencies": {
22
- "@arcblock/did": "1.29.21",
23
- "@ocap/mcrypto": "1.29.21",
24
- "@ocap/util": "1.29.21",
22
+ "@arcblock/did": "1.29.22",
23
+ "@ocap/mcrypto": "1.29.22",
24
+ "@ocap/util": "1.29.22",
25
25
  "debug": "^4.4.3",
26
26
  "json-stable-stringify": "^1.0.1",
27
27
  "semver": "^7.6.3"
28
28
  },
29
29
  "devDependencies": {
30
- "@ocap/wallet": "1.29.21",
30
+ "@ocap/wallet": "1.29.22",
31
31
  "@types/json-stable-stringify": "^1.0.36",
32
32
  "@types/node": "^22.7.5",
33
33
  "@types/semver": "^7.5.8",