dbsc-toolkit 2.10.0 → 2.12.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 (126) hide show
  1. package/README.md +43 -7
  2. package/dist/core/dpop/bind.d.ts +13 -0
  3. package/dist/core/dpop/bind.d.ts.map +1 -0
  4. package/dist/core/dpop/bind.js +12 -0
  5. package/dist/core/dpop/bind.js.map +1 -0
  6. package/dist/core/dpop/guard.d.ts +55 -0
  7. package/dist/core/dpop/guard.d.ts.map +1 -0
  8. package/dist/core/dpop/guard.js +40 -0
  9. package/dist/core/dpop/guard.js.map +1 -0
  10. package/dist/core/dpop/htu.d.ts +4 -0
  11. package/dist/core/dpop/htu.d.ts.map +1 -0
  12. package/dist/core/dpop/htu.js +42 -0
  13. package/dist/core/dpop/htu.js.map +1 -0
  14. package/dist/core/dpop/index.d.ts +9 -0
  15. package/dist/core/dpop/index.d.ts.map +1 -0
  16. package/dist/core/dpop/index.js +6 -0
  17. package/dist/core/dpop/index.js.map +1 -0
  18. package/dist/core/dpop/thumbprint.d.ts +13 -0
  19. package/dist/core/dpop/thumbprint.d.ts.map +1 -0
  20. package/dist/core/dpop/thumbprint.js +30 -0
  21. package/dist/core/dpop/thumbprint.js.map +1 -0
  22. package/dist/core/dpop/verify.d.ts +44 -0
  23. package/dist/core/dpop/verify.d.ts.map +1 -0
  24. package/dist/core/dpop/verify.js +124 -0
  25. package/dist/core/dpop/verify.js.map +1 -0
  26. package/dist/core/errors.d.ts +13 -0
  27. package/dist/core/errors.d.ts.map +1 -1
  28. package/dist/core/errors.js +16 -0
  29. package/dist/core/errors.js.map +1 -1
  30. package/dist/dpop/index.d.ts +12 -0
  31. package/dist/dpop/index.d.ts.map +1 -0
  32. package/dist/dpop/index.js +11 -0
  33. package/dist/dpop/index.js.map +1 -0
  34. package/dist/express/create-dbsc.d.ts +4 -1
  35. package/dist/express/create-dbsc.d.ts.map +1 -1
  36. package/dist/express/create-dbsc.js +2 -0
  37. package/dist/express/create-dbsc.js.map +1 -1
  38. package/dist/express/index.d.ts +1 -0
  39. package/dist/express/index.d.ts.map +1 -1
  40. package/dist/express/index.js +1 -0
  41. package/dist/express/index.js.map +1 -1
  42. package/dist/express/require-dpop.d.ts +17 -0
  43. package/dist/express/require-dpop.d.ts.map +1 -0
  44. package/dist/express/require-dpop.js +51 -0
  45. package/dist/express/require-dpop.js.map +1 -0
  46. package/dist/fastify/create-dbsc.d.ts +4 -0
  47. package/dist/fastify/create-dbsc.d.ts.map +1 -1
  48. package/dist/fastify/create-dbsc.js +2 -0
  49. package/dist/fastify/create-dbsc.js.map +1 -1
  50. package/dist/fastify/index.d.ts +1 -0
  51. package/dist/fastify/index.d.ts.map +1 -1
  52. package/dist/fastify/index.js +1 -0
  53. package/dist/fastify/index.js.map +1 -1
  54. package/dist/fastify/require-dpop.d.ts +13 -0
  55. package/dist/fastify/require-dpop.d.ts.map +1 -0
  56. package/dist/fastify/require-dpop.js +42 -0
  57. package/dist/fastify/require-dpop.js.map +1 -0
  58. package/dist/hono/create-dbsc.d.ts +3 -0
  59. package/dist/hono/create-dbsc.d.ts.map +1 -1
  60. package/dist/hono/create-dbsc.js +2 -0
  61. package/dist/hono/create-dbsc.js.map +1 -1
  62. package/dist/hono/index.d.ts +1 -0
  63. package/dist/hono/index.d.ts.map +1 -1
  64. package/dist/hono/index.js +1 -0
  65. package/dist/hono/index.js.map +1 -1
  66. package/dist/hono/require-dpop.d.ts +14 -0
  67. package/dist/hono/require-dpop.d.ts.map +1 -0
  68. package/dist/hono/require-dpop.js +38 -0
  69. package/dist/hono/require-dpop.js.map +1 -0
  70. package/dist/koa/create-dbsc.d.ts +28 -0
  71. package/dist/koa/create-dbsc.d.ts.map +1 -0
  72. package/dist/koa/create-dbsc.js +34 -0
  73. package/dist/koa/create-dbsc.js.map +1 -0
  74. package/dist/koa/index.d.ts +20 -0
  75. package/dist/koa/index.d.ts.map +1 -0
  76. package/dist/koa/index.js +27 -0
  77. package/dist/koa/index.js.map +1 -0
  78. package/dist/koa/require-dpop.d.ts +14 -0
  79. package/dist/koa/require-dpop.d.ts.map +1 -0
  80. package/dist/koa/require-dpop.js +38 -0
  81. package/dist/koa/require-dpop.js.map +1 -0
  82. package/dist/koa/require-proof.d.ts +9 -0
  83. package/dist/koa/require-proof.d.ts.map +1 -0
  84. package/dist/koa/require-proof.js +69 -0
  85. package/dist/koa/require-proof.js.map +1 -0
  86. package/dist/nestjs/index.d.ts +57 -0
  87. package/dist/nestjs/index.d.ts.map +1 -0
  88. package/dist/nestjs/index.js +193 -0
  89. package/dist/nestjs/index.js.map +1 -0
  90. package/dist/nextjs/index.d.ts +2 -0
  91. package/dist/nextjs/index.d.ts.map +1 -1
  92. package/dist/nextjs/index.js +1 -0
  93. package/dist/nextjs/index.js.map +1 -1
  94. package/dist/nextjs/require-dpop.d.ts +21 -0
  95. package/dist/nextjs/require-dpop.d.ts.map +1 -0
  96. package/dist/nextjs/require-dpop.js +35 -0
  97. package/dist/nextjs/require-dpop.js.map +1 -0
  98. package/dist/node/create-dbsc.d.ts +33 -0
  99. package/dist/node/create-dbsc.d.ts.map +1 -0
  100. package/dist/node/create-dbsc.js +35 -0
  101. package/dist/node/create-dbsc.js.map +1 -0
  102. package/dist/node/index.d.ts +55 -0
  103. package/dist/node/index.d.ts.map +1 -0
  104. package/dist/node/index.js +413 -0
  105. package/dist/node/index.js.map +1 -0
  106. package/dist/node/require-dpop.d.ts +17 -0
  107. package/dist/node/require-dpop.d.ts.map +1 -0
  108. package/dist/node/require-dpop.js +49 -0
  109. package/dist/node/require-dpop.js.map +1 -0
  110. package/dist/node/require-proof.d.ts +17 -0
  111. package/dist/node/require-proof.d.ts.map +1 -0
  112. package/dist/node/require-proof.js +74 -0
  113. package/dist/node/require-proof.js.map +1 -0
  114. package/dist/sveltekit/index.d.ts +49 -0
  115. package/dist/sveltekit/index.d.ts.map +1 -0
  116. package/dist/sveltekit/index.js +319 -0
  117. package/dist/sveltekit/index.js.map +1 -0
  118. package/dist/sveltekit/require-dpop.d.ts +17 -0
  119. package/dist/sveltekit/require-dpop.d.ts.map +1 -0
  120. package/dist/sveltekit/require-dpop.js +48 -0
  121. package/dist/sveltekit/require-dpop.js.map +1 -0
  122. package/dist/sveltekit/require-proof.d.ts +15 -0
  123. package/dist/sveltekit/require-proof.d.ts.map +1 -0
  124. package/dist/sveltekit/require-proof.js +52 -0
  125. package/dist/sveltekit/require-proof.js.map +1 -0
  126. package/package.json +47 -2
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  <p align="center">
8
8
  <strong>Stop stolen session cookies from being replayed on another device.</strong><br>
