@rebasepro/server 0.23.0 → 0.24.1-canary.g19596ef

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 (287) hide show
  1. package/README.md +28 -3
  2. package/bin/rebase-server.js +4 -2
  3. package/dist/GCSStorageController-DEga1ULx.js +402 -0
  4. package/dist/GCSStorageController-DEga1ULx.js.map +1 -0
  5. package/dist/S3StorageController-Btx-6bJ5.js +480 -0
  6. package/dist/S3StorageController-Btx-6bJ5.js.map +1 -0
  7. package/dist/api/ast-schema-editor.d.ts +92 -1
  8. package/dist/api/errors.d.ts +41 -0
  9. package/dist/api/live-schema-routes.d.ts +64 -10
  10. package/dist/api/logs-routes.d.ts +39 -1
  11. package/dist/api/mount-path.d.ts +30 -0
  12. package/dist/api/mount.d.ts +6 -13
  13. package/dist/api/openapi-generator.d.ts +17 -0
  14. package/dist/api/rest/api-generator.d.ts +97 -11
  15. package/dist/api/rest/auth-collection-writes.d.ts +28 -21
  16. package/dist/api/rest/field-access-query.d.ts +28 -8
  17. package/dist/api/rest/field-ops.d.ts +19 -7
  18. package/dist/api/rest/query-body.d.ts +10 -0
  19. package/dist/api/rest/write-validation.d.ts +9 -7
  20. package/dist/api/schema-editor-routes.d.ts +10 -1
  21. package/dist/api/sql-export-routes.d.ts +8 -0
  22. package/dist/api/types.d.ts +52 -1
  23. package/dist/{ast-schema-editor-Mvr50v_S.js → ast-schema-editor-mCeSC03x.js} +310 -12
  24. package/dist/ast-schema-editor-mCeSC03x.js.map +1 -0
  25. package/dist/auth/access.d.ts +156 -0
  26. package/dist/auth/adapter-middleware.d.ts +2 -1
  27. package/dist/auth/address-ownership.d.ts +16 -1
  28. package/dist/auth/admin-roles-route.d.ts +4 -2
  29. package/dist/auth/admin-roles.d.ts +17 -20
  30. package/dist/auth/admin-user-ops.d.ts +24 -2
  31. package/dist/auth/admin-users-route.d.ts +2 -0
  32. package/dist/auth/api-keys/api-key-middleware.d.ts +64 -56
  33. package/dist/auth/api-keys/api-key-routes.d.ts +44 -11
  34. package/dist/auth/api-keys/api-key-store.d.ts +31 -8
  35. package/dist/auth/api-keys/api-key-types.d.ts +14 -16
  36. package/dist/auth/api-keys/http-operation.d.ts +19 -0
  37. package/dist/auth/api-keys/index.d.ts +11 -11
  38. package/dist/auth/api-keys/key-grant.d.ts +41 -0
  39. package/dist/auth/api-keys/legacy-permissions.d.ts +33 -0
  40. package/dist/auth/auth-hooks.d.ts +46 -7
  41. package/dist/auth/builtin-auth-adapter.d.ts +21 -0
  42. package/dist/auth/cookie-utils.d.ts +7 -0
  43. package/dist/auth/deliverable-address.d.ts +6 -0
  44. package/dist/auth/email-change-routes.d.ts +44 -0
  45. package/dist/auth/expired-token-sweep.d.ts +71 -0
  46. package/dist/auth/impersonation.d.ts +110 -0
  47. package/dist/auth/index.d.ts +4 -2
  48. package/dist/auth/interfaces.d.ts +120 -59
  49. package/dist/auth/jwks-routes.d.ts +5 -1
  50. package/dist/auth/jwt-crypto.d.ts +7 -0
  51. package/dist/auth/jwt-keys.d.ts +4 -0
  52. package/dist/auth/jwt.d.ts +319 -157
  53. package/dist/auth/magic-link-routes.d.ts +5 -6
  54. package/dist/auth/mfa-crypto.d.ts +9 -3
  55. package/dist/auth/mfa-gate.d.ts +4 -2
  56. package/dist/auth/mfa-routes.d.ts +8 -9
  57. package/dist/auth/middleware.d.ts +26 -7
  58. package/dist/auth/otp-routes.d.ts +5 -6
  59. package/dist/auth/passwordless-signup.d.ts +27 -0
  60. package/dist/auth/platform-token.d.ts +122 -0
  61. package/dist/auth/rate-limiter.d.ts +99 -31
  62. package/dist/auth/registration-policy.d.ts +17 -0
  63. package/dist/auth/require-auth.d.ts +1 -1
  64. package/dist/auth/routes.d.ts +61 -0
  65. package/dist/auth/scope-routes.d.ts +22 -0
  66. package/dist/auth/session-routes.d.ts +17 -6
  67. package/dist/auth/token-revocation.d.ts +56 -1
  68. package/dist/auth/user-picking.d.ts +37 -0
  69. package/dist/auth/verify-credential.d.ts +49 -0
  70. package/dist/{auth-B-GIMpDG.js → auth-CSBky1mt.js} +4564 -1929
  71. package/dist/auth-CSBky1mt.js.map +1 -0
  72. package/dist/auth_adapter-CIItCTc8.js +21 -0
  73. package/dist/auth_adapter-CIItCTc8.js.map +1 -0
  74. package/dist/backend/create-backend.d.ts +281 -0
  75. package/dist/backend/default-backend.d.ts +35 -0
  76. package/dist/backend/no-collections.d.ts +19 -0
  77. package/dist/backend/options.d.ts +912 -0
  78. package/dist/backend/scope.d.ts +23 -0
  79. package/dist/backend/services.d.ts +54 -0
  80. package/dist/backend-DTAOsLQc.js.map +1 -1
  81. package/dist/backup/backup-common.d.ts +24 -3
  82. package/dist/backup/backup-routes.d.ts +46 -5
  83. package/dist/backup/backup-schedule.d.ts +33 -0
  84. package/dist/backup/backup-storage.d.ts +16 -0
  85. package/dist/backup/index.d.ts +5 -1
  86. package/dist/backup-DBGRUVTS.js +585 -0
  87. package/dist/backup-DBGRUVTS.js.map +1 -0
  88. package/dist/boot/boot.d.ts +2 -2
  89. package/dist/boot/bundle.d.ts +19 -0
  90. package/dist/boot/driver.d.ts +3 -0
  91. package/dist/boot/env.d.ts +58 -6
  92. package/dist/boot/http-server.d.ts +22 -0
  93. package/dist/boot/options.d.ts +16 -1
  94. package/dist/boot/provision.d.ts +4 -2
  95. package/dist/boot/resource-adapters.d.ts +11 -14
  96. package/dist/boot/runtime-cors.d.ts +17 -0
  97. package/dist/boot/security-headers.d.ts +26 -0
  98. package/dist/boot/sources.d.ts +9 -0
  99. package/dist/boot/static-routing.d.ts +65 -0
  100. package/dist/collection_patch-BRu-BvDv.js +472 -0
  101. package/dist/collection_patch-BRu-BvDv.js.map +1 -0
  102. package/dist/{contract-routes-CbFjuBwa.js → contract-routes-DiFwiLg2.js} +5 -8
  103. package/dist/contract-routes-DiFwiLg2.js.map +1 -0
  104. package/dist/cron/cron-loader.d.ts +77 -18
  105. package/dist/cron/cron-routes.d.ts +1 -1
  106. package/dist/cron/cron-scheduler.d.ts +94 -23
  107. package/dist/cron/cron-store.d.ts +37 -5
  108. package/dist/cron/define-cron.d.ts +6 -2
  109. package/dist/cron/index.d.ts +3 -3
  110. package/dist/cron-loader-NHqRfKF0.js +202 -0
  111. package/dist/cron-loader-NHqRfKF0.js.map +1 -0
  112. package/dist/{cron-routes-eE8nif_b.js → cron-routes-DsH8Jwn5.js} +34 -8
  113. package/dist/cron-routes-DsH8Jwn5.js.map +1 -0
  114. package/dist/{cron-scheduler-B0pLfAix.js → cron-scheduler-D1DT0nw5.js} +349 -65
  115. package/dist/cron-scheduler-D1DT0nw5.js.map +1 -0
  116. package/dist/cron-store-DEpVstUU.js +577 -0
  117. package/dist/cron-store-DEpVstUU.js.map +1 -0
  118. package/dist/{ddl-bootstrap-C6mo0Kmz.js → ddl-bootstrap-BNqi2NZe.js} +2 -2
  119. package/dist/{ddl-bootstrap-C6mo0Kmz.js.map → ddl-bootstrap-BNqi2NZe.js.map} +1 -1
  120. package/dist/email/index.d.ts +2 -2
  121. package/dist/email/smtp-email-service.d.ts +23 -0
  122. package/dist/email/templates.d.ts +22 -0
  123. package/dist/email/types.d.ts +44 -0
  124. package/dist/env.d.ts +1 -39
  125. package/dist/{errors-DWsX4yTd.js → errors-Cqp86KnA.js} +263 -10
  126. package/dist/errors-Cqp86KnA.js.map +1 -0
  127. package/dist/filter-dialect-O1HK6Nvr.js +1628 -0
  128. package/dist/filter-dialect-O1HK6Nvr.js.map +1 -0
  129. package/dist/{function-loader-xnbDAPfa.js → function-loader-DbCSoNJj.js} +69 -39
  130. package/dist/function-loader-DbCSoNJj.js.map +1 -0
  131. package/dist/{function-routes-Chet4-lB.js → function-routes-BSTClQNa.js} +28 -15
  132. package/dist/function-routes-BSTClQNa.js.map +1 -0
  133. package/dist/functions/context.d.ts +26 -6
  134. package/dist/functions/define-function.d.ts +10 -6
  135. package/dist/functions/function-loader.d.ts +75 -18
  136. package/dist/functions/function-routes.d.ts +2 -1
  137. package/dist/functions/guards.d.ts +22 -5
  138. package/dist/functions/index.d.ts +6 -5
  139. package/dist/functions/index.js +148 -50
  140. package/dist/functions/index.js.map +1 -1
  141. package/dist/functions/internal.d.ts +2 -2
  142. package/dist/functions/proxy.d.ts +6 -2
  143. package/dist/functions/request-timeout.d.ts +7 -5
  144. package/dist/history/history-routes.d.ts +9 -0
  145. package/dist/history/retention-sweep.d.ts +81 -0
  146. package/dist/{history-recorder-B4MpJfJK.js → history-recorder-RZ1Ow4YY.js} +4 -4
  147. package/dist/{history-recorder-B4MpJfJK.js.map → history-recorder-RZ1Ow4YY.js.map} +1 -1
  148. package/dist/{history-store-BhxWOuz9.js → history-store-DPofGVDp.js} +2 -2
  149. package/dist/{history-store-BhxWOuz9.js.map → history-store-DPofGVDp.js.map} +1 -1
  150. package/dist/index.d.ts +32 -13
  151. package/dist/index.es.js +25329 -18393
  152. package/dist/index.es.js.map +1 -1
  153. package/dist/init/docs.d.ts +35 -10
  154. package/dist/init/health.d.ts +17 -2
  155. package/dist/init/process-safety.d.ts +7 -2
  156. package/dist/init/shutdown.d.ts +26 -1
  157. package/dist/init.d.ts +49 -811
  158. package/dist/internal-tables-L2t39RdT.js +136 -0
  159. package/dist/internal-tables-L2t39RdT.js.map +1 -0
  160. package/dist/jobs/job-queue.d.ts +8 -0
  161. package/dist/jobs/job-store.d.ts +24 -0
  162. package/dist/jobs/types.d.ts +25 -4
  163. package/dist/{jobs-CazMYhyy.js → jobs-8G-_agld.js} +235 -25
  164. package/dist/jobs-8G-_agld.js.map +1 -0
  165. package/dist/{jwt-DnQHNFCl.js → jwt-CBaFc34Y.js} +546 -447
  166. package/dist/jwt-CBaFc34Y.js.map +1 -0
  167. package/dist/{keys-CogCQpxG.js → keys-COzQ2aE8.js} +3 -17
  168. package/dist/{keys-CogCQpxG.js.map → keys-COzQ2aE8.js.map} +1 -1
  169. package/dist/load-failure-L5hvfDoG.js +80 -0
  170. package/dist/load-failure-L5hvfDoG.js.map +1 -0
  171. package/dist/{logger-DO2PZc4i.js → logger-Bt32sHFw.js} +41 -5
  172. package/dist/logger-Bt32sHFw.js.map +1 -0
  173. package/dist/{logs-routes-Bj4TYYUl.js → logs-routes-DQJhrf-b.js} +48 -8
  174. package/dist/logs-routes-DQJhrf-b.js.map +1 -0
  175. package/dist/mcp/consent-page.d.ts +1 -1
  176. package/dist/mcp/mcp-routes.d.ts +13 -0
  177. package/dist/mcp/mcp-tools.d.ts +23 -9
  178. package/dist/mcp/oauth-metadata.d.ts +21 -16
  179. package/dist/mcp/oauth-routes.d.ts +14 -1
  180. package/dist/metrics/index.d.ts +18 -0
  181. package/dist/metrics/pool-wait.d.ts +50 -0
  182. package/dist/offline-QNQgsPOq-B2yGeXkn.js +3305 -0
  183. package/dist/offline-QNQgsPOq-B2yGeXkn.js.map +1 -0
  184. package/dist/offline-store-Cm5sAX81-CALiO4Gn.js +1915 -0
  185. package/dist/offline-store-Cm5sAX81-CALiO4Gn.js.map +1 -0
  186. package/dist/{openapi-generator-O_O24MAT.js → openapi-generator-CeGW2dLC.js} +455 -80
  187. package/dist/openapi-generator-CeGW2dLC.js.map +1 -0
  188. package/dist/policy-PdzX-Opd.js +121 -0
  189. package/dist/policy-PdzX-Opd.js.map +1 -0
  190. package/dist/project_manifest-R6y_KHms.js +59 -0
  191. package/dist/project_manifest-R6y_KHms.js.map +1 -0
  192. package/dist/{proxy-Czngl3p9.js → proxy-BEKbsil6.js} +5 -4
  193. package/dist/proxy-BEKbsil6.js.map +1 -0
  194. package/dist/{query-parser-DGRVFNM3.js → query-parser-ECxP0nDw.js} +497 -52
  195. package/dist/query-parser-ECxP0nDw.js.map +1 -0
  196. package/dist/{request-timeout-C_4C2BeR.js → request-timeout-BiRelY-U.js} +17 -10
  197. package/dist/request-timeout-BiRelY-U.js.map +1 -0
  198. package/dist/resumable-upload-threshold-CKv-Ry0l.js +24 -0
  199. package/dist/resumable-upload-threshold-CKv-Ry0l.js.map +1 -0
  200. package/dist/schema-edit/apply-schema-change.d.ts +73 -3
  201. package/dist/schema-edit/local-source.d.ts +29 -0
  202. package/dist/schema-edit/project-root.d.ts +3 -2
  203. package/dist/schema-edit/remote-source.d.ts +20 -5
  204. package/dist/schema-edit/source-editor.d.ts +28 -0
  205. package/dist/schema-editor-routes-DRXBAbZy.js +136 -0
  206. package/dist/schema-editor-routes-DRXBAbZy.js.map +1 -0
  207. package/dist/serve-spa.d.ts +58 -0
  208. package/dist/services/outbound-post.d.ts +50 -0
  209. package/dist/services/outbound-url-guard.d.ts +34 -5
  210. package/dist/services/routed-realtime-service.d.ts +16 -0
  211. package/dist/services/webhook-service.d.ts +66 -14
  212. package/dist/singleton.d.ts +9 -5
  213. package/dist/soft-delete-params-CBryZXMq.js +668 -0
  214. package/dist/soft-delete-params-CBryZXMq.js.map +1 -0
  215. package/dist/sql-export-routes-D8ZaRvoR.js +240 -0
  216. package/dist/sql-export-routes-D8ZaRvoR.js.map +1 -0
  217. package/dist/{src-vkcwKXbT.js → src-D5Y3N-S4.js} +440 -20
  218. package/dist/src-D5Y3N-S4.js.map +1 -0
  219. package/dist/storage/GCSStorageController.d.ts +48 -2
  220. package/dist/storage/LocalStorageController.d.ts +69 -2
  221. package/dist/storage/S3StorageController.d.ts +39 -3
  222. package/dist/storage/image-transform.d.ts +15 -0
  223. package/dist/storage/index.d.ts +2 -2
  224. package/dist/storage/maintenance-routes.d.ts +23 -0
  225. package/dist/storage/maintenance.d.ts +126 -0
  226. package/dist/storage/property-limits.d.ts +41 -6
  227. package/dist/storage/rendition-cache.d.ts +9 -11
  228. package/dist/storage/request-keys.d.ts +15 -0
  229. package/dist/storage/request-principals.d.ts +30 -0
  230. package/dist/storage/requested-object.d.ts +74 -0
  231. package/dist/storage/routes.d.ts +52 -14
  232. package/dist/storage/source-variables.d.ts +10 -0
  233. package/dist/storage/streams.d.ts +42 -0
  234. package/dist/storage/tus-handler.d.ts +76 -7
  235. package/dist/storage/types.d.ts +101 -7
  236. package/dist/storage/upload-validation.d.ts +13 -0
  237. package/dist/storage-resumable-VO-cMpse-C_YX71pO.js +125 -0
  238. package/dist/storage-resumable-VO-cMpse-C_YX71pO.js.map +1 -0
  239. package/dist/strings.es-BeZWAodn.js +256 -0
  240. package/dist/strings.es-BeZWAodn.js.map +1 -0
  241. package/dist/upload-validation-CVobI5xO.js +172 -0
  242. package/dist/upload-validation-CVobI5xO.js.map +1 -0
  243. package/dist/utils/byte-size.d.ts +10 -0
  244. package/dist/utils/compression.d.ts +6 -0
  245. package/dist/utils/load-failure.d.ts +14 -0
  246. package/dist/utils/logger.d.ts +21 -0
  247. package/package.json +5 -5
  248. package/dist/GCSStorageController-CjrA4PMo.js +0 -242
  249. package/dist/GCSStorageController-CjrA4PMo.js.map +0 -1
  250. package/dist/S3StorageController-B6pKDNVj.js +0 -264
  251. package/dist/S3StorageController-B6pKDNVj.js.map +0 -1
  252. package/dist/admin-roles-vYdp_Pil.js +0 -36
  253. package/dist/admin-roles-vYdp_Pil.js.map +0 -1
  254. package/dist/admin_block-DxKLmdiv.js +0 -206
  255. package/dist/admin_block-DxKLmdiv.js.map +0 -1
  256. package/dist/ast-schema-editor-Mvr50v_S.js.map +0 -1
  257. package/dist/auth/api-keys/api-key-permission-guard.d.ts +0 -65
  258. package/dist/auth-B-GIMpDG.js.map +0 -1
  259. package/dist/backup-D7YR94N3.js +0 -253
  260. package/dist/backup-D7YR94N3.js.map +0 -1
  261. package/dist/contract-routes-CbFjuBwa.js.map +0 -1
  262. package/dist/cron-loader-DfTj2Hbi.js +0 -118
  263. package/dist/cron-loader-DfTj2Hbi.js.map +0 -1
  264. package/dist/cron-routes-eE8nif_b.js.map +0 -1
  265. package/dist/cron-scheduler-B0pLfAix.js.map +0 -1
  266. package/dist/cron-store-TcoGz-xS.js +0 -305
  267. package/dist/cron-store-TcoGz-xS.js.map +0 -1
  268. package/dist/dynamic-import-X40pTZUQ.js +0 -23
  269. package/dist/dynamic-import-X40pTZUQ.js.map +0 -1
  270. package/dist/errors-DWsX4yTd.js.map +0 -1
  271. package/dist/function-loader-xnbDAPfa.js.map +0 -1
  272. package/dist/function-routes-Chet4-lB.js.map +0 -1
  273. package/dist/jobs-CazMYhyy.js.map +0 -1
  274. package/dist/jwt-DnQHNFCl.js.map +0 -1
  275. package/dist/logger-DO2PZc4i.js.map +0 -1
  276. package/dist/logs-routes-Bj4TYYUl.js.map +0 -1
  277. package/dist/openapi-generator-O_O24MAT.js.map +0 -1
  278. package/dist/proxy-Czngl3p9.js.map +0 -1
  279. package/dist/query-parser-DGRVFNM3.js.map +0 -1
  280. package/dist/request-timeout-C_4C2BeR.js.map +0 -1
  281. package/dist/schema-editor-routes-C5-lh_jO.js +0 -87
  282. package/dist/schema-editor-routes-C5-lh_jO.js.map +0 -1
  283. package/dist/src-pmvW7BFx.js +0 -6688
  284. package/dist/src-pmvW7BFx.js.map +0 -1
  285. package/dist/src-vkcwKXbT.js.map +0 -1
  286. package/dist/types-BfKcm9do.js +0 -39
  287. package/dist/types-BfKcm9do.js.map +0 -1
