@dwk/webauthn 0.1.0-beta.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.
Files changed (48) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +111 -0
  3. package/dist/cbor.d.ts +34 -0
  4. package/dist/cbor.d.ts.map +1 -0
  5. package/dist/cbor.js +144 -0
  6. package/dist/cbor.js.map +1 -0
  7. package/dist/config.d.ts +108 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +70 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/cose.d.ts +73 -0
  12. package/dist/cose.d.ts.map +1 -0
  13. package/dist/cose.js +191 -0
  14. package/dist/cose.js.map +1 -0
  15. package/dist/encoding.d.ts +28 -0
  16. package/dist/encoding.d.ts.map +1 -0
  17. package/dist/encoding.js +63 -0
  18. package/dist/encoding.js.map +1 -0
  19. package/dist/handler.d.ts +20 -0
  20. package/dist/handler.d.ts.map +1 -0
  21. package/dist/handler.js +101 -0
  22. package/dist/handler.js.map +1 -0
  23. package/dist/index.d.ts +29 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +28 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/log.d.ts +25 -0
  28. package/dist/log.d.ts.map +1 -0
  29. package/dist/log.js +26 -0
  30. package/dist/log.js.map +1 -0
  31. package/dist/rp.d.ts +21 -0
  32. package/dist/rp.d.ts.map +1 -0
  33. package/dist/rp.js +336 -0
  34. package/dist/rp.js.map +1 -0
  35. package/dist/verify.d.ts +135 -0
  36. package/dist/verify.d.ts.map +1 -0
  37. package/dist/verify.js +277 -0
  38. package/dist/verify.js.map +1 -0
  39. package/package.json +50 -0
  40. package/src/cbor.ts +168 -0
  41. package/src/config.ts +179 -0
  42. package/src/cose.ts +238 -0
  43. package/src/encoding.ts +68 -0
  44. package/src/handler.ts +135 -0
  45. package/src/index.ts +54 -0
  46. package/src/log.ts +25 -0
  47. package/src/rp.ts +492 -0
  48. package/src/verify.ts +471 -0