9
- A language-neutral DBSC protocol spec plus a reference implementation for Node.js — with a Web Crypto polyfill so every browser is covered, not just Chrome.
9
+ Device Bound Session Credentials for Node.js — one framework-agnostic core with adapters for Express, Fastify, Hono, Next.js, NestJS, Koa, SvelteKit and raw <code>node:http</code>, plus a Web Crypto polyfill so every browser is covered, not just Chrome. A language-neutral protocol spec with a Node reference implementation.
10
10
  </p>
11
11
 
12
12
  <p align="center">
@@ -122,9 +122,23 @@ Load the polyfill in your HTML so non-Chromium browsers reach `tier: "bound"`:
122
122
 
123
123
  Full walk-through, failure modes, and migration timeline: **[docs/getting-started.md](./docs/getting-started.md)** and **[docs/integrating-existing-auth.md](./docs/integrating-existing-auth.md)**.
124
124
 
125
- ### Not on Express?
125
+ ### Any framework
126
126
 
127
- The protocol lives in a framework-agnostic core — plain functions plus a `StorageAdapter`, no HTTP-layer assumptions. The Express/Fastify/Hono/Next.js adapters are thin wrappers. Build on the core directly for any runtime:
127
+ The protocol lives in a framework-agnostic core — plain functions plus a `StorageAdapter`, no HTTP-layer assumptions. The adapters are thin wrappers; pick yours:
128
+
129
+ | Framework | Import |
130
+ |---|---|
131
+ | Express | `dbsc-toolkit/express` |
132
+ | Fastify | `dbsc-toolkit/fastify` |
133
+ | Hono (Node, Bun, Deno, Workers) | `dbsc-toolkit/hono` |
134
+ | Next.js (App Router) | `dbsc-toolkit/nextjs` |
135
+ | NestJS | `dbsc-toolkit/nestjs` |
136
+ | Koa | `dbsc-toolkit/koa` |
137
+ | SvelteKit | `dbsc-toolkit/sveltekit` |
138
+ | Any other server (raw `node:http`) | `dbsc-toolkit/node` |
139
+ | [Better Auth](https://better-auth.com) | `@dbsc-toolkit/better-auth` |
140
+
141
+ **No adapter for your framework? You can still use it.** Every adapter is a thin shell over the same core, so any HTTP framework on Node works — wire the core in directly:
128
142
 
129
143
  ```ts
130
144
  import {
@@ -136,7 +150,7 @@ import {
136
150
  } from "dbsc-toolkit";
137
151
  ```
138
152
 
139
- Complete raw-`http` example: [docs/adapters.md](./docs/adapters.md#writing-your-own-adapter).
153
+ The generic `dbsc-toolkit/node` adapter is exactly this over raw `node:http`. Complete example: [docs/adapters.md](./docs/adapters.md#writing-your-own-adapter).
140
154
 
141
155
  ## How it compares
142
156
 
@@ -147,6 +161,7 @@ Complete raw-`http` example: [docs/adapters.md](./docs/adapters.md#writing-your-
147
161
  | Works on Firefox / Safari / mobile / no-TPM | ✅ | ✅ | ❌ | ✅ (polyfill) |
148
162
  | Per-request body-hash proof vs MITM | ❌ | ❌ | ❌ | ✅ |
149
163
  | Captured-proof replay defense | n/a | ❌ | n/a | ✅ (replay cache) |
164
+ | Bearer/access-token replay (DPoP, RFC 9449) | n/a | ❌ | n/a | ✅ (`dbsc-toolkit/dpop`) |
150
165
  | Multi-subdomain binding | loose | loose | ❌ | ✅ (`cookieScope: "site"`) |
151
166
  | Better Auth integration | n/a | n/a | n/a | ✅ (plugin) |
152
167
 
@@ -182,11 +197,30 @@ Every session carries a `tier`. You don't gate on it directly — `requireProof(
182
197
 
183
198
  The polyfill is on by default. To run native DBSC only (Chromium 145+, no `bound` tier), pass `bound: false` — the `/dbsc-bound/*` routes don't mount and `requireProof()` relaxes to the native binding.
184
199
 
200
+ ## Optional: DPoP for bearer tokens (RFC 9449)
201
+
202
+ DBSC binds a session **cookie**. If you hand out **bearer / access tokens** for an API, those have the same replay problem a cookie does — copy the `Authorization` header, use it anywhere. DPoP closes that the same way: bind the token to a device key and require a per-request `DPoP` proof. It ships as a separate import, off the default path, so projects that don't use it pay nothing.
203
+
204
+ ```ts
205
+ import { dpopConfirmation } from "dbsc-toolkit/dpop";
206
+ import { requireDpop } from "dbsc-toolkit/express";
207
+
208
+ // at issue time — bind the token to the device key:
209
+ const { jkt } = await dpopConfirmation(deviceJwk);
210
+ const token = signAccessToken({ sub, cnf: { jkt } }); // your JWT lib
211
+
212
+ // on the resource route — verify the proof and the binding:
213
+ app.get("/api/resource", requireDpop({ getBoundJkt }), handler);
214
+ ```
215
+
216
+ `requireDpop` is exported from every adapter (Express, Fastify, Hono, Next.js, NestJS, Koa, SvelteKit, `node:http`). A failed check answers `401` with `WWW-Authenticate: DPoP`. Always pass `getBoundJkt` so the presented token is bound to its key — see [docs/dpop.md](./docs/dpop.md) and [spec/10-dpop.md](./spec/10-dpop.md).
217
+
185
218
  ## Ecosystem
186
219
 
187
220
  | Package | What it is |
188
221
  |---|---|
189
- | `dbsc-toolkit` | Core + Express/Fastify/Hono/Next.js adapters, memory/Redis/Postgres storage |
222
+ | `dbsc-toolkit` | Core + adapters for Express, Fastify, Hono, Next.js, NestJS, Koa, SvelteKit & raw `node:http`; memory/Redis/Postgres storage |
223
+ | `dbsc-toolkit/dpop` | Optional DPoP (RFC 9449) — bind bearer/access tokens to a device key |
190
224
  | `dbsc-toolkit/client` | Browser SDK + Web Crypto polyfill |
191
225
  | [`@dbsc-toolkit/better-auth`](./packages/better-auth/) | First-class [Better Auth](https://better-auth.com) plugin — binds every sign-in method automatically |
192
226
 
@@ -211,7 +245,8 @@ The wire protocol is documented as a language-neutral spec in [`spec/`](./spec/)
211
245
  - [x] Per-request proof + body signing + replay cache
212
246
  - [x] Multi-subdomain binding (`cookieScope: "site"`)
213
247
  - [x] Better Auth plugin
214
- - [ ] Koa / NestJS adapters
248
+ - [x] NestJS, Koa, SvelteKit & generic `node:http` adapters
249
+ - [x] DPoP (RFC 9449) for bearer-token binding
215
250
  - [ ] Bun / Deno native paths
216
251
  - [ ] Third-party security audit
217
252
 
@@ -220,7 +255,8 @@ The wire protocol is documented as a language-neutral spec in [`spec/`](./spec/)
220
255
  | Import | What it is |
221
256
  |---|---|
222
257
  | `dbsc-toolkit` | Core: types, crypto, protocol handlers, framework-agnostic |
223
- | `dbsc-toolkit/express` · `/fastify` · `/hono` · `/nextjs` | Framework adapters |
258
+ | `dbsc-toolkit/express` · `/fastify` · `/hono` · `/nextjs` · `/nestjs` · `/koa` · `/sveltekit` · `/node` | Framework adapters |
259
+ | `dbsc-toolkit/dpop` | Optional DPoP (RFC 9449) verifier + `requireDpop` per adapter |
224
260
  | `dbsc-toolkit/client` | Browser SDK + polyfill |
225
261
  | `dbsc-toolkit/storage/{memory,redis,postgres}` | Storage adapters |
226
262
 
@@ -0,0 +1,13 @@
1
+ export interface DpopConfirmation {
2
+ /** RFC 7638 thumbprint of the bound key, for the token's cnf.jkt. */
3
+ jkt: string;
4
+ }
5
+ /**
6
+ * Build the `cnf` confirmation to embed in an access token at issue time so
7
+ * the token is bound to a DPoP key (RFC 9449 §6). Embed the return value as
8
+ * `{ cnf: { jkt } }` in the token claims, then guard the resource route with
9
+ * `requireDpop({ getBoundJkt })` returning the same jkt. Framework-neutral:
10
+ * the caller signs the token however it already does.
11
+ */
12
+ export declare function dpopConfirmation(jwk: JsonWebKey): Promise<DpopConfirmation>;
13
+ //# sourceMappingURL=bind.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bind.d.ts","sourceRoot":"","sources":["../../../src/core/dpop/bind.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEjF"}
@@ -0,0 +1,12 @@
1
+ import { jwkThumbprint } from "./thumbprint.js";
2
+ /**
3
+ * Build the `cnf` confirmation to embed in an access token at issue time so
4
+ * the token is bound to a DPoP key (RFC 9449 §6). Embed the return value as
5
+ * `{ cnf: { jkt } }` in the token claims, then guard the resource route with
6
+ * `requireDpop({ getBoundJkt })` returning the same jkt. Framework-neutral:
7
+ * the caller signs the token however it already does.
8
+ */
9
+ export async function dpopConfirmation(jwk) {
10
+ return { jkt: await jwkThumbprint(jwk) };
11
+ }
12
+ //# sourceMappingURL=bind.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bind.js","sourceRoot":"","sources":["../../../src/core/dpop/bind.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAOhD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAe;IACpD,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,55 @@
1
+ import type { ProofReplayCache } from "../types.js";
2
+ /**
3
+ * Adapter-neutral options for a `requireDpop()` guard. `getBoundJkt` is generic
4
+ * over the framework request type so each adapter passes its own.
5
+ */
6
+ export interface RequireDpopOptions<Req = unknown> {
7
+ /**
8
+ * Resolve the `cnf.jkt` the presented bearer token was issued against, from
9
+ * the request (e.g. decode the token, read `cnf.jkt`). Required for token
10
+ * binding — without it a presented token is rejected as
11
+ * DPOP_TOKEN_BINDING_REQUIRED unless `requireTokenBinding` is false.
12
+ */
13
+ getBoundJkt?: (req: Req) => string | undefined | Promise<string | undefined>;
14
+ /**
15
+ * Default true. Set false to verify a presented token's proof without binding
16
+ * it to a jkt — strictly weaker proof-of-possession only. A conscious choice.
17
+ */
18
+ requireTokenBinding?: boolean;
19
+ /** Acceptable iat window in ms. Default 300000. */
20
+ iatWindowMs?: number;
21
+ /** jti replay store. Falls back to the DBSC middleware's replayCache. */
22
+ replayCache?: ProofReplayCache;
23
+ }
24
+ export interface DpopGuardInput {
25
+ proof: string | undefined;
26
+ authorization: string | undefined;
27
+ method: string;
28
+ url: string;
29
+ boundJkt: string | undefined;
30
+ replayCache: ProofReplayCache | undefined;
31
+ opts: {
32
+ requireTokenBinding?: boolean;
33
+ iatWindowMs?: number;
34
+ };
35
+ }
36
+ export interface DpopGuardOutcome {
37
+ ok: boolean;
38
+ /** Set when ok=false: the HTTP error to emit. */
39
+ error?: {
40
+ code: string;
41
+ message: string;
42
+ };
43
+ /** Set when ok=true. */
44
+ jkt?: string;
45
+ }
46
+ /** Parse a `DPoP <token>` Authorization header. Returns the token or undefined. */
47
+ export declare function parseDpopAuthorization(authorization: string | undefined): string | undefined;
48
+ /**
49
+ * Adapter-neutral core of every `requireDpop()`. Each adapter extracts the
50
+ * fields, calls this, then writes its own 401 + WWW-Authenticate on failure.
51
+ */
52
+ export declare function runDpopGuard(input: DpopGuardInput): Promise<DpopGuardOutcome>;
53
+ /** The WWW-Authenticate header value for a failed DPoP check (RFC 9449 §7.1). */
54
+ export declare const DPOP_WWW_AUTHENTICATE = "DPoP error=\"invalid_dpop_proof\"";
55
+ //# sourceMappingURL=guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../../src/core/dpop/guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD;;;GAGG;AACH,MAAM,WAAW,kBAAkB,CAAC,GAAG,GAAG,OAAO;IAC/C;;;;;OAKG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7E;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,WAAW,CAAC,EAAE,gBAAgB,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,WAAW,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC1C,IAAI,EAAE;QAAE,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/D;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,iDAAiD;IACjD,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,mFAAmF;AACnF,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAI5F;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAsBnF;AAED,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,sCAAoC,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { DbscVerificationError } from "../errors.js";
2
+ import { verifyDpopProof } from "./verify.js";
3
+ /** Parse a `DPoP <token>` Authorization header. Returns the token or undefined. */
4
+ export function parseDpopAuthorization(authorization) {
5
+ if (!authorization)
6
+ return undefined;
7
+ const m = /^DPoP\s+(.+)$/i.exec(authorization.trim());
8
+ return m ? m[1] : undefined;
9
+ }
10
+ /**
11
+ * Adapter-neutral core of every `requireDpop()`. Each adapter extracts the
12
+ * fields, calls this, then writes its own 401 + WWW-Authenticate on failure.
13
+ */
14
+ export async function runDpopGuard(input) {
15
+ const accessToken = parseDpopAuthorization(input.authorization);
16
+ try {
17
+ const { jkt } = await verifyDpopProof({
18
+ proof: input.proof,
19
+ method: input.method,
20
+ url: input.url,
21
+ ...(accessToken !== undefined && { accessToken }),
22
+ ...(input.boundJkt !== undefined && { boundJkt: input.boundJkt }),
23
+ ...(input.opts.requireTokenBinding !== undefined && {
24
+ requireTokenBinding: input.opts.requireTokenBinding,
25
+ }),
26
+ ...(input.opts.iatWindowMs !== undefined && { iatWindowMs: input.opts.iatWindowMs }),
27
+ ...(input.replayCache !== undefined && { replayCache: input.replayCache }),
28
+ });
29
+ return { ok: true, jkt };
30
+ }
31
+ catch (e) {
32
+ if (e instanceof DbscVerificationError) {
33
+ return { ok: false, error: { code: e.code, message: e.message } };
34
+ }
35
+ throw e;
36
+ }
37
+ }
38
+ /** The WWW-Authenticate header value for a failed DPoP check (RFC 9449 §7.1). */
39
+ export const DPOP_WWW_AUTHENTICATE = 'DPoP error="invalid_dpop_proof"';
40
+ //# sourceMappingURL=guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.js","sourceRoot":"","sources":["../../../src/core/dpop/guard.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AA2C9C,mFAAmF;AACnF,MAAM,UAAU,sBAAsB,CAAC,aAAiC;IACtE,IAAI,CAAC,aAAa;QAAE,OAAO,SAAS,CAAC;IACrC,MAAM,CAAC,GAAG,gBAAgB,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC;IACtD,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAqB;IACtD,MAAM,WAAW,GAAG,sBAAsB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAChE,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,eAAe,CAAC;YACpC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,GAAG,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,CAAC;YACjD,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;YACjE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,KAAK,SAAS,IAAI;gBAClD,mBAAmB,EAAE,KAAK,CAAC,IAAI,CAAC,mBAAmB;aACpD,CAAC;YACF,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACpF,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;SAC3E,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,qBAAqB,EAAE,CAAC;YACvC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QACpE,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,MAAM,qBAAqB,GAAG,iCAAiC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function normalizeHtu(uri: string): string;
2
+ /** True when the claimed htu and the actual request URL normalize equal. */
3
+ export declare function htuMatches(claimed: string, requestUrl: string): boolean;
4
+ //# sourceMappingURL=htu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"htu.d.ts","sourceRoot":"","sources":["../../../src/core/dpop/htu.ts"],"names":[],"mappings":"AAsBA,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAoBhD;AAED,4EAA4E;AAC5E,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAEvE"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * RFC 9449 htu normalization. This is the dangerous check: a weak normalizer
3
+ * lets a proof minted for one URL be accepted on another. §4.3 requires the
4
+ * htu claim to match the request URI "ignoring any query and fragment parts"
5
+ * and SHOULD apply RFC 3986 §6.2.2 (syntax-based) + §6.2.3 (scheme-based)
6
+ * normalization before comparing.
7
+ *
8
+ * Rules applied here, on both the claimed htu and the live request URL, then
9
+ * compared as strings:
10
+ * - lowercase scheme and host (WHATWG URL does this for us)
11
+ * - drop ONLY the scheme-default port (443 for https, 80 for http); keep
12
+ * every non-default port exactly (:8443 stays :8443)
13
+ * - strip query and fragment
14
+ * - empty path becomes "/"
15
+ * - trailing slash is SIGNIFICANT: "/token/" does not equal "/token"
16
+ *
17
+ * Percent-encoding and path "."/".." resolution are handled by `new URL()`.
18
+ */
19
+ import { DbscVerificationError, ErrorCodes } from "../errors.js";
20
+ const DEFAULT_PORT = { "https:": "443", "http:": "80" };
21
+ export function normalizeHtu(uri) {
22
+ let u;
23
+ try {
24
+ u = new URL(uri);
25
+ }
26
+ catch {
27
+ throw new DbscVerificationError(ErrorCodes.DPOP_HTU_MISMATCH, `htu is not an absolute URI: ${uri}`);
28
+ }
29
+ const scheme = u.protocol.toLowerCase();
30
+ const host = u.hostname.toLowerCase();
31
+ // u.port is "" when the URL used the scheme-default port implicitly, and the
32
+ // numeric string otherwise. Drop it only when it equals the scheme default.
33
+ const port = u.port && u.port !== DEFAULT_PORT[scheme] ? `:${u.port}` : "";
34
+ const path = u.pathname === "" ? "/" : u.pathname;
35
+ // scheme://host[:port]path — query and fragment intentionally dropped.
36
+ return `${scheme}//${host}${port}${path}`;
37
+ }
38
+ /** True when the claimed htu and the actual request URL normalize equal. */
39
+ export function htuMatches(claimed, requestUrl) {
40
+ return normalizeHtu(claimed) === normalizeHtu(requestUrl);
41
+ }
42
+ //# sourceMappingURL=htu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"htu.js","sourceRoot":"","sources":["../../../src/core/dpop/htu.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAEjE,MAAM,YAAY,GAA2B,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAEhF,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,IAAI,CAAM,CAAC;IACX,IAAI,CAAC;QACH,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,qBAAqB,CAC7B,UAAU,CAAC,iBAAiB,EAC5B,+BAA+B,GAAG,EAAE,CACrC,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IACxC,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IACtC,6EAA6E;IAC7E,4EAA4E;IAC5E,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3E,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAElD,uEAAuE;IACvE,OAAO,GAAG,MAAM,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;AAC5C,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,UAAkB;IAC5D,OAAO,YAAY,CAAC,OAAO,CAAC,KAAK,YAAY,CAAC,UAAU,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,9 @@
1
+ export { verifyDpopProof } from "./verify.js";
2
+ export type { VerifyDpopProofRequest, DpopVerifyResult } from "./verify.js";
3
+ export { normalizeHtu, htuMatches } from "./htu.js";
4
+ export { jwkThumbprint, accessTokenHash } from "./thumbprint.js";
5
+ export { dpopConfirmation } from "./bind.js";
6
+ export type { DpopConfirmation } from "./bind.js";
7
+ export { runDpopGuard, parseDpopAuthorization, DPOP_WWW_AUTHENTICATE, } from "./guard.js";
8
+ export type { RequireDpopOptions, DpopGuardInput, DpopGuardOutcome, } from "./guard.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/dpop/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EACL,YAAY,EACZ,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { verifyDpopProof } from "./verify.js";
2
+ export { normalizeHtu, htuMatches } from "./htu.js";
3
+ export { jwkThumbprint, accessTokenHash } from "./thumbprint.js";
4
+ export { dpopConfirmation } from "./bind.js";
5
+ export { runDpopGuard, parseDpopAuthorization, DPOP_WWW_AUTHENTICATE, } from "./guard.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/dpop/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EACL,YAAY,EACZ,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * RFC 7638 JWK SHA-256 Thumbprint, base64url without padding. This is the
3
+ * `jkt` value: the access token is bound to the proof key by embedding this
4
+ * thumbprint in the token's `cnf.jkt`, and the resource server confirms the
5
+ * DPoP proof's `jwk` produces the same thumbprint (RFC 9449 §6).
6
+ */
7
+ export declare function jwkThumbprint(jwk: JsonWebKey): Promise<string>;
8
+ /**
9
+ * The `ath` claim: base64url(SHA-256(ASCII(access token))) (RFC 9449 §4.2).
10
+ * Lets the server confirm the proof was minted for the exact token presented.
11
+ */
12
+ export declare function accessTokenHash(accessToken: string): Promise<string>;
13
+ //# sourceMappingURL=thumbprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thumbprint.d.ts","sourceRoot":"","sources":["../../../src/core/dpop/thumbprint.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAEpE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI1E"}
@@ -0,0 +1,30 @@
1
+ import { calculateJwkThumbprint } from "jose";
2
+ /**
3
+ * RFC 7638 JWK SHA-256 Thumbprint, base64url without padding. This is the
4
+ * `jkt` value: the access token is bound to the proof key by embedding this
5
+ * thumbprint in the token's `cnf.jkt`, and the resource server confirms the
6
+ * DPoP proof's `jwk` produces the same thumbprint (RFC 9449 §6).
7
+ */
8
+ export async function jwkThumbprint(jwk) {
9
+ return calculateJwkThumbprint(jwk, "sha256");
10
+ }
11
+ /**
12
+ * The `ath` claim: base64url(SHA-256(ASCII(access token))) (RFC 9449 §4.2).
13
+ * Lets the server confirm the proof was minted for the exact token presented.
14
+ */
15
+ export async function accessTokenHash(accessToken) {
16
+ const bytes = new TextEncoder().encode(accessToken);
17
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
18
+ return base64UrlBytes(new Uint8Array(digest));
19
+ }
20
+ function base64UrlBytes(b) {
21
+ let s = "";
22
+ for (let i = 0; i < b.length; i++)
23
+ s += String.fromCharCode(b[i]);
24
+ return Buffer.from(s, "binary")
25
+ .toString("base64")
26
+ .replace(/=/g, "")
27
+ .replace(/\+/g, "-")
28
+ .replace(/\//g, "_");
29
+ }
30
+ //# sourceMappingURL=thumbprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thumbprint.js","sourceRoot":"","sources":["../../../src/core/dpop/thumbprint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAY,MAAM,MAAM,CAAC;AAExD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAe;IACjD,OAAO,sBAAsB,CAAC,GAAU,EAAE,QAAQ,CAAC,CAAC;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,WAAmB;IACvD,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC5D,OAAO,cAAc,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,cAAc,CAAC,CAAa;IACnC,IAAI,CAAC,GAAG,EAAE,CAAC;IACX,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,CAAC,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC,CAAC;IAC5E,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC;SAC5B,QAAQ,CAAC,QAAQ,CAAC;SAClB,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;SACjB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACzB,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { type JWTPayload } from "jose";
2
+ import type { ProofReplayCache } from "../types.js";
3
+ export interface VerifyDpopProofRequest {
4
+ /** The `DPoP` header value (the proof JWT). */
5
+ proof: string | undefined;
6
+ /** The actual HTTP method of the request being guarded. */
7
+ method: string;
8
+ /** The actual absolute request URL (scheme://host[:port]/path...). */
9
+ url: string;
10
+ /**
11
+ * The bearer access token presented with the request, when binding a token.
12
+ * Omit for pure proof-of-possession (no token).
13
+ */
14
+ accessToken?: string | undefined;
15
+ /**
16
+ * The `cnf.jkt` the presented access token was issued against. Required
17
+ * whenever `accessToken` is set unless `requireTokenBinding` is explicitly
18
+ * false. When present, the proof key's thumbprint MUST equal it.
19
+ */
20
+ boundJkt?: string | undefined;
21
+ /**
22
+ * Default true. With a token presented but no `boundJkt`, throw
23
+ * DPOP_TOKEN_BINDING_REQUIRED rather than silently accepting an unbound
24
+ * proof. Pass false to opt into proof-of-possession-only on a presented
25
+ * token — strictly weaker, a conscious choice.
26
+ */
27
+ requireTokenBinding?: boolean | undefined;
28
+ /** Acceptable `iat` window in ms (past and future). Default 300000. */
29
+ iatWindowMs?: number | undefined;
30
+ /**
31
+ * jti replay store. Reuses the per-request proof cache: keyed on the proof
32
+ * `jti`. Default no-op (no replay defense). Pass Memory/Redis to enable.
33
+ */
34
+ replayCache?: ProofReplayCache | undefined;
35
+ }
36
+ export interface DpopVerifyResult {
37
+ /** RFC 7638 thumbprint of the proof key — the value to bind a token to. */
38
+ jkt: string;
39
+ /** The proof's unique id, recorded for replay defense. */
40
+ jti: string;
41
+ payload: JWTPayload;
42
+ }
43
+ export declare function verifyDpopProof(req: VerifyDpopProofRequest): Promise<DpopVerifyResult>;
44
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../src/core/dpop/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,MAAM,CAAC;AAGd,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAWpD,MAAM,WAAW,sBAAsB;IACrC,+CAA+C;IAC/C,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1C,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC;;;OAGG;IACH,WAAW,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAC5C;AAED,MAAM,WAAW,gBAAgB;IAC/B,2EAA2E;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ,0DAA0D;IAC1D,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,UAAU,CAAC;CACrB;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,sBAAsB,GAC1B,OAAO,CAAC,gBAAgB,CAAC,CA6I3B"}
@@ -0,0 +1,124 @@
1
+ import { decodeProtectedHeader, importJWK, jwtVerify, } from "jose";
2
+ import { DbscVerificationError, ErrorCodes } from "../errors.js";
3
+ import { validateJwk } from "../crypto/jwk.js";
4
+ import { htuMatches } from "./htu.js";
5
+ import { accessTokenHash, jwkThumbprint } from "./thumbprint.js";
6
+ const DPOP_TYP = "dpop+jwt";
7
+ const SUPPORTED_ALGS = ["ES256", "RS256"];
8
+ const DEFAULT_IAT_WINDOW_MS = 5 * 60 * 1000;
9
+ // Private-key members that must never appear in a DPoP proof's public jwk
10
+ // (RFC 9449 §4.3: "the jwk JOSE Header Parameter does not contain a private key").
11
+ const PRIVATE_JWK_MEMBERS = ["d", "p", "q", "dp", "dq", "qi", "k", "oth"];
12
+ export async function verifyDpopProof(req) {
13
+ if (!req.proof) {
14
+ throw new DbscVerificationError(ErrorCodes.DPOP_PROOF_MISSING, "DPoP header missing");
15
+ }
16
+ // A DPoP header carrying more than one token is malformed (§4.3).
17
+ if (req.proof.includes(",") || /\s/.test(req.proof.trim())) {
18
+ throw new DbscVerificationError(ErrorCodes.DPOP_PROOF_MALFORMED, "DPoP header must be a single JWT");
19
+ }
20
+ let header;
21
+ try {
22
+ header = decodeProtectedHeader(req.proof);
23
+ }
24
+ catch {
25
+ throw new DbscVerificationError(ErrorCodes.DPOP_PROOF_MALFORMED, "failed to decode DPoP header");
26
+ }
27
+ if (header["typ"] !== DPOP_TYP) {
28
+ throw new DbscVerificationError(ErrorCodes.DPOP_INVALID_TYP, `expected typ=${DPOP_TYP}, got ${String(header["typ"])}`);
29
+ }
30
+ const alg = header["alg"];
31
+ if (!SUPPORTED_ALGS.includes(alg)) {
32
+ throw new DbscVerificationError(ErrorCodes.DPOP_INVALID_ALG, `unsupported or disallowed alg: ${String(alg)}`);
33
+ }
34
+ const jwk = header["jwk"];
35
+ if (!jwk || typeof jwk !== "object") {
36
+ throw new DbscVerificationError(ErrorCodes.DPOP_PROOF_MALFORMED, "DPoP proof missing jwk header");
37
+ }
38
+ for (const m of PRIVATE_JWK_MEMBERS) {
39
+ if (m in jwk) {
40
+ throw new DbscVerificationError(ErrorCodes.DPOP_JWK_PRIVATE, "DPoP proof jwk contains private key material");
41
+ }
42
+ }
43
+ // Reuse the existing JWK validation (P-256 / RSA-2048 floor). Map its
44
+ // INVALID_JWK to the DPoP code so callers get a DPoP-shaped error.
45
+ try {
46
+ validateJwk(jwk);
47
+ }
48
+ catch {
49
+ throw new DbscVerificationError(ErrorCodes.DPOP_PROOF_MALFORMED, "DPoP proof jwk failed validation");
50
+ }
51
+ let key;
52
+ try {
53
+ key = await importJWK(jwk, alg);
54
+ }
55
+ catch {
56
+ throw new DbscVerificationError(ErrorCodes.DPOP_PROOF_MALFORMED, "failed to import DPoP proof jwk");
57
+ }
58
+ let payload;
59
+ try {
60
+ const result = await jwtVerify(req.proof, key, { algorithms: [...SUPPORTED_ALGS] });
61
+ payload = result.payload;
62
+ }
63
+ catch {
64
+ throw new DbscVerificationError(ErrorCodes.DPOP_SIGNATURE_INVALID, "DPoP proof signature did not verify");
65
+ }
66
+ const { jti, htm, htu, iat } = payload;
67
+ if (typeof jti !== "string" || !jti) {
68
+ throw new DbscVerificationError(ErrorCodes.DPOP_PROOF_MALFORMED, "DPoP proof missing jti");
69
+ }
70
+ if (typeof htm !== "string") {
71
+ throw new DbscVerificationError(ErrorCodes.DPOP_PROOF_MALFORMED, "DPoP proof missing htm");
72
+ }
73
+ if (typeof htu !== "string") {
74
+ throw new DbscVerificationError(ErrorCodes.DPOP_PROOF_MALFORMED, "DPoP proof missing htu");
75
+ }
76
+ if (typeof iat !== "number") {
77
+ throw new DbscVerificationError(ErrorCodes.DPOP_PROOF_MALFORMED, "DPoP proof missing iat");
78
+ }
79
+ if (htm.toUpperCase() !== req.method.toUpperCase()) {
80
+ throw new DbscVerificationError(ErrorCodes.DPOP_HTM_MISMATCH, "DPoP htm does not match request method");
81
+ }
82
+ if (!htuMatches(htu, req.url)) {
83
+ throw new DbscVerificationError(ErrorCodes.DPOP_HTU_MISMATCH, "DPoP htu does not match request URI");
84
+ }
85
+ // iat is a NumericDate (seconds). Window applies in both directions to allow
86
+ // for clock skew (§11.1).
87
+ const windowMs = req.iatWindowMs ?? DEFAULT_IAT_WINDOW_MS;
88
+ if (Math.abs(Date.now() - iat * 1000) > windowMs) {
89
+ throw new DbscVerificationError(ErrorCodes.DPOP_IAT_OUT_OF_WINDOW, "DPoP iat outside acceptable window");
90
+ }
91
+ const jkt = await jwkThumbprint(jwk);
92
+ // Token binding. Default-secure: a presented token without a boundJkt is
93
+ // rejected, never silently downgraded.
94
+ if (req.accessToken !== undefined) {
95
+ const requireBinding = req.requireTokenBinding ?? true;
96
+ if (req.boundJkt === undefined) {
97
+ if (requireBinding) {
98
+ throw new DbscVerificationError(ErrorCodes.DPOP_TOKEN_BINDING_REQUIRED, "access token presented without a bound jkt; pass getBoundJkt or set requireTokenBinding:false");
99
+ }
100
+ }
101
+ else if (jkt !== req.boundJkt) {
102
+ throw new DbscVerificationError(ErrorCodes.DPOP_JKT_MISMATCH, "DPoP proof key does not match token cnf.jkt");
103
+ }
104
+ const ath = payload.ath;
105
+ if (typeof ath !== "string") {
106
+ throw new DbscVerificationError(ErrorCodes.DPOP_ATH_MISMATCH, "DPoP proof missing ath for presented token");
107
+ }
108
+ const expected = await accessTokenHash(req.accessToken);
109
+ if (ath !== expected) {
110
+ throw new DbscVerificationError(ErrorCodes.DPOP_ATH_MISMATCH, "DPoP ath does not match presented token");
111
+ }
112
+ }
113
+ // Replay defense, after the cryptographic gate. Recording an unverified jti
114
+ // would let an attacker poison the cache. TTL is 2*window so a proof at the
115
+ // edge of the future window survives until the past window closes.
116
+ if (req.replayCache) {
117
+ const fresh = await req.replayCache.checkAndRecord(`dpop:${jti}`, 2 * windowMs);
118
+ if (!fresh) {
119
+ throw new DbscVerificationError(ErrorCodes.DPOP_JTI_REPLAY, "DPoP proof jti already used (replay)");
120
+ }
121
+ }
122
+ return { jkt, jti, payload };
123
+ }
124
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../../src/core/dpop/verify.ts"],"names":[],"mappings":"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"}
@@ -29,5 +29,18 @@ export declare const ErrorCodes: {
29
29
  readonly MISSING_PROOF: "MISSING_PROOF";
30
30
  readonly MALFORMED_PROOF: "MALFORMED_PROOF";
31
31
  readonly PROOF_REPLAY: "PROOF_REPLAY";
32
+ readonly DPOP_PROOF_MISSING: "DPOP_PROOF_MISSING";
33
+ readonly DPOP_PROOF_MALFORMED: "DPOP_PROOF_MALFORMED";
34
+ readonly DPOP_INVALID_TYP: "DPOP_INVALID_TYP";
35
+ readonly DPOP_INVALID_ALG: "DPOP_INVALID_ALG";
36
+ readonly DPOP_JWK_PRIVATE: "DPOP_JWK_PRIVATE";
37
+ readonly DPOP_SIGNATURE_INVALID: "DPOP_SIGNATURE_INVALID";
38
+ readonly DPOP_HTM_MISMATCH: "DPOP_HTM_MISMATCH";
39
+ readonly DPOP_HTU_MISMATCH: "DPOP_HTU_MISMATCH";
40
+ readonly DPOP_IAT_OUT_OF_WINDOW: "DPOP_IAT_OUT_OF_WINDOW";
41
+ readonly DPOP_JTI_REPLAY: "DPOP_JTI_REPLAY";
42
+ readonly DPOP_ATH_MISMATCH: "DPOP_ATH_MISMATCH";
43
+ readonly DPOP_JKT_MISMATCH: "DPOP_JKT_MISMATCH";
44
+ readonly DPOP_TOKEN_BINDING_REQUIRED: "DPOP_TOKEN_BINDING_REQUIRED";
32
45
  };
33
46
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1C;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1C;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1C;AAED,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;CAuBb,CAAC"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1C;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1C;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1C;AAED,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuCb,CAAC"}
@@ -45,5 +45,21 @@ export const ErrorCodes = {
45
45
  MISSING_PROOF: "MISSING_PROOF",
46
46
  MALFORMED_PROOF: "MALFORMED_PROOF",
47
47
  PROOF_REPLAY: "PROOF_REPLAY",
48
+ // DPoP (RFC 9449). Optional layer, reached only via the dbsc-toolkit/dpop
49
+ // subpath. A failed DPoP check maps to HTTP 401 + WWW-Authenticate: DPoP
50
+ // (resource-server semantics) — not the 403 the DBSC per-request proof uses.
51
+ DPOP_PROOF_MISSING: "DPOP_PROOF_MISSING",
52
+ DPOP_PROOF_MALFORMED: "DPOP_PROOF_MALFORMED",
53
+ DPOP_INVALID_TYP: "DPOP_INVALID_TYP",
54
+ DPOP_INVALID_ALG: "DPOP_INVALID_ALG",
55
+ DPOP_JWK_PRIVATE: "DPOP_JWK_PRIVATE",
56
+ DPOP_SIGNATURE_INVALID: "DPOP_SIGNATURE_INVALID",
57
+ DPOP_HTM_MISMATCH: "DPOP_HTM_MISMATCH",
58
+ DPOP_HTU_MISMATCH: "DPOP_HTU_MISMATCH",
59
+ DPOP_IAT_OUT_OF_WINDOW: "DPOP_IAT_OUT_OF_WINDOW",
60
+ DPOP_JTI_REPLAY: "DPOP_JTI_REPLAY",
61
+ DPOP_ATH_MISMATCH: "DPOP_ATH_MISMATCH",
62
+ DPOP_JKT_MISMATCH: "DPOP_JKT_MISMATCH",
63
+ DPOP_TOKEN_BINDING_REQUIRED: "DPOP_TOKEN_BINDING_REQUIRED",
48
64
  };
49
65
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,IAAI,CAAS;IAEtB,YAAY,IAAY,EAAE,OAAe;QACvC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IACrC,IAAI,CAAS;IAEtB,YAAY,IAAY,EAAE,OAAe;QACvC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAChC,IAAI,CAAS;IAEtB,YAAY,IAAY,EAAE,OAAe;QACvC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,uBAAuB,EAAE,yBAAyB;IAClD,aAAa,EAAE,eAAe;IAC9B,WAAW,EAAE,aAAa;IAC1B,iBAAiB,EAAE,mBAAmB;IACtC,mBAAmB,EAAE,qBAAqB;IAC1C,iBAAiB,EAAE,mBAAmB;IACtC,kBAAkB,EAAE,oBAAoB;IACxC,YAAY,EAAE,cAAc;IAC5B,iBAAiB,EAAE,mBAAmB;IACtC,aAAa,EAAE,eAAe;IAC9B,wEAAwE;IACxE,0EAA0E;IAC1E,wEAAwE;IACxE,gBAAgB;IAChB,oBAAoB,EAAE,sBAAsB;IAC5C,mBAAmB,EAAE,qBAAqB;IAC1C,iBAAiB,EAAE,mBAAmB;IACtC,0BAA0B,EAAE,4BAA4B;IACxD,YAAY,EAAE,cAAc;IAC5B,aAAa,EAAE,eAAe;IAC9B,eAAe,EAAE,iBAAiB;IAClC,YAAY,EAAE,cAAc;CACpB,CAAC"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,IAAI,CAAS;IAEtB,YAAY,IAAY,EAAE,OAAe;QACvC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IACrC,IAAI,CAAS;IAEtB,YAAY,IAAY,EAAE,OAAe;QACvC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAChC,IAAI,CAAS;IAEtB,YAAY,IAAY,EAAE,OAAe;QACvC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,uBAAuB,EAAE,yBAAyB;IAClD,aAAa,EAAE,eAAe;IAC9B,WAAW,EAAE,aAAa;IAC1B,iBAAiB,EAAE,mBAAmB;IACtC,mBAAmB,EAAE,qBAAqB;IAC1C,iBAAiB,EAAE,mBAAmB;IACtC,kBAAkB,EAAE,oBAAoB;IACxC,YAAY,EAAE,cAAc;IAC5B,iBAAiB,EAAE,mBAAmB;IACtC,aAAa,EAAE,eAAe;IAC9B,wEAAwE;IACxE,0EAA0E;IAC1E,wEAAwE;IACxE,gBAAgB;IAChB,oBAAoB,EAAE,sBAAsB;IAC5C,mBAAmB,EAAE,qBAAqB;IAC1C,iBAAiB,EAAE,mBAAmB;IACtC,0BAA0B,EAAE,4BAA4B;IACxD,YAAY,EAAE,cAAc;IAC5B,aAAa,EAAE,eAAe;IAC9B,eAAe,EAAE,iBAAiB;IAClC,YAAY,EAAE,cAAc;IAC5B,0EAA0E;IAC1E,yEAAyE;IACzE,6EAA6E;IAC7E,kBAAkB,EAAE,oBAAoB;IACxC,oBAAoB,EAAE,sBAAsB;IAC5C,gBAAgB,EAAE,kBAAkB;IACpC,gBAAgB,EAAE,kBAAkB;IACpC,gBAAgB,EAAE,kBAAkB;IACpC,sBAAsB,EAAE,wBAAwB;IAChD,iBAAiB,EAAE,mBAAmB;IACtC,iBAAiB,EAAE,mBAAmB;IACtC,sBAAsB,EAAE,wBAAwB;IAChD,eAAe,EAAE,iBAAiB;IAClC,iBAAiB,EAAE,mBAAmB;IACtC,iBAAiB,EAAE,mBAAmB;IACtC,2BAA2B,EAAE,6BAA6B;CAClD,CAAC"}