@@ -1,3 +1,5 @@
1
+ import type { Context } from "hono";
2
+ import type { HonoEnv } from "../api/types.js";
1
3
  import { type JwtSigningKeyConfig, type PublicJwk } from "./jwt-keys.js";
2
4
  export interface JwtConfig {
3
5
  secret: string;
@@ -61,6 +63,23 @@ export interface AccessTokenPayload {
61
63
  * comparison and the watermark was read on exactly one path — refresh.
62
64
  */
63
65
  iat?: number;
66
+ /**
67
+ * When the token expires, in seconds since the epoch — the standard `exp`
68
+ * claim. Carried through because a socket authenticated with this token
69
+ * has to stop honouring it at this instant, and has no request to refuse.
70
+ */
71
+ exp?: number;
72
+ /**
73
+ * The sign-in this token was minted for: the session id its refresh
74
+ * tokens share, carried across every rotation.
75
+ *
76
+ * What lets one device be signed out — `POST /auth/logout`,
77
+ * `DELETE /auth/sessions/:id` — reach that device's access token rather
78
+ * than only its refresh token, and what lets `GET /auth/sessions` mark the
79
+ * caller's own session. Absent on tokens minted before it existed; those
80
+ * keep working until they expire, judged by the watermark alone.
81
+ */
82
+ sid?: string;
64
83
  /** Email claim from the JWT, if present */
65
84
  email?: string;
66
85
  /** Display name claim from the JWT, if present */
@@ -90,48 +109,284 @@ export interface AccessTokenPayload {
90
109
  claims?: Record<string, unknown>;
91
110
  }
92
111
  /**
93
- * Configure JWT settings - call this during initialization.
94
- * Validates the secret strength to prevent deployment with default/weak secrets.
112
+ * The custom half of a verified token, or nothing when there is none.
113
+ *
114
+ * Exported for the one other place that builds a request identity's claims
115
+ * without a token to verify — `resolveUser`, which reads what a token minted
116
+ * now would carry — so both drop the same identity claims.
95
117
  */
96
- export declare function configureJwt(config: JwtConfig): void;
118
+ export declare function customClaimsOf(decoded: Record<string, unknown>): Record<string, unknown> | undefined;
97
119
  /**
98
- * The public keys, in JWKS form, for `/.well-known/jwks.json`.
120
+ * How long a refresh token survives inactivity when no lifetime is configured.
121
+ * Sliding: every rotation re-ups it, so an active user stays signed in.
122
+ */
123
+ export declare const DEFAULT_REFRESH_EXPIRES_IN = "30d";
124
+ /**
125
+ * One backend's tokens: what it signs with, what it verifies against, and how
126
+ * long what it mints lives.
99
127
  *
100
- * An empty `keys` array on a backend with no asymmetric keys configured is the
101
- * correct answer rather than a 404: it says "this issuer publishes none",
102
- * which a verifier can act on, where a 404 is indistinguishable from a
103
- * misconfigured URL.
128
+ * Every backend built by `createRebaseBackend` holds its own
129
+ * (`backend.services.jwt`), so two backends in one process sign and verify
130
+ * with their own secrets and keys and a token one minted means nothing to the
131
+ * other. {@link createJwtService} builds one by hand.
132
+ *
133
+ * The module-level functions of the same names — `generateAccessToken`,
134
+ * `verifyAccessToken`, … — answer for the process default instead: what
135
+ * {@link configureJwt} set, or the backend `initializeRebaseBackend` installed.
104
136
  */
105
- export declare function getJwks(): {
106
- keys: PublicJwk[];
107
- };
108
- /** Is this backend signing access tokens asymmetrically? */
109
- export declare function hasAsymmetricSigningKey(): boolean;
137
+ export interface JwtService {
138
+ /** The access-token lifetime, in the grammar {@link parseDurationMs} reads. */
139
+ readonly accessExpiresIn: string;
140
+ /** The refresh-token lifetime, in the grammar {@link parseDurationMs} reads. */
141
+ readonly refreshExpiresIn: string;
142
+ /**
143
+ * Has this service been given a JWT secret?
144
+ *
145
+ * False on every backend that authenticates through an adapter — Firebase,
146
+ * Clerk, anything with its own tokens — because nothing gives it one there.
147
+ * Signing paths still throw when it is false, since asking for a token from
148
+ * a server that cannot mint one is a mistake worth hearing about. Paths
149
+ * whose contract is *"tolerate the absence of auth"* must ask first:
150
+ * `optionalAuth` crashing a request because this backend does not do JWT is
151
+ * a 500 on a route that had already decided anonymous was acceptable.
152
+ */
153
+ isConfigured(): boolean;
154
+ /** Is this service signing access tokens asymmetrically? */
155
+ hasAsymmetricSigningKey(): boolean;
156
+ /**
157
+ * The public keys, in JWKS form, for `/.well-known/jwks.json`.
158
+ *
159
+ * An empty `keys` array on a backend with no asymmetric keys configured is
160
+ * the correct answer rather than a 404: it says "this issuer publishes
161
+ * none", which a verifier can act on, where a 404 is indistinguishable from
162
+ * a misconfigured URL.
163
+ */
164
+ getJwks(): {
165
+ keys: PublicJwk[];
166
+ };
167
+ /**
168
+ * The symmetric secret this service signs purpose-scoped tokens with, or
169
+ * undefined when it has none — for deriving a key of the backend's own.
170
+ * MFA's encryption falls back to it when no `MFA_ENCRYPTION_KEY` is set.
171
+ * A method rather than a field, so serialising the service never prints it.
172
+ */
173
+ hmacSecret(): string | undefined;
174
+ /**
175
+ * Generate an access token (short-lived, 1 hour by default).
176
+ *
177
+ * @param isAnonymous Whether this session is a guest — anonymous sign-in
178
+ * rather than an account. Written into the token so the RLS identity and
179
+ * the WebSocket path can tell the two apart without a database lookup.
180
+ * @param sessionId The sign-in this token belongs to — see
181
+ * {@link AccessTokenPayload.sid}. Every token the auth routes mint
182
+ * carries one.
183
+ */
184
+ generateAccessToken(uid: string, roles: string[], aal?: "aal1" | "aal2", customClaims?: Record<string, unknown>, isAnonymous?: boolean, sessionId?: string): Promise<string>;
185
+ /**
186
+ * Verify and decode an access token.
187
+ *
188
+ * Every token this service issues is signed with the same secret, so what a
189
+ * token *is* comes from its claims, not from its signature. A download
190
+ * token ({@link JwtService.generateDownloadToken}) is therefore a
191
+ * validly-signed string that must never authenticate anybody: it is scoped
192
+ * to one file path and handed out in URLs, which is a far weaker thing to
193
+ * hold than a session.
194
+ *
195
+ * Today it is rejected below for want of an id — but only by luck, since
196
+ * nothing stops a future download token from carrying one. So the purpose
197
+ * is checked explicitly: a token minted for reading a file is not a token
198
+ * for being a user.
199
+ */
200
+ verifyAccessToken(token: string): Promise<AccessTokenPayload | null>;
201
+ /** The access-token lifetime in milliseconds. */
202
+ getAccessTokenExpiryMs(): number;
203
+ /** When an access token minted now expires, in milliseconds since the epoch. */
204
+ getAccessTokenExpiry(): number;
205
+ /**
206
+ * How long a refresh token is valid for, in milliseconds.
207
+ *
208
+ * Every rotation issues a token with a fresh TTL, so this is a sliding
209
+ * window: a user who visits at all keeps their session indefinitely, and
210
+ * one who disappears loses it this long after their last visit. That is
211
+ * what both Firebase and Supabase do by default, and it is the behaviour
212
+ * people mean when they say they expect to still be signed in.
213
+ */
214
+ getRefreshTokenTtlMs(): number;
215
+ /** When a refresh token minted now expires. */
216
+ getRefreshTokenExpiry(): Date;
217
+ /**
218
+ * Mint the short-lived credential handed back with an `MFA_REQUIRED`
219
+ * response.
220
+ *
221
+ * Short-lived on purpose: it is the window in which a caller who has
222
+ * proven the first factor may present the second, not a session to be
223
+ * carried around. Five minutes matches the challenge TTL.
224
+ */
225
+ generateMfaPendingToken(uid: string, expiresInSeconds?: number): Promise<string>;
226
+ /**
227
+ * Verify a pre-auth token and return the user it was minted for.
228
+ *
229
+ * Returns `null` for anything else — including a perfectly valid *access*
230
+ * token, which must not be interchangeable with this one in either
231
+ * direction.
232
+ *
233
+ * `iat` comes back with the uid because this token is a first factor that
234
+ * was accepted at that instant, and a sign-out everywhere after it has to
235
+ * void it the way it voids an access token — see `isAccessTokenRevoked`.
236
+ */
237
+ verifyMfaPendingToken(token: string): Promise<{
238
+ uid: string;
239
+ iat?: number;
240
+ } | null>;
241
+ /**
242
+ * Generate a short-lived download token scoped to a specific file path or
243
+ * prefix *within one storage source*.
244
+ *
245
+ * Both halves of that scope are load-bearing. A key is only unique inside
246
+ * its own bucket, and a project with more than one source routinely holds
247
+ * the same key in several of them — `avatars/u1.png` in `(default)` and in
248
+ * `media` are different objects, quite possibly with different owners. A
249
+ * token that names only the path is therefore a grant on every source at
250
+ * once: authorize a read on the source whose `storageAuthorize` hook says
251
+ * yes, then spend the token against `?storageId=` pointing somewhere else.
252
+ *
253
+ * `storageId` is optional here only because omitting it *is* the default
254
+ * source, which is what the overwhelming majority of deployments have. A
255
+ * mint site that forgets to pass a named source produces a default-scoped
256
+ * token, which fails closed at `/file/*` rather than over-granting.
257
+ *
258
+ * @param principal The user minting it, so the reads it buys are charged
259
+ * to them.
260
+ */
261
+ generateDownloadToken(path: string, expiresInSeconds?: number, storageId?: string | null, principal?: string | null): Promise<string>;
262
+ /**
263
+ * Verify and decode a download token.
264
+ *
265
+ * A token minted before `storageId` existed carries no such claim. It is
266
+ * read as a grant on the **default source** rather than on all of them:
267
+ * that is the fail-closed reading, and it is what such a token almost
268
+ * always was, since a named source has to be asked for explicitly. The
269
+ * cost is bounded by the five-minute TTL — for at most that long after a
270
+ * deploy, an in-flight token for a *named* source is refused and the
271
+ * client re-fetches `/metadata`.
272
+ */
273
+ verifyDownloadToken(token: string): Promise<DownloadTokenPayload | null>;
274
+ /**
275
+ * Sign a short-lived token that carries state across a redirect.
276
+ *
277
+ * The generalisation of the MFA-pending token: a signed blob the server
278
+ * hands out and expects back, where the point is that the holder cannot
279
+ * edit it. The OAuth authorize flow needs one to carry the authorization
280
+ * request across the sign-in hop — without it, the endpoint the consent
281
+ * page posts to would mint a code for whatever `client_id` and
282
+ * `redirect_uri` its caller typed, skipping every check the authorize
283
+ * endpoint performs.
284
+ *
285
+ * The `purpose` is not decoration. {@link JwtService.verifyAccessToken}
286
+ * refuses any token that has one, so nothing minted here can be replayed
287
+ * as a session, and {@link JwtService.verifyPurposeToken} refuses a token
288
+ * whose purpose is not the one the caller named — so a token minted for
289
+ * one hop cannot be spent on another.
290
+ */
291
+ signPurposeToken(purpose: string, claims: Record<string, unknown>, expiresInSeconds: number): Promise<string>;
292
+ /** Verify a token minted by {@link JwtService.signPurposeToken}, for one named purpose. */
293
+ verifyPurposeToken<T>(purpose: string, token: string): Promise<T | null>;
294
+ /**
295
+ * Mint an access token for the MCP endpoint.
296
+ *
297
+ * Deliberately **not** an ordinary session token, and the `purpose` claim
298
+ * is what enforces that: {@link JwtService.verifyAccessToken} refuses any
299
+ * token carrying one, so a credential issued to a third-party MCP client —
300
+ * Claude, an IDE, anything that completed the OAuth flow — cannot be
301
+ * replayed against `/api/data`, `/api/admin` or the websocket. It buys
302
+ * exactly the one resource it names.
303
+ *
304
+ * That asymmetry matters more than it first looks. These tokens are handed
305
+ * to software the user authorized but the operator never vetted, they
306
+ * live in that software's storage, and they are the only credential in
307
+ * this system minted for a third party. Without the purpose separation,
308
+ * "connect Claude to your data" would silently mean "give Claude a full
309
+ * session".
310
+ *
311
+ * The audience is the canonical resource URI, and
312
+ * {@link JwtService.verifyMcpAccessToken} requires the caller to say which
313
+ * resource it is checking for. A token minted for another Rebase project —
314
+ * or another path on this one — fails there.
315
+ *
316
+ * HS256 with the shared secret, like the download token: the authorization
317
+ * server and the resource server are the same process, so nothing outside
318
+ * it ever needs to verify one, and an asymmetric key here would be a
319
+ * second key surface bought for nobody.
320
+ */
321
+ generateMcpAccessToken(payload: Omit<McpAccessTokenPayload, "purpose">, expiresInSeconds: number): Promise<string>;
322
+ /**
323
+ * Verify an MCP access token **for a specific resource**.
324
+ *
325
+ * `expectedAudience` has no default. The MCP specification requires a
326
+ * resource server to validate that a token was issued for it
327
+ * specifically, and a default would be the thing that quietly turns that
328
+ * check off — the caller has to say what it is, every time, so a new call
329
+ * site cannot forget by omission.
330
+ */
331
+ verifyMcpAccessToken(token: string, expectedAudience: string): Promise<McpAccessTokenPayload | null>;
332
+ }
110
333
  /**
111
- * Has this server been given a JWT secret?
334
+ * Build a {@link JwtService} from a configuration, refusing one it would sign
335
+ * badly with: a short or well-known secret, an `activeKid` no key carries, a
336
+ * lifetime that is not one.
337
+ *
338
+ * Unset lifetimes take the defaults — an hour for access tokens,
339
+ * {@link DEFAULT_REFRESH_EXPIRES_IN} for refresh tokens.
112
340
  *
113
- * False on every backend that authenticates through an adapter — Firebase,
114
- * Clerk, anything with its own tokens — because nothing calls
115
- * {@link configureJwt} there. Signing paths still throw when it is false, since
116
- * asking for a token from a server that cannot mint one is a mistake worth
117
- * hearing about. Paths whose contract is *"tolerate the absence of auth"* must
118
- * ask first: `optionalAuth` crashing a request because this backend does not do
119
- * JWT is a 500 on a route that had already decided anonymous was acceptable.
341
+ * @example
342
+ * ```ts
343
+ * const jwt = createJwtService({ secret: process.env.JWT_SECRET! });
344
+ * const token = await jwt.generateAccessToken("u1", ["editor"]);
345
+ * const payload = await jwt.verifyAccessToken(token); // { uid: "u1", roles: ["editor"], … }
346
+ * ```
120
347
  */
121
- export declare function isJwtConfigured(): boolean;
348
+ export declare function createJwtService(config: JwtConfig): JwtService;
122
349
  /**
123
- * Generate an access token (short-lived, 1 hour by default)
350
+ * Configure the process default's JWT settings — what `verifyAccessToken`,
351
+ * `generateAccessToken` and the other module-level functions sign and verify
352
+ * with.
353
+ *
354
+ * Validates the secret strength to prevent deployment with default/weak
355
+ * secrets. A lifetime left unset keeps the one already configured; a
356
+ * configuration that fails validation leaves the previous one standing rather
357
+ * than half-applying a new one.
358
+ */
359
+ export declare function configureJwt(config: JwtConfig): void;
360
+ /**
361
+ * @internal The process default itself, to install another or to restore it.
362
+ * `setDefaultBackend` and tests use these; an application calls
363
+ * {@link configureJwt} or `setDefaultBackend`.
124
364
  */
125
- export declare function generateAccessToken(uid: string, roles: string[], aal?: "aal1" | "aal2", customClaims?: Record<string, unknown>,
365
+ export declare function defaultJwtService(): JwtService;
366
+ /** @internal See {@link defaultJwtService}. */
367
+ export declare function setDefaultJwtService(service: JwtService): void;
126
368
  /**
127
- * Whether this session is a guest — anonymous sign-in rather than an
128
- * account. Written into the token so the RLS identity and the WebSocket
129
- * path can tell the two apart without a database lookup.
369
+ * The JWT service serving this request: the backend's whose route group is
370
+ * answering it, or the process default for a route mounted outside any
371
+ * backend.
130
372
  */
131
- isAnonymous?: boolean): Promise<string>;
373
+ export declare function jwtOf(c: Context<HonoEnv>): JwtService;
374
+ /** See {@link JwtService.getJwks}. Answers for the process default. */
375
+ export declare function getJwks(): {
376
+ keys: PublicJwk[];
377
+ };
132
378
  /**
133
- * Get the expiration time of an access token in milliseconds from now
379
+ * The secret {@link configureJwt} was given, or undefined before it is called.
380
+ * Answers for the process default — see {@link JwtService.hmacSecret}.
134
381
  */
382
+ export declare function configuredJwtSecret(): string | undefined;
383
+ /** See {@link JwtService.hasAsymmetricSigningKey}. Answers for the process default. */
384
+ export declare function hasAsymmetricSigningKey(): boolean;
385
+ /** See {@link JwtService.isConfigured}. Answers for the process default. */
386
+ export declare function isJwtConfigured(): boolean;
387
+ /** See {@link JwtService.generateAccessToken}. Answers for the process default. */
388
+ export declare function generateAccessToken(uid: string, roles: string[], aal?: "aal1" | "aal2", customClaims?: Record<string, unknown>, isAnonymous?: boolean, sessionId?: string): Promise<string>;
389
+ /** See {@link JwtService.getAccessTokenExpiryMs}. Answers for the process default. */
135
390
  export declare function getAccessTokenExpiryMs(): number;
136
391
  /**
137
392
  * A lifetime setting in milliseconds, or null when it is not one.
@@ -145,27 +400,13 @@ export declare function getAccessTokenExpiryMs(): number;
145
400
  * (ms reads "3600" as 3.6 seconds) and a lifetime of zero or less.
146
401
  */
147
402
  export declare function parseDurationMs(value: string): number | null;
148
- /**
149
- * Get the expiration timestamp for an access token
150
- */
403
+ /** See {@link JwtService.getAccessTokenExpiry}. Answers for the process default. */
151
404
  export declare function getAccessTokenExpiry(): number;
152
- /**
153
- * Verify and decode an access token.
154
- *
155
- * Every token this server issues is signed with the same secret, so what a
156
- * token *is* comes from its claims, not from its signature. A download token
157
- * ({@link generateDownloadToken}) is therefore a validly-signed string that
158
- * must never authenticate anybody: it is scoped to one file path and handed out
159
- * in URLs, which is a far weaker thing to hold than a session.
160
- *
161
- * Today it is rejected below for want of an id — but only by luck, since
162
- * nothing stops a future download token from carrying one. So the purpose is
163
- * checked explicitly: a token minted for reading a file is not a token for
164
- * being a user.
165
- */
405
+ /** See {@link JwtService.verifyAccessToken}. Answers for the process default. */
166
406
  export declare function verifyAccessToken(token: string): Promise<AccessTokenPayload | null>;
167
407
  /**
168
- * Generate a random refresh token (long-lived, 30 days by default)
408
+ * Generate a random refresh token. Long-lived: 30 days by default, sliding —
409
+ * see {@link JwtService.getRefreshTokenTtlMs}.
169
410
  */
170
411
  export declare function generateRefreshToken(): string;
171
412
  /**
@@ -179,49 +420,24 @@ export declare function hashRefreshToken(token: string): Promise<string>;
179
420
  * what is actually enforced, which is worse than knowing the ceiling.
180
421
  */
181
422
  export declare const MAX_COOKIE_AGE_MS: number;
182
- /**
183
- * How long a refresh token is valid for, in milliseconds.
184
- *
185
- * Every rotation issues a token with a fresh TTL, so this is a sliding window:
186
- * a user who visits at all keeps their session indefinitely, and one who
187
- * disappears loses it this long after their last visit. That is what both
188
- * Firebase and Supabase do by default, and it is the behaviour people mean
189
- * when they say they expect to still be signed in.
190
- */
423
+ /** See {@link JwtService.getRefreshTokenTtlMs}. Answers for the process default. */
191
424
  export declare function getRefreshTokenTtlMs(): number;
192
- /**
193
- * Calculate refresh token expiration date
194
- */
425
+ /** See {@link JwtService.getRefreshTokenExpiry}. Answers for the process default. */
195
426
  export declare function getRefreshTokenExpiry(): Date;
196
427
  /**
197
428
  * The `purpose` claim carried by a credential that stands between "first factor
198
429
  * accepted" and "session issued".
199
430
  *
200
431
  * A pre-auth token is NOT a session and must never be usable as one:
201
- * {@link verifyAccessToken} refuses any token carrying a `purpose`, so this
202
- * value cannot authenticate a request no matter which route it is presented to.
203
- * The only thing that reads it is the MFA challenge pair, which exchanges it —
204
- * plus a second factor — for a real session.
432
+ * {@link JwtService.verifyAccessToken} refuses any token carrying a `purpose`,
433
+ * so this value cannot authenticate a request no matter which route it is
434
+ * presented to. The only thing that reads it is the MFA challenge pair, which
435
+ * exchanges it — plus a second factor — for a real session.
205
436
  */
206
437
  export declare const MFA_PENDING_PURPOSE = "mfa-pending";
207
- /**
208
- * Mint the short-lived credential handed back with an `MFA_REQUIRED` response.
209
- *
210
- * Short-lived on purpose: it is the window in which a caller who has proven the
211
- * first factor may present the second, not a session to be carried around. Five
212
- * minutes matches the challenge TTL.
213
- */
438
+ /** See {@link JwtService.generateMfaPendingToken}. Answers for the process default. */
214
439
  export declare function generateMfaPendingToken(uid: string, expiresInSeconds?: number): Promise<string>;
215
- /**
216
- * Verify a pre-auth token and return the user it was minted for.
217
- *
218
- * Returns `null` for anything else — including a perfectly valid *access*
219
- * token, which must not be interchangeable with this one in either direction.
220
- *
221
- * `iat` comes back with the uid because this token is a first factor that was
222
- * accepted at that instant, and a sign-out everywhere after it has to void it
223
- * the way it voids an access token — see `isAccessTokenRevoked`.
224
- */
440
+ /** See {@link JwtService.verifyMfaPendingToken}. Answers for the process default. */
225
441
  export declare function verifyMfaPendingToken(token: string): Promise<{
226
442
  uid: string;
227
443
  iat?: number;
@@ -232,57 +448,27 @@ export interface DownloadTokenPayload {
232
448
  /**
233
449
  * The storage source the grant is good for, canonicalized by
234
450
  * {@link canonicalStorageId}. Always present on a decoded payload; see
235
- * {@link verifyDownloadToken} for how tokens minted before this claim
236
- * existed are read.
451
+ * {@link JwtService.verifyDownloadToken} for how tokens minted before this
452
+ * claim existed are read.
237
453
  */
238
454
  storageId: string;
455
+ /**
456
+ * An opaque mark of the user who minted the token, for rate limiting only:
457
+ * a read that spends the token is charged to that user's allowance rather
458
+ * than to the reader's address. A hash, because the token travels in a URL.
459
+ * Absent for a token minted for nobody.
460
+ */
461
+ rl?: string;
239
462
  }
240
- /**
241
- * Generate a short-lived download token scoped to a specific file path or prefix
242
- * *within one storage source*.
243
- *
244
- * Both halves of that scope are load-bearing. A key is only unique inside its
245
- * own bucket, and a project with more than one source routinely holds the same
246
- * key in several of them — `avatars/u1.png` in `(default)` and in `media` are
247
- * different objects, quite possibly with different owners. A token that names
248
- * only the path is therefore a grant on every source at once: authorize a read
249
- * on the source whose `storageAuthorize` hook says yes, then spend the token
250
- * against `?storageId=` pointing somewhere else.
251
- *
252
- * `storageId` is optional here only because omitting it *is* the default
253
- * source, which is what the overwhelming majority of deployments have. A mint
254
- * site that forgets to pass a named source produces a default-scoped token,
255
- * which fails closed at `/file/*` rather than over-granting.
256
- */
257
- export declare function generateDownloadToken(path: string, expiresInSeconds?: number, storageId?: string | null): Promise<string>;
258
- /**
259
- * Verify and decode a download token.
260
- *
261
- * A token minted before `storageId` existed carries no such claim. It is read
262
- * as a grant on the **default source** rather than on all of them: that is the
263
- * fail-closed reading, and it is what such a token almost always was, since a
264
- * named source has to be asked for explicitly. The cost is bounded by the
265
- * five-minute TTL — for at most that long after a deploy, an in-flight token
266
- * for a *named* source is refused and the client re-fetches `/metadata`.
267
- */
463
+ /** See {@link JwtService.generateDownloadToken}. Answers for the process default. */
464
+ export declare function generateDownloadToken(path: string, expiresInSeconds?: number, storageId?: string | null,
465
+ /** The user minting it, so the reads it buys are charged to them. */
466
+ principal?: string | null): Promise<string>;
467
+ /** See {@link JwtService.verifyDownloadToken}. Answers for the process default. */
268
468
  export declare function verifyDownloadToken(token: string): Promise<DownloadTokenPayload | null>;
269
- /**
270
- * Sign a short-lived token that carries state across a redirect.
271
- *
272
- * The generalisation of the MFA-pending token: a signed blob the server hands
273
- * out and expects back, where the point is that the holder cannot edit it. The
274
- * OAuth authorize flow needs one to carry the authorization request across the
275
- * sign-in hop — without it, the endpoint the consent page posts to would mint a
276
- * code for whatever `client_id` and `redirect_uri` its caller typed, skipping
277
- * every check the authorize endpoint performs.
278
- *
279
- * The `purpose` is not decoration. {@link verifyAccessToken} refuses any token
280
- * that has one, so nothing minted here can be replayed as a session, and
281
- * {@link verifyPurposeToken} refuses a token whose purpose is not the one the
282
- * caller named — so a token minted for one hop cannot be spent on another.
283
- */
469
+ /** See {@link JwtService.signPurposeToken}. Answers for the process default. */
284
470
  export declare function signPurposeToken(purpose: string, claims: Record<string, unknown>, expiresInSeconds: number): Promise<string>;
285
- /** Verify a token minted by {@link signPurposeToken}, for one named purpose. */
471
+ /** See {@link JwtService.verifyPurposeToken}. Answers for the process default. */
286
472
  export declare function verifyPurposeToken<T>(purpose: string, token: string): Promise<T | null>;
287
473
  /** The `purpose` that marks a token as belonging to the MCP resource. */
288
474
  export declare const MCP_ACCESS_PURPOSE = "mcp-access";
@@ -299,37 +485,13 @@ export interface McpAccessTokenPayload {
299
485
  aud: string;
300
486
  iss: string;
301
487
  }
302
- /**
303
- * Mint an access token for the MCP endpoint.
304
- *
305
- * Deliberately **not** an ordinary session token, and the `purpose` claim is
306
- * what enforces that: {@link verifyAccessToken} refuses any token carrying one,
307
- * so a credential issued to a third-party MCP client — Claude, an IDE, anything
308
- * that completed the OAuth flow — cannot be replayed against `/api/data`,
309
- * `/api/admin` or the websocket. It buys exactly the one resource it names.
310
- *
311
- * That asymmetry matters more than it first looks. These tokens are handed to
312
- * software the user authorized but the operator never vetted, they live in that
313
- * software's storage, and they are the only credential in this system minted
314
- * for a third party. Without the purpose separation, "connect Claude to your
315
- * data" would silently mean "give Claude a full session".
316
- *
317
- * The audience is the canonical resource URI, and {@link verifyMcpAccessToken}
318
- * requires the caller to say which resource it is checking for. A token minted
319
- * for another Rebase project — or another path on this one — fails there.
320
- *
321
- * HS256 with the shared secret, like the download token: the authorization
322
- * server and the resource server are the same process, so nothing outside it
323
- * ever needs to verify one, and an asymmetric key here would be a second key
324
- * surface bought for nobody.
325
- */
488
+ /** See {@link JwtService.generateMcpAccessToken}. Answers for the process default. */
326
489
  export declare function generateMcpAccessToken(payload: Omit<McpAccessTokenPayload, "purpose">, expiresInSeconds: number): Promise<string>;
490
+ /** See {@link JwtService.verifyMcpAccessToken}. Answers for the process default. */
491
+ export declare function verifyMcpAccessToken(token: string, expectedAudience: string): Promise<McpAccessTokenPayload | null>;
327
492
  /**
328
- * Verify an MCP access token **for a specific resource**.
329
- *
330
- * `expectedAudience` has no default. The MCP specification requires a resource
331
- * server to validate that a token was issued for it specifically, and a default
332
- * would be the thing that quietly turns that check off — the caller has to say
333
- * what it is, every time, so a new call site cannot forget by omission.
493
+ * The process default as a service object that follows it — every call reads
494
+ * whatever {@link configureJwt} or `setDefaultBackend` installed last. What a
495
+ * route built outside any backend falls back to.
334
496
  */
335
- export declare function verifyMcpAccessToken(token: string, expectedAudience: string): Promise<McpAccessTokenPayload | null>;
497
+ export declare const processJwtService: JwtService;
@@ -1,8 +1,9 @@
1
1
  import { Hono } from "hono";
2
2
  import type { MiddlewareHandler } from "hono";
3
- import type { AuthModuleConfig } from "./routes.js";
3
+ import type { AuthModuleConfig, CreateSessionAndTokens } from "./routes.js";
4
4
  import type { ResolvedAuthHooks } from "./auth-hooks.js";
5
5
  import type { HonoEnv } from "../api/types.js";
6
+ import { type AuthLimiters } from "./rate-limiter.js";
6
7
  import { z } from "zod";
7
8
  import type { AuthResponsePayload, TransformAuthResponseContext } from "@rebasepro/types";
8
9
  /**
@@ -13,6 +14,8 @@ import type { AuthResponsePayload, TransformAuthResponseContext } from "@rebasep
13
14
  export declare function mountMagicLinkRoutes(deps: {
14
15
  router: Hono<HonoEnv>;
15
16
  config: AuthModuleConfig;
17
+ /** The backend's auth limiters. */
18
+ limiters: AuthLimiters;
16
19
  ops: ResolvedAuthHooks;
17
20
  parseBody: <T>(schema: z.ZodSchema<T>, body: unknown) => T;
18
21
  buildAuthResponse: (user: {
@@ -24,11 +27,7 @@ export declare function mountMagicLinkRoutes(deps: {
24
27
  isAnonymous?: boolean;
25
28
  metadata?: Record<string, unknown> | null;
26
29
  }, roleIds: string[], accessToken: string, refreshToken: string, providerId: string) => unknown;
27
- createSessionAndTokens: (uid: string, userAgent: string, ipAddress: string) => Promise<{
28
- roleIds: string[];
29
- accessToken: string;
30
- refreshToken: string;
31
- }>;
30
+ createSessionAndTokens: CreateSessionAndTokens;
32
31
  applyTransformHook: (response: AuthResponsePayload, method: TransformAuthResponseContext["method"], request: Request, uid: string) => Promise<AuthResponsePayload>;
33
32
  /**
34
33
  * Built by the caller so a misconfiguration fails the boot once, rather
@@ -36,13 +36,16 @@
36
36
  *
37
37
  * @module
38
38
  */
39
+ import { type JwtService } from "./jwt.js";
39
40
  /**
40
41
  * Encrypt a plaintext TOTP secret.
41
42
  *
42
43
  * @param plaintext - The Base32 TOTP secret to encrypt.
44
+ * @param jwt - The backend whose JWT secret is the last key fallback. The
45
+ * process default when omitted.
43
46
  * @returns A string in the format `v1.<keyId>:iv_hex:authTag_hex:ciphertext_hex`.
44
47
  */
45
- export declare function encryptTotpSecret(plaintext: string): string;
48
+ export declare function encryptTotpSecret(plaintext: string, jwt?: JwtService): string;
46
49
  /** What a factor's stored secret opened to, and whether it should be re-stored. */
47
50
  export interface OpenedTotpSecret {
48
51
  /** The Base32 TOTP secret. */
@@ -59,8 +62,10 @@ export interface OpenedTotpSecret {
59
62
  *
60
63
  * Accepts both the key-stamped format and the original unstamped
61
64
  * `iv:authTag:ciphertext`, which is tried against each candidate in turn.
65
+ * `jwt` is the backend whose JWT secret is the last key fallback — the process
66
+ * default when omitted.
62
67
  */
63
- export declare function openTotpSecret(ciphertext: string): OpenedTotpSecret;
68
+ export declare function openTotpSecret(ciphertext: string, jwt?: JwtService): OpenedTotpSecret;
64
69
  /**
65
70
  * Decrypt a previously encrypted TOTP secret.
66
71
  *
@@ -69,6 +74,7 @@ export declare function openTotpSecret(ciphertext: string): OpenedTotpSecret;
69
74
  * on whichever key it was written with.
70
75
  *
71
76
  * @param ciphertext - A stored TOTP secret, in either format.
77
+ * @param jwt - The backend whose JWT secret is the last key fallback.
72
78
  * @returns The original Base32 TOTP secret.
73
79
  */
74
- export declare function decryptTotpSecret(ciphertext: string): string;
80
+ export declare function decryptTotpSecret(ciphertext: string, jwt?: JwtService): string;
@@ -12,6 +12,7 @@
12
12
  *
13
13
  * @module
14
14
  */
15
+ import type { JwtService } from "./jwt.js";
15
16
  import type { AuthRepository } from "./interfaces.js";
16
17
  /** Error code a client watches for to switch a sign-in into its second step. */
17
18
  export declare const MFA_REQUIRED_CODE = "MFA_REQUIRED";
@@ -37,6 +38,7 @@ export interface MfaRequiredDetails {
37
38
  *
38
39
  * A 401 rather than a 200 with a different body: a client that has not been
39
40
  * taught about MFA must fail, not proceed. The credential in `details` is
40
- * useless for anything except the challenge routes.
41
+ * useless for anything except the challenge routes, and is signed by `jwt` —
42
+ * the backend's own key.
41
43
  */
42
- export declare function assertMfaSatisfied(authRepo: AuthRepository, uid: string): Promise<void>;
44
+ export declare function assertMfaSatisfied(authRepo: AuthRepository, uid: string, jwt: JwtService): Promise<void>;