@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/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026 David W. Keith
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # `@dwk/webauthn`
2
+
3
+ > WebAuthn / passkeys relying party: registration + authentication ceremonies
4
+ > over a per-relying-party Durable Object for challenge state and credential
5
+ > records.
6
+
7
+ Part of the [`@dwk` IndieWeb + Solid cohort](../../README.md). See the
8
+ [package specification](../../spec/packages/webauthn.md) for the full
9
+ requirements.
10
+
11
+ > **Status: exploratory, lowest priority.** This package is filed for
12
+ > completeness. A WebAuthn relying party is a clean technical fit for Workers —
13
+ > ceremonies plus a credential store, with challenge state mapping neatly onto a
14
+ > short-TTL Durable Object — but it is a step *away* from the "implement open
15
+ > *web-presence* standards" thesis and *toward* generic authentication. Prefer
16
+ > [`@dwk/indieauth`](../indieauth) as a site's primary identity mechanism; reach
17
+ > for this only if you specifically need passkeys. Tracked in
18
+ > [#64](https://github.com/davidwkeith/workers/issues/64).
19
+
20
+ ## What it provides
21
+
22
+ A single factory, `createWebAuthn(config)`, returning a `fetch`-style handler
23
+ that exposes the four ceremony endpoints (mountable under any path prefix):
24
+
25
+ | Endpoint | Purpose |
26
+ | --- | --- |
27
+ | `POST /register/options` | Issue `PublicKeyCredentialCreationOptions` + a fresh challenge |
28
+ | `POST /register/verify` | Verify the attestation and store the credential |
29
+ | `POST /authenticate/options` | Issue `PublicKeyCredentialRequestOptions` + a fresh challenge |
30
+ | `POST /authenticate/verify` | Verify the assertion and advance the signature counter |
31
+
32
+ It also exports the `WebAuthnObject` Durable Object class (bind it as a
33
+ namespace), and the pure verification primitives (`verifyRegistration`,
34
+ `verifyAuthentication`, `parseClientData`, `parseAuthenticatorData`) for callers
35
+ who want to drive the ceremonies themselves.
36
+
37
+ ## Architecture
38
+
39
+ A stateless front door routes each ceremony step to a per-relying-party Durable
40
+ Object keyed by `rpId`. The Durable Object is the consistency authority: it mints
41
+ and **single-use-consumes** short-TTL challenges and reads/writes credential
42
+ records (public key, signature counter, transports) in its SQLite, all strongly
43
+ consistent. **Challenge and credential state never live in KV** — a stale
44
+ challenge or counter is a security bug (see
45
+ [non-functional requirements](../../spec/non-functional-requirements.md)).
46
+
47
+ Verification runs entirely on **Web Crypto**: a minimal CBOR decoder reads the
48
+ attestation object and COSE public key, which is imported as a JWK and used to
49
+ verify attestation/assertion signatures (ECDSA signatures are unwrapped from
50
+ ASN.1 DER to the raw form Web Crypto expects). The only runtime dependency is
51
+ [`@dwk/log`](../log).
52
+
53
+ ### Attestation scope
54
+
55
+ The relying party requests `attestation: "none"`, so the accepted attestation
56
+ statement formats are **`none`** and **`packed` self-attestation** (no `x5c`).
57
+ Verifying a full attestation-certificate chain (basic / AttCA attestation) is
58
+ intentionally out of scope — it proves authenticator provenance, which a
59
+ personal-site relying party does not need. A statement carrying `x5c` is rejected
60
+ rather than silently trusted.
61
+
62
+ ## Usage
63
+
64
+ ```ts
65
+ import { createWebAuthn, WebAuthnObject } from "@dwk/webauthn";
66
+
67
+ // Bind a Durable Object namespace `WEBAUTHN` to the WebAuthnObject class.
68
+ export { WebAuthnObject };
69
+
70
+ const webauthn = createWebAuthn({
71
+ rpId: "example.com",
72
+ rpName: "Example",
73
+ origin: "https://example.com", // or an array of accepted origins
74
+ // optional:
75
+ // algorithms: [-7, -257], // COSE alg ids (ES256, RS256) — the default
76
+ // challengeTtlSeconds: 300,
77
+ // userVerification: "preferred",
78
+ });
79
+
80
+ export default {
81
+ fetch(request, env, ctx) {
82
+ return webauthn(request, env, ctx); // mount under any prefix you like
83
+ },
84
+ };
85
+ ```
86
+
87
+ The browser glue is standard: pass the `/register/options` (or
88
+ `/authenticate/options`) JSON to `navigator.credentials.create()` /
89
+ `.get()` after base64url-decoding the binary fields, then base64url-encode the
90
+ credential response and POST it to the matching `verify` endpoint.
91
+
92
+ ## Configuration
93
+
94
+ | Field | Default | Notes |
95
+ | --- | --- | --- |
96
+ | `rpId` | — (required) | Relying party id (effective domain). |
97
+ | `rpName` | — (required) | Human-readable name for the authenticator UI. |
98
+ | `origin` | — (required) | Accepted client origin(s); matched exactly. |
99
+ | `algorithms` | `[-7, -257]` | Accepted COSE algorithms, most-preferred first. |
100
+ | `challengeTtlSeconds` | `300` | Challenge lifetime. |
101
+ | `timeoutMs` | `60000` | Ceremony timeout advertised to the client. |
102
+ | `userVerification` | `"preferred"` | `"required"` also rejects assertions whose UV flag is unset. |
103
+ | `logger` / `metrics` | no-op | Injectable `@dwk/log` seams for ceremony outcomes. |
104
+
105
+ Per the [composition contract](../../spec/composition-contract.md), the package
106
+ never reads the global environment: all config is passed into the factory, and a
107
+ missing `WEBAUTHN` Durable Object binding fails loudly at startup.
108
+
109
+ ## License
110
+
111
+ ISC
package/dist/cbor.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * A minimal CBOR (RFC 8949) decoder — only the subset WebAuthn needs.
3
+ *
4
+ * Two WebAuthn structures are CBOR: the attestation object (a string-keyed map
5
+ * wrapping `fmt` / `attStmt` / `authData`) and the credential public key (a
6
+ * COSE_Key, an integer-keyed map). Decoding those needs unsigned and negative
7
+ * integers, byte and text strings, arrays, and maps — nothing else. We
8
+ * deliberately do **not** pull a general CBOR library: the script-size budget is
9
+ * tight (see `spec/non-functional-requirements.md`) and a focused decoder is
10
+ * easy to audit.
11
+ *
12
+ * Maps decode to `Map` so integer COSE labels survive as keys (a plain object
13
+ * would coerce them to strings and collide negative/positive labels by string
14
+ * form). The decoder reports how many bytes it consumed so a caller can locate
15
+ * the bytes that follow a variable-length structure (the COSE key embedded in
16
+ * authenticator data is followed by optional extension bytes).
17
+ */
18
+ /** A decoded CBOR value (the subset this decoder produces). */
19
+ export type CborValue = number | bigint | string | Uint8Array | CborValue[] | Map<CborValue, CborValue>;
20
+ /** A decoded value together with the number of input bytes it consumed. */
21
+ export interface CborDecoded {
22
+ readonly value: CborValue;
23
+ readonly length: number;
24
+ }
25
+ /** Thrown when the input is not valid CBOR (or uses an unsupported feature). */
26
+ export declare class CborError extends Error {
27
+ }
28
+ /**
29
+ * Decode the first CBOR data item starting at `start`. Returns the value and
30
+ * the number of bytes consumed; trailing bytes are ignored (the caller decides
31
+ * whether they are allowed).
32
+ */
33
+ export declare function decodeFirst(bytes: Uint8Array, start?: number): CborDecoded;
34
+ //# sourceMappingURL=cbor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cbor.d.ts","sourceRoot":"","sources":["../src/cbor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,+DAA+D;AAC/D,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,MAAM,GACN,UAAU,GACV,SAAS,EAAE,GACX,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAE9B,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,gFAAgF;AAChF,qBAAa,SAAU,SAAQ,KAAK;CAAG;AAEvC;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,SAAI,GAAG,WAAW,CAIrE"}
package/dist/cbor.js ADDED
@@ -0,0 +1,144 @@
1
+ /**
2
+ * A minimal CBOR (RFC 8949) decoder — only the subset WebAuthn needs.
3
+ *
4
+ * Two WebAuthn structures are CBOR: the attestation object (a string-keyed map
5
+ * wrapping `fmt` / `attStmt` / `authData`) and the credential public key (a
6
+ * COSE_Key, an integer-keyed map). Decoding those needs unsigned and negative
7
+ * integers, byte and text strings, arrays, and maps — nothing else. We
8
+ * deliberately do **not** pull a general CBOR library: the script-size budget is
9
+ * tight (see `spec/non-functional-requirements.md`) and a focused decoder is
10
+ * easy to audit.
11
+ *
12
+ * Maps decode to `Map` so integer COSE labels survive as keys (a plain object
13
+ * would coerce them to strings and collide negative/positive labels by string
14
+ * form). The decoder reports how many bytes it consumed so a caller can locate
15
+ * the bytes that follow a variable-length structure (the COSE key embedded in
16
+ * authenticator data is followed by optional extension bytes).
17
+ */
18
+ /** Thrown when the input is not valid CBOR (or uses an unsupported feature). */
19
+ export class CborError extends Error {
20
+ }
21
+ /**
22
+ * Decode the first CBOR data item starting at `start`. Returns the value and
23
+ * the number of bytes consumed; trailing bytes are ignored (the caller decides
24
+ * whether they are allowed).
25
+ */
26
+ export function decodeFirst(bytes, start = 0) {
27
+ const reader = new Reader(bytes, start);
28
+ const value = reader.readItem();
29
+ return { value, length: reader.offset - start };
30
+ }
31
+ class Reader {
32
+ offset;
33
+ #bytes;
34
+ #view;
35
+ constructor(bytes, start) {
36
+ this.#bytes = bytes;
37
+ this.#view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
38
+ this.offset = start;
39
+ }
40
+ readItem() {
41
+ const initial = this.#byte();
42
+ const major = initial >> 5;
43
+ const info = initial & 0x1f;
44
+ switch (major) {
45
+ case 0: // unsigned integer
46
+ return this.#argument(info);
47
+ case 1: {
48
+ // negative integer: encodes -(n + 1)
49
+ const n = this.#argument(info);
50
+ return typeof n === "bigint" ? -(n + 1n) : -(n + 1);
51
+ }
52
+ case 2: // byte string
53
+ return this.#bytesOfLength(this.#lengthArgument(info));
54
+ case 3: // text string
55
+ return new TextDecoder().decode(this.#bytesOfLength(this.#lengthArgument(info)));
56
+ case 4: {
57
+ // array
58
+ const len = this.#lengthArgument(info);
59
+ const items = [];
60
+ for (let i = 0; i < len; i++)
61
+ items.push(this.readItem());
62
+ return items;
63
+ }
64
+ case 5: {
65
+ // map
66
+ const len = this.#lengthArgument(info);
67
+ const map = new Map();
68
+ for (let i = 0; i < len; i++) {
69
+ const key = this.readItem();
70
+ map.set(key, this.readItem());
71
+ }
72
+ return map;
73
+ }
74
+ default:
75
+ // Tags (6) and simple/float (7) are not used by the WebAuthn subset.
76
+ throw new CborError(`unsupported CBOR major type ${major}`);
77
+ }
78
+ }
79
+ /** Read the integer argument that follows the initial byte. */
80
+ #argument(info) {
81
+ if (info < 24)
82
+ return info;
83
+ switch (info) {
84
+ case 24:
85
+ return this.#byte();
86
+ case 25: {
87
+ this.#need(2);
88
+ const v = this.#view.getUint16(this.offset);
89
+ this.offset += 2;
90
+ return v;
91
+ }
92
+ case 26: {
93
+ this.#need(4);
94
+ const v = this.#view.getUint32(this.offset);
95
+ this.offset += 4;
96
+ return v;
97
+ }
98
+ case 27: {
99
+ this.#need(8);
100
+ const v = this.#view.getBigUint64(this.offset);
101
+ this.offset += 8;
102
+ // Collapse to a number when it fits, so callers compare with `===`.
103
+ return v <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(v) : v;
104
+ }
105
+ default:
106
+ // 28-30 are reserved; 31 (indefinite length) is unsupported here.
107
+ throw new CborError(`unsupported CBOR additional info ${info}`);
108
+ }
109
+ }
110
+ /** Like {@link #argument} but as a JS number bounded for use as a length. */
111
+ #lengthArgument(info) {
112
+ const value = this.#argument(info);
113
+ if (typeof value === "bigint" || value > this.#bytes.length) {
114
+ throw new CborError("CBOR length out of range");
115
+ }
116
+ return value;
117
+ }
118
+ #byte() {
119
+ if (this.offset >= this.#bytes.length) {
120
+ throw new CborError("unexpected end of CBOR input");
121
+ }
122
+ return this.#bytes[this.offset++];
123
+ }
124
+ /**
125
+ * Assert `n` more bytes are available before a multi-byte read. Without this,
126
+ * a truncated argument would let `DataView` throw a native `RangeError` that
127
+ * escapes the `CborError` contract callers rely on.
128
+ */
129
+ #need(n) {
130
+ if (this.offset + n > this.#bytes.length) {
131
+ throw new CborError("unexpected end of CBOR input");
132
+ }
133
+ }
134
+ #bytesOfLength(length) {
135
+ const end = this.offset + length;
136
+ if (end > this.#bytes.length) {
137
+ throw new CborError("unexpected end of CBOR input");
138
+ }
139
+ const slice = this.#bytes.subarray(this.offset, end);
140
+ this.offset = end;
141
+ return slice;
142
+ }
143
+ }
144
+ //# sourceMappingURL=cbor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cbor.js","sourceRoot":"","sources":["../src/cbor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Configuration, the declared Cloudflare `Env` fragment, and config resolution
3
+ * for `@dwk/webauthn`.
4
+ *
5
+ * Per the composition contract the package never reads the global environment
6
+ * directly: the relying party id, expected origins, accepted algorithms, and
7
+ * TTLs are all passed into {@link createWebAuthn}, so the handler can be
8
+ * instantiated multiple times and unit-tested in isolation. The only runtime
9
+ * coupling is the per-relying-party Durable Object namespace, and a missing
10
+ * binding fails loudly at startup.
11
+ */
12
+ import { type Logger, type Metrics } from "@dwk/log";
13
+ import type { WebAuthnObject } from "./rp";
14
+ /** Cloudflare bindings required by the WebAuthn handler and Durable Object. */
15
+ export interface WebAuthnEnv {
16
+ /**
17
+ * Durable Object namespace for the per-relying-party class
18
+ * ({@link WebAuthnObject}). It owns short-TTL challenge state and the
19
+ * credential records — both strongly consistent, never KV (staleness in
20
+ * either is a security bug).
21
+ */
22
+ readonly WEBAUTHN: DurableObjectNamespace<WebAuthnObject>;
23
+ }
24
+ /** Configuration passed to {@link createWebAuthn}. */
25
+ export interface WebAuthnConfig {
26
+ /**
27
+ * The relying party id: the effective domain credentials are scoped to, e.g.
28
+ * `example.com`. MUST be a registrable suffix of every accepted origin's
29
+ * host. The authenticator hashes this into `rpIdHash`.
30
+ */
31
+ readonly rpId: string;
32
+ /** Human-readable relying party name shown in the authenticator UI. */
33
+ readonly rpName: string;
34
+ /**
35
+ * Acceptable client origin(s), e.g. `https://example.com`. The browser puts
36
+ * the ceremony origin in `clientDataJSON`; it must match one of these exactly.
37
+ */
38
+ readonly origin: string | readonly string[];
39
+ /**
40
+ * Accepted COSE signature algorithm identifiers, most-preferred first, offered
41
+ * as `pubKeyCredParams`. Defaults to `[-7, -257]` (ES256, RS256).
42
+ */
43
+ readonly algorithms?: readonly number[];
44
+ /** Challenge lifetime in seconds. Defaults to 300 (5 minutes). */
45
+ readonly challengeTtlSeconds?: number;
46
+ /** Ceremony timeout in milliseconds advertised to the client. Defaults to 60000. */
47
+ readonly timeoutMs?: number;
48
+ /**
49
+ * User-verification requirement for both ceremonies. `"required"` additionally
50
+ * makes the verifier reject an assertion whose UV flag is unset. Defaults to
51
+ * `"preferred"`.
52
+ */
53
+ readonly userVerification?: UserVerificationRequirement;
54
+ /** Injectable clock (epoch ms) for deterministic tests. Defaults to `Date.now`. */
55
+ readonly now?: () => number;
56
+ /** Logger for ceremony outcomes; defaults to a no-op. */
57
+ readonly logger?: Logger;
58
+ /** Metrics sink for ceremony outcomes; defaults to a no-op. */
59
+ readonly metrics?: Metrics;
60
+ }
61
+ /** WebAuthn user-verification requirement values. */
62
+ export type UserVerificationRequirement = "required" | "preferred" | "discouraged";
63
+ /** Fully-resolved configuration with defaults applied. */
64
+ export interface ResolvedConfig {
65
+ readonly rpId: string;
66
+ readonly rpName: string;
67
+ readonly origins: readonly string[];
68
+ readonly algorithms: readonly number[];
69
+ readonly challengeTtlSeconds: number;
70
+ readonly timeoutMs: number;
71
+ readonly userVerification: UserVerificationRequirement;
72
+ readonly now: () => number;
73
+ readonly logger: Logger;
74
+ readonly metrics: Metrics;
75
+ }
76
+ /**
77
+ * The serializable subset of resolved config the front door forwards to the
78
+ * Durable Object (which cannot receive the injected logger/metrics/clock).
79
+ */
80
+ export interface ForwardedConfig {
81
+ readonly rpId: string;
82
+ readonly rpName: string;
83
+ readonly origins: readonly string[];
84
+ readonly algorithms: readonly number[];
85
+ readonly challengeTtlSeconds: number;
86
+ readonly timeoutMs: number;
87
+ readonly userVerification: UserVerificationRequirement;
88
+ }
89
+ /** Internal headers the trusted front door uses to drive the Durable Object. */
90
+ export declare const INTERNAL_HEADERS: {
91
+ /** Which ceremony step to run (see {@link WebAuthnOperation}). */
92
+ readonly op: "x-webauthn-op";
93
+ /** JSON-encoded {@link ForwardedConfig}. */
94
+ readonly config: "x-webauthn-config";
95
+ /** Current time (epoch ms) from the injected clock, for TTL decisions. */
96
+ readonly now: "x-webauthn-now";
97
+ /** DO→front-door: the ceremony outcome event name, logged then stripped. */
98
+ readonly event: "x-webauthn-event";
99
+ /** DO→front-door: a stable failure reason when the ceremony was rejected. */
100
+ readonly reason: "x-webauthn-reason";
101
+ };
102
+ /** The four ceremony steps the handler routes. */
103
+ export type WebAuthnOperation = "register/options" | "register/verify" | "authenticate/options" | "authenticate/verify";
104
+ /** Apply defaults and derive values from raw {@link WebAuthnConfig}. */
105
+ export declare function resolveConfig(config: WebAuthnConfig): ResolvedConfig;
106
+ /** Project the resolved config to the serializable subset forwarded to the DO. */
107
+ export declare function forwardedConfig(config: ResolvedConfig): ForwardedConfig;
108
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAA2B,KAAK,MAAM,EAAE,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AAG9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAE3C,+EAA+E;AAC/E,MAAM,WAAW,WAAW;IAC1B;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC,cAAc,CAAC,CAAC;CAC3D;AAED,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IAE5C;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAExC,kEAAkE;IAClE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAEtC,oFAAoF;IACpF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAE5B;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,2BAA2B,CAAC;IAExD,mFAAmF;IACnF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAE5B,yDAAyD;IACzD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEzB,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,qDAAqD;AACrD,MAAM,MAAM,2BAA2B,GACnC,UAAU,GACV,WAAW,GACX,aAAa,CAAC;AAElB,0DAA0D;AAC1D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,gBAAgB,EAAE,2BAA2B,CAAC;IACvD,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,gBAAgB,EAAE,2BAA2B,CAAC;CACxD;AAED,gFAAgF;AAChF,eAAO,MAAM,gBAAgB;IAC3B,kEAAkE;;IAElE,4CAA4C;;IAE5C,0EAA0E;;IAE1E,4EAA4E;;IAE5E,6EAA6E;;CAErE,CAAC;AAEX,kDAAkD;AAClD,MAAM,MAAM,iBAAiB,GACzB,kBAAkB,GAClB,iBAAiB,GACjB,sBAAsB,GACtB,qBAAqB,CAAC;AAK1B,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CA+BpE;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,eAAe,CAUvE"}
package/dist/config.js ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Configuration, the declared Cloudflare `Env` fragment, and config resolution
3
+ * for `@dwk/webauthn`.
4
+ *
5
+ * Per the composition contract the package never reads the global environment
6
+ * directly: the relying party id, expected origins, accepted algorithms, and
7
+ * TTLs are all passed into {@link createWebAuthn}, so the handler can be
8
+ * instantiated multiple times and unit-tested in isolation. The only runtime
9
+ * coupling is the per-relying-party Durable Object namespace, and a missing
10
+ * binding fails loudly at startup.
11
+ */
12
+ import { noopLogger, noopMetrics } from "@dwk/log";
13
+ import { DEFAULT_COSE_ALGORITHMS } from "./cose";
14
+ /** Internal headers the trusted front door uses to drive the Durable Object. */
15
+ export const INTERNAL_HEADERS = {
16
+ /** Which ceremony step to run (see {@link WebAuthnOperation}). */
17
+ op: "x-webauthn-op",
18
+ /** JSON-encoded {@link ForwardedConfig}. */
19
+ config: "x-webauthn-config",
20
+ /** Current time (epoch ms) from the injected clock, for TTL decisions. */
21
+ now: "x-webauthn-now",
22
+ /** DO→front-door: the ceremony outcome event name, logged then stripped. */
23
+ event: "x-webauthn-event",
24
+ /** DO→front-door: a stable failure reason when the ceremony was rejected. */
25
+ reason: "x-webauthn-reason",
26
+ };
27
+ const DEFAULT_CHALLENGE_TTL_SECONDS = 300;
28
+ const DEFAULT_TIMEOUT_MS = 60_000;
29
+ /** Apply defaults and derive values from raw {@link WebAuthnConfig}. */
30
+ export function resolveConfig(config) {
31
+ if (!config.rpId)
32
+ throw new Error("@dwk/webauthn: `rpId` is required");
33
+ if (!config.rpName)
34
+ throw new Error("@dwk/webauthn: `rpName` is required");
35
+ const origins = typeof config.origin === "string" ? [config.origin] : [...config.origin];
36
+ if (origins.length === 0) {
37
+ throw new Error("@dwk/webauthn: at least one `origin` is required");
38
+ }
39
+ const algorithms = config.algorithms === undefined
40
+ ? [...DEFAULT_COSE_ALGORITHMS]
41
+ : [...config.algorithms];
42
+ if (algorithms.length === 0) {
43
+ throw new Error("@dwk/webauthn: at least one algorithm is required");
44
+ }
45
+ return {
46
+ rpId: config.rpId,
47
+ rpName: config.rpName,
48
+ origins,
49
+ algorithms,
50
+ challengeTtlSeconds: config.challengeTtlSeconds ?? DEFAULT_CHALLENGE_TTL_SECONDS,
51
+ timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,
52
+ userVerification: config.userVerification ?? "preferred",
53
+ now: config.now ?? (() => Date.now()),
54
+ logger: config.logger ?? noopLogger,
55
+ metrics: config.metrics ?? noopMetrics,
56
+ };
57
+ }
58
+ /** Project the resolved config to the serializable subset forwarded to the DO. */
59
+ export function forwardedConfig(config) {
60
+ return {
61
+ rpId: config.rpId,
62
+ rpName: config.rpName,
63
+ origins: config.origins,
64
+ algorithms: config.algorithms,
65
+ challengeTtlSeconds: config.challengeTtlSeconds,
66
+ timeoutMs: config.timeoutMs,
67
+ userVerification: config.userVerification,
68
+ };
69
+ }
70
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAA6B,MAAM,UAAU,CAAC;AAE9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,QAAQ,CAAC;AA+FjD,gFAAgF;AAChF,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,kEAAkE;IAClE,EAAE,EAAE,eAAe;IACnB,4CAA4C;IAC5C,MAAM,EAAE,mBAAmB;IAC3B,0EAA0E;IAC1E,GAAG,EAAE,gBAAgB;IACrB,4EAA4E;IAC5E,KAAK,EAAE,kBAAkB;IACzB,6EAA6E;IAC7E,MAAM,EAAE,mBAAmB;CACnB,CAAC;AASX,MAAM,6BAA6B,GAAG,GAAG,CAAC;AAC1C,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC,wEAAwE;AACxE,MAAM,UAAU,aAAa,CAAC,MAAsB;IAClD,IAAI,CAAC,MAAM,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvE,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAE3E,MAAM,OAAO,GACX,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC3E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,UAAU,GACd,MAAM,CAAC,UAAU,KAAK,SAAS;QAC7B,CAAC,CAAC,CAAC,GAAG,uBAAuB,CAAC;QAC9B,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAC7B,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IAED,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO;QACP,UAAU;QACV,mBAAmB,EACjB,MAAM,CAAC,mBAAmB,IAAI,6BAA6B;QAC7D,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,kBAAkB;QACjD,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,IAAI,WAAW;QACxD,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACrC,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,UAAU;QACnC,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,WAAW;KACvC,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,eAAe,CAAC,MAAsB;IACpD,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,mBAAmB,EAAE,MAAM,CAAC,mBAAmB;QAC/C,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;KAC1C,CAAC;AACJ,CAAC"}
package/dist/cose.d.ts ADDED
@@ -0,0 +1,73 @@
1
+ /**
2
+ * COSE_Key (RFC 9052) → JWK conversion and the Web Crypto parameters for the
3
+ * COSE signature algorithms a WebAuthn relying party accepts.
4
+ *
5
+ * Authenticators hand the relying party a credential public key as a COSE_Key
6
+ * (an integer-keyed CBOR map) and sign assertions with a COSE algorithm
7
+ * identifier. This module narrows that to the algorithms we support — the same
8
+ * asymmetric set as `@dwk/dpop` (ES256/ES384, RS256/PS256) — and produces a JWK
9
+ * plus the `importKey`/`verify` parameter objects, so verification stays on Web
10
+ * Crypto with no external dependency.
11
+ *
12
+ * Web Crypto's ECDSA `verify` expects a raw `r‖s` signature, but WebAuthn EC
13
+ * assertions are ASN.1 DER `SEQUENCE { r, s }`; {@link derToRawEcdsaSignature}
14
+ * bridges that gap.
15
+ */
16
+ /** COSE algorithm identifiers (the asymmetric subset we accept). */
17
+ export declare const COSE_ALG_ES256 = -7;
18
+ export declare const COSE_ALG_ES384 = -35;
19
+ export declare const COSE_ALG_ES512 = -36;
20
+ export declare const COSE_ALG_RS256 = -257;
21
+ export declare const COSE_ALG_PS256 = -37;
22
+ /** Default `pubKeyCredParams`, most-preferred first: ES256 then RS256. */
23
+ export declare const DEFAULT_COSE_ALGORITHMS: readonly number[];
24
+ /** A credential public key extracted from a COSE_Key. */
25
+ export interface CoseKey {
26
+ /** The public key as a JWK ready for `crypto.subtle.importKey`. */
27
+ readonly jwk: JsonWebKey;
28
+ /** The COSE signature algorithm identifier the key declared. */
29
+ readonly alg: number;
30
+ }
31
+ /** Thrown when a COSE_Key is malformed or uses an unsupported algorithm. */
32
+ export declare class CoseError extends Error {
33
+ }
34
+ /** Convert a decoded COSE_Key map to a JWK plus its declared algorithm. */
35
+ export declare function coseToKey(map: Map<unknown, unknown>): CoseKey;
36
+ interface ImportAlg {
37
+ name: string;
38
+ namedCurve?: string;
39
+ hash?: string;
40
+ }
41
+ interface VerifyAlg {
42
+ name: string;
43
+ hash?: string;
44
+ saltLength?: number;
45
+ }
46
+ /** Web Crypto parameters for one COSE algorithm. */
47
+ export interface CryptoParams {
48
+ readonly importParams: ImportAlg;
49
+ readonly verifyParams: VerifyAlg;
50
+ /** EC algorithms carry a DER-encoded signature that needs unwrapping. */
51
+ readonly ec: boolean;
52
+ /** Raw `r‖s` length (one coordinate × 2) for EC; unused for RSA. */
53
+ readonly ecSignatureBytes: number;
54
+ }
55
+ /**
56
+ * Resolve the `importKey`/`verify` parameters for a COSE algorithm, or `null`
57
+ * when it is outside the accepted set. The set mirrors `@dwk/dpop`: ES256/ES384
58
+ * (ECDSA), RS256 (RSASSA-PKCS1-v1_5), PS256 (RSA-PSS).
59
+ */
60
+ export declare function cryptoParamsForCoseAlg(alg: number): CryptoParams | null;
61
+ /**
62
+ * Convert an ASN.1 DER `SEQUENCE { INTEGER r, INTEGER s }` ECDSA signature to
63
+ * the fixed-length raw `r‖s` form Web Crypto's ECDSA `verify` expects. DER
64
+ * integers are big-endian, minimally encoded, and may carry a leading `0x00`
65
+ * sign byte; each is left-padded (or its sign byte trimmed) to `size/2` bytes.
66
+ *
67
+ * @param der - the DER-encoded signature
68
+ * @param size - the raw signature length (64 for P-256, 96 for P-384)
69
+ * @throws CoseError if the DER structure is malformed
70
+ */
71
+ export declare function derToRawEcdsaSignature(der: Uint8Array, size: number): Uint8Array;
72
+ export {};
73
+ //# sourceMappingURL=cose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cose.d.ts","sourceRoot":"","sources":["../src/cose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAsBH,oEAAoE;AACpE,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,cAAc,OAAO,CAAC;AACnC,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC,0EAA0E;AAC1E,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAGpD,CAAC;AAEF,yDAAyD;AACzD,MAAM,WAAW,OAAO;IACtB,mEAAmE;IACnE,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IACzB,gEAAgE;IAChE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,4EAA4E;AAC5E,qBAAa,SAAU,SAAQ,KAAK;CAAG;AA4BvC,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,OAAO,CAwC7D;AAED,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AACD,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,oDAAoD;AACpD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAC;IACjC,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAC;IACjC,yEAAyE;IACzE,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,oEAAoE;IACpE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACnC;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAiCvE;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,MAAM,GACX,UAAU,CAkCZ"}