package/dist/rp.js ADDED
@@ -0,0 +1,336 @@
1
+ /**
2
+ * The per-relying-party Durable Object: the single-threaded consistency
3
+ * authority for WebAuthn challenge state and credential records.
4
+ *
5
+ * The stateless front door (`handler.ts`) routes a ceremony step to this object
6
+ * via the {@link INTERNAL_HEADERS.op} header and the request body; everything
7
+ * that must be strongly consistent — minting and single-use consumption of
8
+ * short-TTL challenges, and reading/writing credential records (public key,
9
+ * signature counter, transports) — happens here, where Cloudflare guarantees a
10
+ * single thread per relying party. Challenge and credential state are kept in DO
11
+ * SQLite (never KV: a stale challenge or counter is a security bug). Consumers
12
+ * bind this class as a Durable Object namespace.
13
+ */
14
+ import { DurableObject } from "cloudflare:workers";
15
+ import { INTERNAL_HEADERS, } from "./config";
16
+ import { base64urlToBytes, bytesToBase64url } from "./encoding";
17
+ import { WebAuthnLogEvent } from "./log";
18
+ import { verifyAuthentication, verifyRegistration, } from "./verify";
19
+ /** Number of random bytes in a challenge (WebAuthn recommends ≥16). */
20
+ const CHALLENGE_BYTES = 32;
21
+ /** Random bytes minted for a generated user handle. */
22
+ const USER_HANDLE_BYTES = 16;
23
+ export class WebAuthnObject extends DurableObject {
24
+ #sql;
25
+ constructor(state, env) {
26
+ super(state, env);
27
+ this.#sql = state.storage.sql;
28
+ this.#sql.exec(`CREATE TABLE IF NOT EXISTS challenges (
29
+ challenge TEXT PRIMARY KEY,
30
+ type TEXT NOT NULL,
31
+ user_id TEXT,
32
+ expires_at INTEGER NOT NULL
33
+ )`);
34
+ this.#sql.exec(`CREATE TABLE IF NOT EXISTS credentials (
35
+ credential_id TEXT PRIMARY KEY,
36
+ user_id TEXT NOT NULL,
37
+ public_key TEXT NOT NULL,
38
+ alg INTEGER NOT NULL,
39
+ counter INTEGER NOT NULL,
40
+ transports TEXT
41
+ )`);
42
+ this.#sql.exec(`CREATE INDEX IF NOT EXISTS credentials_user_id ON credentials (user_id)`);
43
+ }
44
+ async fetch(request) {
45
+ const op = request.headers.get(INTERNAL_HEADERS.op);
46
+ const config = this.#readConfig(request);
47
+ const now = Number(request.headers.get(INTERNAL_HEADERS.now)) || Date.now();
48
+ const body = await readJsonObject(request);
49
+ if (config === null)
50
+ return badRequest("missing config");
51
+ switch (op) {
52
+ case "register/options":
53
+ return this.#registerOptions(config, now, body);
54
+ case "register/verify":
55
+ return this.#registerVerify(config, now, body);
56
+ case "authenticate/options":
57
+ return this.#authenticateOptions(config, now, body);
58
+ case "authenticate/verify":
59
+ return this.#authenticateVerify(config, now, body);
60
+ default:
61
+ return new Response("Not Found", { status: 404 });
62
+ }
63
+ }
64
+ #readConfig(request) {
65
+ const raw = request.headers.get(INTERNAL_HEADERS.config);
66
+ if (!raw)
67
+ return null;
68
+ try {
69
+ return JSON.parse(raw);
70
+ }
71
+ catch {
72
+ return null;
73
+ }
74
+ }
75
+ // -- registration ----------------------------------------------------------
76
+ #registerOptions(config, now, body) {
77
+ const user = isObject(body.user) ? body.user : {};
78
+ const userId = typeof user.id === "string" && user.id.length > 0
79
+ ? user.id
80
+ : bytesToBase64url(randomBytes(USER_HANDLE_BYTES));
81
+ const name = typeof user.name === "string" ? user.name : "user";
82
+ const displayName = typeof user.displayName === "string" ? user.displayName : name;
83
+ const challenge = this.#mintChallenge("registration", userId, config, now);
84
+ const options = {
85
+ challenge,
86
+ rp: { id: config.rpId, name: config.rpName },
87
+ user: { id: userId, name, displayName },
88
+ pubKeyCredParams: config.algorithms.map((alg) => ({
89
+ type: "public-key",
90
+ alg,
91
+ })),
92
+ timeout: config.timeoutMs,
93
+ attestation: "none",
94
+ authenticatorSelection: {
95
+ userVerification: config.userVerification,
96
+ residentKey: "preferred",
97
+ },
98
+ excludeCredentials: this.#credentialDescriptors(userId),
99
+ };
100
+ return ok(options, WebAuthnLogEvent.RegisterOptions);
101
+ }
102
+ async #registerVerify(config, now, body) {
103
+ const response = isObject(body.response) ? body.response : null;
104
+ const clientDataB64 = response?.clientDataJSON;
105
+ const attestationB64 = response?.attestationObject;
106
+ if (typeof clientDataB64 !== "string" ||
107
+ typeof attestationB64 !== "string") {
108
+ return rejected(WebAuthnLogEvent.RegisterRejected, "bad_request");
109
+ }
110
+ const clientDataJSON = decode(clientDataB64);
111
+ const attestationObject = decode(attestationB64);
112
+ if (clientDataJSON === null || attestationObject === null) {
113
+ return rejected(WebAuthnLogEvent.RegisterRejected, "bad_request");
114
+ }
115
+ const row = this.#consumeChallenge(clientDataJSON, "registration", now);
116
+ if (row === null) {
117
+ return rejected(WebAuthnLogEvent.RegisterRejected, "challenge_mismatch");
118
+ }
119
+ const result = await verifyRegistration({
120
+ attestationObject,
121
+ clientDataJSON,
122
+ expectedChallenge: row.challenge,
123
+ expectedOrigins: config.origins,
124
+ expectedRpId: config.rpId,
125
+ requireUserVerification: config.userVerification === "required",
126
+ });
127
+ if (!result.verified) {
128
+ return rejected(WebAuthnLogEvent.RegisterRejected, result.reason);
129
+ }
130
+ const userId = row.user_id ?? "";
131
+ const transports = normalizeTransports(response?.transports ?? body.transports);
132
+ try {
133
+ this.#sql.exec(`INSERT INTO credentials
134
+ (credential_id, user_id, public_key, alg, counter, transports)
135
+ VALUES (?, ?, ?, ?, ?, ?)`, result.credential.id, userId, JSON.stringify(result.credential.publicKeyJwk), result.credential.alg, result.credential.counter, transports === null ? null : JSON.stringify(transports));
136
+ }
137
+ catch {
138
+ // PRIMARY KEY conflict: this credential is already registered.
139
+ return rejected(WebAuthnLogEvent.RegisterRejected, "credential_exists");
140
+ }
141
+ return ok({
142
+ verified: true,
143
+ credentialId: result.credential.id,
144
+ userId,
145
+ aaguid: result.credential.aaguid,
146
+ }, WebAuthnLogEvent.RegisterVerified);
147
+ }
148
+ // -- authentication --------------------------------------------------------
149
+ #authenticateOptions(config, now, body) {
150
+ const userId = typeof body.userId === "string" ? body.userId : null;
151
+ const challenge = this.#mintChallenge("authentication", userId, config, now);
152
+ const options = {
153
+ challenge,
154
+ timeout: config.timeoutMs,
155
+ rpId: config.rpId,
156
+ userVerification: config.userVerification,
157
+ };
158
+ // With a known user we scope the assertion to their credentials; without
159
+ // one we omit allowCredentials so a discoverable credential can be used.
160
+ if (userId !== null) {
161
+ options.allowCredentials = this.#credentialDescriptors(userId);
162
+ }
163
+ return ok(options, WebAuthnLogEvent.AuthenticateOptions);
164
+ }
165
+ async #authenticateVerify(config, now, body) {
166
+ const response = isObject(body.response) ? body.response : null;
167
+ const clientDataB64 = response?.clientDataJSON;
168
+ const authDataB64 = response?.authenticatorData;
169
+ const signatureB64 = response?.signature;
170
+ const credentialId = typeof body.id === "string" ? body.id : body.rawId;
171
+ if (typeof clientDataB64 !== "string" ||
172
+ typeof authDataB64 !== "string" ||
173
+ typeof signatureB64 !== "string" ||
174
+ typeof credentialId !== "string") {
175
+ return rejected(WebAuthnLogEvent.AuthenticateRejected, "bad_request");
176
+ }
177
+ const clientDataJSON = decode(clientDataB64);
178
+ const authenticatorData = decode(authDataB64);
179
+ const signature = decode(signatureB64);
180
+ if (clientDataJSON === null ||
181
+ authenticatorData === null ||
182
+ signature === null) {
183
+ return rejected(WebAuthnLogEvent.AuthenticateRejected, "bad_request");
184
+ }
185
+ const row = this.#consumeChallenge(clientDataJSON, "authentication", now);
186
+ if (row === null) {
187
+ return rejected(WebAuthnLogEvent.AuthenticateRejected, "challenge_mismatch");
188
+ }
189
+ const credential = this.#sql
190
+ .exec("SELECT * FROM credentials WHERE credential_id = ?", credentialId)
191
+ .toArray()[0];
192
+ if (!credential) {
193
+ return rejected(WebAuthnLogEvent.AuthenticateRejected, "no_credential");
194
+ }
195
+ // When the ceremony was scoped to a user, the asserted credential MUST be
196
+ // one of theirs.
197
+ if (row.user_id !== null && credential.user_id !== row.user_id) {
198
+ return rejected(WebAuthnLogEvent.AuthenticateRejected, "no_credential");
199
+ }
200
+ const result = await verifyAuthentication({
201
+ authenticatorData,
202
+ clientDataJSON,
203
+ signature,
204
+ expectedChallenge: row.challenge,
205
+ expectedOrigins: config.origins,
206
+ expectedRpId: config.rpId,
207
+ requireUserVerification: config.userVerification === "required",
208
+ credentialPublicKeyJwk: JSON.parse(credential.public_key),
209
+ credentialAlg: credential.alg,
210
+ storedCounter: credential.counter,
211
+ });
212
+ if (!result.verified) {
213
+ return rejected(WebAuthnLogEvent.AuthenticateRejected, result.reason);
214
+ }
215
+ this.#sql.exec("UPDATE credentials SET counter = ? WHERE credential_id = ?", result.newCounter, credentialId);
216
+ return ok({
217
+ verified: true,
218
+ credentialId,
219
+ userId: credential.user_id,
220
+ }, WebAuthnLogEvent.AuthenticateVerified);
221
+ }
222
+ // -- challenge state -------------------------------------------------------
223
+ /** Mint, store, and return a fresh challenge; prune expired rows first. */
224
+ #mintChallenge(type, userId, config, now) {
225
+ this.#sql.exec("DELETE FROM challenges WHERE expires_at < ?", now);
226
+ const challenge = bytesToBase64url(randomBytes(CHALLENGE_BYTES));
227
+ this.#sql.exec(`INSERT INTO challenges (challenge, type, user_id, expires_at)
228
+ VALUES (?, ?, ?, ?)`, challenge, type, userId, now + config.challengeTtlSeconds * 1000);
229
+ return challenge;
230
+ }
231
+ /**
232
+ * Find the stored challenge named in `clientDataJSON`, of the expected type
233
+ * and unexpired, and delete it (single use). Returns the row or `null` when no
234
+ * live matching challenge exists. The challenge is consumed even on a later
235
+ * verification failure, so a captured ceremony cannot be replayed.
236
+ */
237
+ #consumeChallenge(clientDataJSON, type, now) {
238
+ let challenge;
239
+ try {
240
+ const parsed = JSON.parse(new TextDecoder().decode(clientDataJSON));
241
+ if (typeof parsed.challenge !== "string")
242
+ return null;
243
+ challenge = parsed.challenge;
244
+ }
245
+ catch {
246
+ return null;
247
+ }
248
+ const row = this.#sql
249
+ .exec("SELECT * FROM challenges WHERE challenge = ? AND type = ?", challenge, type)
250
+ .toArray()[0];
251
+ if (!row)
252
+ return null;
253
+ this.#sql.exec("DELETE FROM challenges WHERE challenge = ?", challenge);
254
+ if (row.expires_at < now)
255
+ return null;
256
+ return row;
257
+ }
258
+ /** Build the credential-descriptor list for a user (exclude / allow lists). */
259
+ #credentialDescriptors(userId) {
260
+ return this.#sql
261
+ .exec("SELECT * FROM credentials WHERE user_id = ?", userId)
262
+ .toArray()
263
+ .map((row) => {
264
+ const transports = parseTransports(row.transports);
265
+ return {
266
+ type: "public-key",
267
+ id: row.credential_id,
268
+ ...(transports ? { transports } : {}),
269
+ };
270
+ });
271
+ }
272
+ }
273
+ // ---------------------------------------------------------------------------
274
+ // Module-level helpers
275
+ // ---------------------------------------------------------------------------
276
+ function randomBytes(length) {
277
+ return crypto.getRandomValues(new Uint8Array(length));
278
+ }
279
+ function isObject(value) {
280
+ return typeof value === "object" && value !== null && !Array.isArray(value);
281
+ }
282
+ /** Base64url-decode a field, returning `null` if it is not decodable. */
283
+ function decode(input) {
284
+ try {
285
+ return base64urlToBytes(input);
286
+ }
287
+ catch {
288
+ return null;
289
+ }
290
+ }
291
+ async function readJsonObject(request) {
292
+ try {
293
+ const parsed = (await request.json());
294
+ return isObject(parsed) ? parsed : {};
295
+ }
296
+ catch {
297
+ return {};
298
+ }
299
+ }
300
+ /** Coerce a client-supplied transports value to a string array, or `null`. */
301
+ function normalizeTransports(value) {
302
+ if (!Array.isArray(value))
303
+ return null;
304
+ const transports = value.filter((t) => typeof t === "string");
305
+ return transports.length > 0 ? transports : null;
306
+ }
307
+ /** Parse the stored transports JSON back to an array, or `null`. */
308
+ function parseTransports(stored) {
309
+ if (stored === null)
310
+ return null;
311
+ try {
312
+ const parsed = JSON.parse(stored);
313
+ return normalizeTransports(parsed);
314
+ }
315
+ catch {
316
+ return null;
317
+ }
318
+ }
319
+ /** A `200` JSON response carrying the ceremony outcome event for the front door. */
320
+ function ok(body, event) {
321
+ return json(200, body, { [INTERNAL_HEADERS.event]: event });
322
+ }
323
+ /** A `400` JSON rejection carrying the outcome event and a stable reason. */
324
+ function rejected(event, reason) {
325
+ return json(400, { verified: false, error: reason }, { [INTERNAL_HEADERS.event]: event, [INTERNAL_HEADERS.reason]: reason });
326
+ }
327
+ function badRequest(message) {
328
+ return json(400, { error: message });
329
+ }
330
+ function json(status, body, headers = {}) {
331
+ return new Response(JSON.stringify(body), {
332
+ status,
333
+ headers: { "content-type": "application/json; charset=utf-8", ...headers },
334
+ });
335
+ }
336
+ //# sourceMappingURL=rp.js.map
package/dist/rp.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rp.js","sourceRoot":"","sources":["../src/rp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EACL,gBAAgB,GAGjB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,EACL,oBAAoB,EACpB,kBAAkB,GAEnB,MAAM,UAAU,CAAC;AAoBlB,uEAAuE;AACvE,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,uDAAuD;AACvD,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAE7B,MAAM,OAAO,cAAe,SAAQ,aAA0B;IACnD,IAAI,CAAa;IAE1B,YAAY,KAAyB,EAAE,GAAgB;QACrD,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAClB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,IAAI,CACZ;;;;;SAKG,CACJ,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,IAAI,CACZ;;;;;;;SAOG,CACJ,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,IAAI,CACZ,yEAAyE,CAC1E,CAAC;IACJ,CAAC;IAEQ,KAAK,CAAC,KAAK,CAAC,OAAgB;QACnC,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;QACpD,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;QAC5E,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,UAAU,CAAC,gBAAgB,CAAC,CAAC;QAEzD,QAAQ,EAAE,EAAE,CAAC;YACX,KAAK,kBAAkB;gBACrB,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YAClD,KAAK,iBAAiB;gBACpB,OAAO,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YACjD,KAAK,sBAAsB;gBACzB,OAAO,IAAI,CAAC,oBAAoB,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YACtD,KAAK,qBAAqB;gBACxB,OAAO,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YACrD;gBACE,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED,WAAW,CAAC,OAAgB;QAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QACzD,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,6EAA6E;IAE7E,gBAAgB,CACd,MAAuB,EACvB,GAAW,EACX,IAA6B;QAE7B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,MAAM,MAAM,GACV,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC;YAC/C,CAAC,CAAC,IAAI,CAAC,EAAE;YACT,CAAC,CAAC,gBAAgB,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;QAChE,MAAM,WAAW,GACf,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;QAEjE,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;QAE3E,MAAM,OAAO,GAAG;YACd,SAAS;YACT,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE;YAC5C,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE;YACvC,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBAChD,IAAI,EAAE,YAAY;gBAClB,GAAG;aACJ,CAAC,CAAC;YACH,OAAO,EAAE,MAAM,CAAC,SAAS;YACzB,WAAW,EAAE,MAAM;YACnB,sBAAsB,EAAE;gBACtB,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;gBACzC,WAAW,EAAE,WAAW;aACzB;YACD,kBAAkB,EAAE,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC;SACxD,CAAC;QACF,OAAO,EAAE,CAAC,OAAO,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,MAAuB,EACvB,GAAW,EACX,IAA6B;QAE7B,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;QAChE,MAAM,aAAa,GAAG,QAAQ,EAAE,cAAc,CAAC;QAC/C,MAAM,cAAc,GAAG,QAAQ,EAAE,iBAAiB,CAAC;QACnD,IACE,OAAO,aAAa,KAAK,QAAQ;YACjC,OAAO,cAAc,KAAK,QAAQ,EAClC,CAAC;YACD,OAAO,QAAQ,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;QACpE,CAAC;QAED,MAAM,cAAc,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;QAC7C,MAAM,iBAAiB,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;QACjD,IAAI,cAAc,KAAK,IAAI,IAAI,iBAAiB,KAAK,IAAI,EAAE,CAAC;YAC1D,OAAO,QAAQ,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;QACpE,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,CAAC,cAAc,EAAE,cAAc,EAAE,GAAG,CAAC,CAAC;QACxE,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,OAAO,QAAQ,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,oBAAoB,CAAC,CAAC;QAC3E,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC;YACtC,iBAAiB;YACjB,cAAc;YACd,iBAAiB,EAAE,GAAG,CAAC,SAAS;YAChC,eAAe,EAAE,MAAM,CAAC,OAAO;YAC/B,YAAY,EAAE,MAAM,CAAC,IAAI;YACzB,uBAAuB,EAAE,MAAM,CAAC,gBAAgB,KAAK,UAAU;SAChE,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrB,OAAO,QAAQ,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QACpE,CAAC;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,mBAAmB,CACpC,QAAQ,EAAE,UAAU,IAAI,IAAI,CAAC,UAAU,CACxC,CAAC;QACF,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,IAAI,CACZ;;mCAE2B,EAC3B,MAAM,CAAC,UAAU,CAAC,EAAE,EACpB,MAAM,EACN,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,EAC9C,MAAM,CAAC,UAAU,CAAC,GAAG,EACrB,MAAM,CAAC,UAAU,CAAC,OAAO,EACzB,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CACxD,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;YAC/D,OAAO,QAAQ,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAC;QAC1E,CAAC;QAED,OAAO,EAAE,CACP;YACE,QAAQ,EAAE,IAAI;YACd,YAAY,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE;YAClC,MAAM;YACN,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,MAAM;SACjC,EACD,gBAAgB,CAAC,gBAAgB,CAClC,CAAC;IACJ,CAAC;IAED,6EAA6E;IAE7E,oBAAoB,CAClB,MAAuB,EACvB,GAAW,EACX,IAA6B;QAE7B,MAAM,MAAM,GAAG,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QACpE,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CACnC,gBAAgB,EAChB,MAAM,EACN,MAAM,EACN,GAAG,CACJ,CAAC;QAEF,MAAM,OAAO,GAA4B;YACvC,SAAS;YACT,OAAO,EAAE,MAAM,CAAC,SAAS;YACzB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;SAC1C,CAAC;QACF,yEAAyE;QACzE,yEAAyE;QACzE,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,EAAE,CAAC,OAAO,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,mBAAmB,CACvB,MAAuB,EACvB,GAAW,EACX,IAA6B;QAE7B,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;QAChE,MAAM,aAAa,GAAG,QAAQ,EAAE,cAAc,CAAC;QAC/C,MAAM,WAAW,GAAG,QAAQ,EAAE,iBAAiB,CAAC;QAChD,MAAM,YAAY,GAAG,QAAQ,EAAE,SAAS,CAAC;QACzC,MAAM,YAAY,GAAG,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;QACxE,IACE,OAAO,aAAa,KAAK,QAAQ;YACjC,OAAO,WAAW,KAAK,QAAQ;YAC/B,OAAO,YAAY,KAAK,QAAQ;YAChC,OAAO,YAAY,KAAK,QAAQ,EAChC,CAAC;YACD,OAAO,QAAQ,CAAC,gBAAgB,CAAC,oBAAoB,EAAE,aAAa,CAAC,CAAC;QACxE,CAAC;QAED,MAAM,cAAc,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;QAC7C,MAAM,iBAAiB,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;QACvC,IACE,cAAc,KAAK,IAAI;YACvB,iBAAiB,KAAK,IAAI;YAC1B,SAAS,KAAK,IAAI,EAClB,CAAC;YACD,OAAO,QAAQ,CAAC,gBAAgB,CAAC,oBAAoB,EAAE,aAAa,CAAC,CAAC;QACxE,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,CAAC,cAAc,EAAE,gBAAgB,EAAE,GAAG,CAAC,CAAC;QAC1E,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,OAAO,QAAQ,CACb,gBAAgB,CAAC,oBAAoB,EACrC,oBAAoB,CACrB,CAAC;QACJ,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI;aACzB,IAAI,CACH,mDAAmD,EACnD,YAAY,CACb;aACA,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QAChB,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,QAAQ,CAAC,gBAAgB,CAAC,oBAAoB,EAAE,eAAe,CAAC,CAAC;QAC1E,CAAC;QACD,0EAA0E;QAC1E,iBAAiB;QACjB,IAAI,GAAG,CAAC,OAAO,KAAK,IAAI,IAAI,UAAU,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC;YAC/D,OAAO,QAAQ,CAAC,gBAAgB,CAAC,oBAAoB,EAAE,eAAe,CAAC,CAAC;QAC1E,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC;YACxC,iBAAiB;YACjB,cAAc;YACd,SAAS;YACT,iBAAiB,EAAE,GAAG,CAAC,SAAS;YAChC,eAAe,EAAE,MAAM,CAAC,OAAO;YAC/B,YAAY,EAAE,MAAM,CAAC,IAAI;YACzB,uBAAuB,EAAE,MAAM,CAAC,gBAAgB,KAAK,UAAU;YAC/D,sBAAsB,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,CAAe;YACvE,aAAa,EAAE,UAAU,CAAC,GAAG;YAC7B,aAAa,EAAE,UAAU,CAAC,OAAO;SAClC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrB,OAAO,QAAQ,CAAC,gBAAgB,CAAC,oBAAoB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QACxE,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,IAAI,CACZ,4DAA4D,EAC5D,MAAM,CAAC,UAAU,EACjB,YAAY,CACb,CAAC;QAEF,OAAO,EAAE,CACP;YACE,QAAQ,EAAE,IAAI;YACd,YAAY;YACZ,MAAM,EAAE,UAAU,CAAC,OAAO;SAC3B,EACD,gBAAgB,CAAC,oBAAoB,CACtC,CAAC;IACJ,CAAC;IAED,6EAA6E;IAE7E,2EAA2E;IAC3E,cAAc,CACZ,IAAuC,EACvC,MAAqB,EACrB,MAAuB,EACvB,GAAW;QAEX,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,6CAA6C,EAAE,GAAG,CAAC,CAAC;QACnE,MAAM,SAAS,GAAG,gBAAgB,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC;QACjE,IAAI,CAAC,IAAI,CAAC,IAAI,CACZ;2BACqB,EACrB,SAAS,EACT,IAAI,EACJ,MAAM,EACN,GAAG,GAAG,MAAM,CAAC,mBAAmB,GAAG,IAAI,CACxC,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;;OAKG;IACH,iBAAiB,CACf,cAA0B,EAC1B,IAAuC,EACvC,GAAW;QAEX,IAAI,SAAiB,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAEjE,CAAC;YACF,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAC;YACtD,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI;aAClB,IAAI,CACH,2DAA2D,EAC3D,SAAS,EACT,IAAI,CACL;aACA,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QAChB,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,4CAA4C,EAAE,SAAS,CAAC,CAAC;QACxE,IAAI,GAAG,CAAC,UAAU,GAAG,GAAG;YAAE,OAAO,IAAI,CAAC;QACtC,OAAO,GAAG,CAAC;IACb,CAAC;IAED,+EAA+E;IAC/E,sBAAsB,CACpB,MAAc;QAEd,OAAO,IAAI,CAAC,IAAI;aACb,IAAI,CACH,6CAA6C,EAC7C,MAAM,CACP;aACA,OAAO,EAAE;aACT,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YACX,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACnD,OAAO;gBACL,IAAI,EAAE,YAAqB;gBAC3B,EAAE,EAAE,GAAG,CAAC,aAAa;gBACrB,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACtC,CAAC;QACJ,CAAC,CAAC,CAAC;IACP,CAAC;CACF;AAED,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E,SAAS,WAAW,CAAC,MAAc;IACjC,OAAO,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,yEAAyE;AACzE,SAAS,MAAM,CAAC,KAAa;IAC3B,IAAI,CAAC;QACH,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,cAAc,CAC3B,OAAgB;IAEhB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAY,CAAC;QACjD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,SAAS,mBAAmB,CAAC,KAAc;IACzC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;IAC3E,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACnD,CAAC;AAED,oEAAoE;AACpE,SAAS,eAAe,CAAC,MAAqB;IAC5C,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAY,CAAC;QAC7C,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,oFAAoF;AACpF,SAAS,EAAE,CAAC,IAAa,EAAE,KAAuB;IAChD,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED,6EAA6E;AAC7E,SAAS,QAAQ,CACf,KAAuB,EACvB,MAAoC;IAEpC,OAAO,IAAI,CACT,GAAG,EACH,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAClC,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CACvE,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,OAAe;IACjC,OAAO,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,IAAI,CACX,MAAc,EACd,IAAa,EACb,UAAkC,EAAE;IAEpC,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;QACxC,MAAM;QACN,OAAO,EAAE,EAAE,cAAc,EAAE,iCAAiC,EAAE,GAAG,OAAO,EAAE;KAC3E,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * The WebAuthn ceremony verification core: parsing `clientDataJSON` and
3
+ * authenticator data, then verifying a registration (attestation) and an
4
+ * authentication (assertion) per the
5
+ * [W3C WebAuthn Level 3](https://www.w3.org/TR/webauthn-3/) verification
6
+ * procedures (§7.1 and §7.2).
7
+ *
8
+ * These functions are **pure** and runtime-agnostic — plain-data in, result
9
+ * out, Web Crypto the only I/O — so they unit-test in isolation and never read
10
+ * Cloudflare bindings. The relying party state (single-use challenges, stored
11
+ * credential records, the signature counter) lives in the Durable Object, which
12
+ * supplies the expected values to these functions and persists what they return.
13
+ *
14
+ * Attestation scope: the relying party requests `attestation: "none"`, so the
15
+ * accepted attestation statement formats are `none` and `packed` *self*
16
+ * attestation (no `x5c`). Verifying a full attestation-certificate chain (basic
17
+ * / AttCA attestation) is intentionally out of scope — it proves authenticator
18
+ * provenance, which a personal-site relying party does not need. A format
19
+ * carrying `x5c` is rejected rather than silently trusted.
20
+ */
21
+ /** Stable, locale-independent verification failure codes. */
22
+ export type VerifyFailureReason = "client_data_malformed" | "client_data_type" | "challenge_mismatch" | "origin_mismatch" | "attestation_malformed" | "attestation_format_unsupported" | "auth_data_malformed" | "rp_id_mismatch" | "user_not_present" | "user_not_verified" | "no_credential_data" | "credential_key_unsupported" | "signature_invalid" | "counter_regression";
23
+ /** The decoded WebAuthn `clientDataJSON`. */
24
+ export interface ClientData {
25
+ readonly type: string;
26
+ readonly challenge: string;
27
+ readonly origin: string;
28
+ readonly crossOrigin?: boolean;
29
+ }
30
+ /** Authenticator-data flag bits (WebAuthn §6.1). */
31
+ export interface AuthDataFlags {
32
+ /** User Present. */
33
+ readonly up: boolean;
34
+ /** User Verified. */
35
+ readonly uv: boolean;
36
+ /** Attested credential data included. */
37
+ readonly at: boolean;
38
+ /** Extension data included. */
39
+ readonly ed: boolean;
40
+ }
41
+ /** Parsed attested credential data (present on registration). */
42
+ export interface AttestedCredentialData {
43
+ readonly aaguid: Uint8Array;
44
+ readonly credentialId: Uint8Array;
45
+ /** The credential public key, still a COSE_Key map. */
46
+ readonly credentialPublicKey: Map<unknown, unknown>;
47
+ }
48
+ /** Parsed authenticator data (WebAuthn §6.1). */
49
+ export interface AuthenticatorData {
50
+ readonly rpIdHash: Uint8Array;
51
+ readonly flags: AuthDataFlags;
52
+ readonly signCount: number;
53
+ readonly attestedCredentialData?: AttestedCredentialData;
54
+ }
55
+ /** Parse `clientDataJSON` bytes, or `null` if it is not a valid client-data object. */
56
+ export declare function parseClientData(bytes: Uint8Array): ClientData | null;
57
+ /**
58
+ * Parse authenticator data. The fixed header is 37 bytes (32 rpIdHash + 1 flags
59
+ * + 4 signCount); when the AT flag is set, attested credential data follows
60
+ * (16 aaguid + 2 credentialIdLength + L credentialId + the COSE public key).
61
+ * Returns `null` on any structural problem.
62
+ */
63
+ export declare function parseAuthenticatorData(bytes: Uint8Array): AuthenticatorData | null;
64
+ /** Inputs to {@link verifyRegistration}. */
65
+ export interface RegistrationVerifyInput {
66
+ /** The CBOR attestation object bytes. */
67
+ readonly attestationObject: Uint8Array;
68
+ /** The raw `clientDataJSON` bytes. */
69
+ readonly clientDataJSON: Uint8Array;
70
+ /** The challenge the relying party issued (base64url). */
71
+ readonly expectedChallenge: string;
72
+ /** Acceptable client origins. */
73
+ readonly expectedOrigins: readonly string[];
74
+ /** The relying party id (effective domain). */
75
+ readonly expectedRpId: string;
76
+ /** Whether the User Verified flag must be set. */
77
+ readonly requireUserVerification: boolean;
78
+ }
79
+ /** A verified credential ready to persist. */
80
+ export interface VerifiedCredential {
81
+ /** Credential id (base64url). */
82
+ readonly id: string;
83
+ /** Public key as a JWK. */
84
+ readonly publicKeyJwk: JsonWebKey;
85
+ /** COSE algorithm the key signs with. */
86
+ readonly alg: number;
87
+ /** Initial signature counter. */
88
+ readonly counter: number;
89
+ /** Authenticator AAGUID (base64url). */
90
+ readonly aaguid: string;
91
+ }
92
+ /** Result of {@link verifyRegistration}. */
93
+ export type RegistrationVerifyResult = {
94
+ readonly verified: true;
95
+ readonly credential: VerifiedCredential;
96
+ } | {
97
+ readonly verified: false;
98
+ readonly reason: VerifyFailureReason;
99
+ };
100
+ /** Verify a registration (attestation) ceremony (WebAuthn §7.1). */
101
+ export declare function verifyRegistration(input: RegistrationVerifyInput): Promise<RegistrationVerifyResult>;
102
+ /** Inputs to {@link verifyAuthentication}. */
103
+ export interface AuthenticationVerifyInput {
104
+ /** The raw authenticator data bytes. */
105
+ readonly authenticatorData: Uint8Array;
106
+ /** The raw `clientDataJSON` bytes. */
107
+ readonly clientDataJSON: Uint8Array;
108
+ /** The assertion signature bytes. */
109
+ readonly signature: Uint8Array;
110
+ /** The challenge the relying party issued (base64url). */
111
+ readonly expectedChallenge: string;
112
+ /** Acceptable client origins. */
113
+ readonly expectedOrigins: readonly string[];
114
+ /** The relying party id (effective domain). */
115
+ readonly expectedRpId: string;
116
+ /** Whether the User Verified flag must be set. */
117
+ readonly requireUserVerification: boolean;
118
+ /** The stored credential public key (JWK). */
119
+ readonly credentialPublicKeyJwk: JsonWebKey;
120
+ /** The stored credential's COSE algorithm. */
121
+ readonly credentialAlg: number;
122
+ /** The last signature counter recorded for this credential. */
123
+ readonly storedCounter: number;
124
+ }
125
+ /** Result of {@link verifyAuthentication}. */
126
+ export type AuthenticationVerifyResult = {
127
+ readonly verified: true;
128
+ readonly newCounter: number;
129
+ } | {
130
+ readonly verified: false;
131
+ readonly reason: VerifyFailureReason;
132
+ };
133
+ /** Verify an authentication (assertion) ceremony (WebAuthn §7.2). */
134
+ export declare function verifyAuthentication(input: AuthenticationVerifyInput): Promise<AuthenticationVerifyResult>;
135
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}