@rebasepro/server 0.24.0 → 0.24.1-canary.gcb918fc

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 (224) hide show
  1. package/README.md +27 -2
  2. package/dist/GCSStorageController-fv6JAZ87.js +402 -0
  3. package/dist/GCSStorageController-fv6JAZ87.js.map +1 -0
  4. package/dist/S3StorageController-BNg-pXiY.js +480 -0
  5. package/dist/S3StorageController-BNg-pXiY.js.map +1 -0
  6. package/dist/api/mount-path.d.ts +30 -0
  7. package/dist/api/mount.d.ts +6 -13
  8. package/dist/api/rest/api-generator.d.ts +53 -1
  9. package/dist/api/rest/auth-collection-writes.d.ts +28 -21
  10. package/dist/api/rest/field-access-query.d.ts +28 -8
  11. package/dist/api/rest/field-ops.d.ts +19 -7
  12. package/dist/api/rest/query-body.d.ts +10 -0
  13. package/dist/api/rest/write-validation.d.ts +7 -5
  14. package/dist/api/schema-editor-routes.d.ts +10 -1
  15. package/dist/api/sql-export-routes.d.ts +8 -0
  16. package/dist/api/types.d.ts +35 -0
  17. package/dist/{ast-schema-editor-CWqS_sLJ.js → ast-schema-editor-mCeSC03x.js} +3 -3
  18. package/dist/{ast-schema-editor-CWqS_sLJ.js.map → ast-schema-editor-mCeSC03x.js.map} +1 -1
  19. package/dist/auth/access.d.ts +57 -8
  20. package/dist/auth/admin-user-ops.d.ts +24 -2
  21. package/dist/auth/admin-users-route.d.ts +1 -0
  22. package/dist/auth/api-keys/api-key-middleware.d.ts +10 -3
  23. package/dist/auth/api-keys/api-key-routes.d.ts +4 -1
  24. package/dist/auth/builtin-auth-adapter.d.ts +13 -0
  25. package/dist/auth/email-change-routes.d.ts +3 -0
  26. package/dist/auth/expired-token-sweep.d.ts +5 -1
  27. package/dist/auth/interfaces.d.ts +10 -0
  28. package/dist/auth/jwks-routes.d.ts +5 -1
  29. package/dist/auth/jwt-crypto.d.ts +7 -0
  30. package/dist/auth/jwt-keys.d.ts +4 -0
  31. package/dist/auth/jwt.d.ts +282 -166
  32. package/dist/auth/magic-link-routes.d.ts +3 -0
  33. package/dist/auth/mfa-crypto.d.ts +9 -3
  34. package/dist/auth/mfa-gate.d.ts +4 -2
  35. package/dist/auth/mfa-routes.d.ts +6 -0
  36. package/dist/auth/middleware.d.ts +9 -2
  37. package/dist/auth/otp-routes.d.ts +3 -0
  38. package/dist/auth/rate-limiter.d.ts +61 -34
  39. package/dist/auth/registration-policy.d.ts +17 -0
  40. package/dist/auth/require-auth.d.ts +1 -1
  41. package/dist/auth/routes.d.ts +16 -0
  42. package/dist/auth/session-routes.d.ts +6 -0
  43. package/dist/auth/user-picking.d.ts +37 -0
  44. package/dist/auth/verify-credential.d.ts +25 -4
  45. package/dist/{auth-DMLngxn_.js → auth-GnONzteu.js} +2869 -1871
  46. package/dist/auth-GnONzteu.js.map +1 -0
  47. package/dist/auth_adapter-CIItCTc8.js +21 -0
  48. package/dist/auth_adapter-CIItCTc8.js.map +1 -0
  49. package/dist/backend/create-backend.d.ts +281 -0
  50. package/dist/backend/default-backend.d.ts +35 -0
  51. package/dist/backend/options.d.ts +912 -0
  52. package/dist/backend/scope.d.ts +23 -0
  53. package/dist/backend/services.d.ts +54 -0
  54. package/dist/backend-DTAOsLQc.js.map +1 -1
  55. package/dist/backup/backup-common.d.ts +14 -3
  56. package/dist/backup/backup-routes.d.ts +23 -2
  57. package/dist/backup/backup-storage.d.ts +3 -1
  58. package/dist/backup/index.d.ts +3 -1
  59. package/dist/{backup-CN0s50D2.js → backup-BnvkSLHi.js} +176 -35
  60. package/dist/backup-BnvkSLHi.js.map +1 -0
  61. package/dist/boot/boot.d.ts +2 -2
  62. package/dist/boot/driver.d.ts +3 -0
  63. package/dist/boot/env.d.ts +9 -2
  64. package/dist/boot/http-server.d.ts +22 -0
  65. package/dist/boot/options.d.ts +16 -1
  66. package/dist/boot/provision.d.ts +4 -2
  67. package/dist/boot/runtime-cors.d.ts +17 -0
  68. package/dist/boot/sources.d.ts +2 -0
  69. package/dist/boot/static-routing.d.ts +9 -0
  70. package/dist/{contract-routes-fz8i4pxs.js → contract-routes-Ey6ftnKH.js} +4 -20
  71. package/dist/contract-routes-Ey6ftnKH.js.map +1 -0
  72. package/dist/cron/cron-loader.d.ts +77 -18
  73. package/dist/cron/cron-routes.d.ts +1 -1
  74. package/dist/cron/cron-scheduler.d.ts +69 -3
  75. package/dist/cron/cron-store.d.ts +33 -5
  76. package/dist/cron/define-cron.d.ts +6 -2
  77. package/dist/cron/index.d.ts +3 -3
  78. package/dist/cron-loader-B-u0snqq.js +202 -0
  79. package/dist/cron-loader-B-u0snqq.js.map +1 -0
  80. package/dist/{cron-routes-Bc-SB0Se.js → cron-routes-OD6BstUj.js} +27 -4
  81. package/dist/cron-routes-OD6BstUj.js.map +1 -0
  82. package/dist/{cron-scheduler-CYQgco86.js → cron-scheduler-idtLPoN-.js} +299 -33
  83. package/dist/cron-scheduler-idtLPoN-.js.map +1 -0
  84. package/dist/cron-store-CZ30ZBi-.js +577 -0
  85. package/dist/cron-store-CZ30ZBi-.js.map +1 -0
  86. package/dist/email/smtp-email-service.d.ts +23 -0
  87. package/dist/email/types.d.ts +18 -0
  88. package/dist/env.d.ts +0 -37
  89. package/dist/filter-dialect-O1HK6Nvr.js +1628 -0
  90. package/dist/filter-dialect-O1HK6Nvr.js.map +1 -0
  91. package/dist/{function-loader-D7o5Epjj.js → function-loader-iKhOZatS.js} +68 -38
  92. package/dist/function-loader-iKhOZatS.js.map +1 -0
  93. package/dist/{function-routes-CaNG4waN.js → function-routes-j9TwpvQe.js} +5 -4
  94. package/dist/function-routes-j9TwpvQe.js.map +1 -0
  95. package/dist/functions/context.d.ts +9 -0
  96. package/dist/functions/define-function.d.ts +10 -6
  97. package/dist/functions/function-loader.d.ts +75 -18
  98. package/dist/functions/function-routes.d.ts +2 -1
  99. package/dist/functions/index.d.ts +5 -4
  100. package/dist/functions/index.js +42 -13
  101. package/dist/functions/index.js.map +1 -1
  102. package/dist/functions/internal.d.ts +2 -2
  103. package/dist/functions/proxy.d.ts +6 -2
  104. package/dist/functions/request-timeout.d.ts +7 -5
  105. package/dist/history/history-routes.d.ts +9 -0
  106. package/dist/history/retention-sweep.d.ts +81 -0
  107. package/dist/{history-recorder-Nr8zLvoU.js → history-recorder-BfWRwmPy.js} +3 -3
  108. package/dist/{history-recorder-Nr8zLvoU.js.map → history-recorder-BfWRwmPy.js.map} +1 -1
  109. package/dist/{history-store-rcAm_xFR.js → history-store-DPofGVDp.js} +2 -2
  110. package/dist/{history-store-rcAm_xFR.js.map → history-store-DPofGVDp.js.map} +1 -1
  111. package/dist/index.d.ts +23 -10
  112. package/dist/index.es.js +24423 -20038
  113. package/dist/index.es.js.map +1 -1
  114. package/dist/init/docs.d.ts +27 -10
  115. package/dist/init/process-safety.d.ts +7 -2
  116. package/dist/init/shutdown.d.ts +18 -3
  117. package/dist/init.d.ts +49 -865
  118. package/dist/internal-tables-L2t39RdT.js +136 -0
  119. package/dist/internal-tables-L2t39RdT.js.map +1 -0
  120. package/dist/jobs/job-queue.d.ts +8 -0
  121. package/dist/jobs/job-store.d.ts +24 -0
  122. package/dist/jobs/types.d.ts +25 -4
  123. package/dist/{jobs-DqYNfquG.js → jobs-BCbflZj2.js} +234 -24
  124. package/dist/jobs-BCbflZj2.js.map +1 -0
  125. package/dist/{jwt-R6bSPMjk.js → jwt-BlvuKoR6.js} +529 -454
  126. package/dist/jwt-BlvuKoR6.js.map +1 -0
  127. package/dist/{keys-GAVZqbqx.js → keys-COzQ2aE8.js} +2 -2
  128. package/dist/{keys-GAVZqbqx.js.map → keys-COzQ2aE8.js.map} +1 -1
  129. package/dist/load-failure-L5hvfDoG.js +80 -0
  130. package/dist/load-failure-L5hvfDoG.js.map +1 -0
  131. package/dist/mcp/mcp-routes.d.ts +6 -0
  132. package/dist/mcp/mcp-tools.d.ts +8 -0
  133. package/dist/mcp/oauth-routes.d.ts +7 -0
  134. package/dist/metrics/index.d.ts +18 -0
  135. package/dist/metrics/pool-wait.d.ts +50 -0
  136. package/dist/offline-QNQgsPOq-B2yGeXkn.js +3305 -0
  137. package/dist/offline-QNQgsPOq-B2yGeXkn.js.map +1 -0
  138. package/dist/offline-store-Cm5sAX81-CALiO4Gn.js +1915 -0
  139. package/dist/offline-store-Cm5sAX81-CALiO4Gn.js.map +1 -0
  140. package/dist/{openapi-generator-DAq_XVDu.js → openapi-generator-D9zUQmEp.js} +366 -82
  141. package/dist/openapi-generator-D9zUQmEp.js.map +1 -0
  142. package/dist/policy-PdzX-Opd.js +121 -0
  143. package/dist/policy-PdzX-Opd.js.map +1 -0
  144. package/dist/project_manifest-R6y_KHms.js +59 -0
  145. package/dist/project_manifest-R6y_KHms.js.map +1 -0
  146. package/dist/{proxy-qRlqeUmO.js → proxy-CkTlMGmh.js} +4 -3
  147. package/dist/proxy-CkTlMGmh.js.map +1 -0
  148. package/dist/{query-parser-BgiKJKvc.js → query-parser-4WkMoA_K.js} +510 -15
  149. package/dist/query-parser-4WkMoA_K.js.map +1 -0
  150. package/dist/{request-timeout-DgH7j8qO.js → request-timeout-Dnl2_OBc.js} +15 -8
  151. package/dist/request-timeout-Dnl2_OBc.js.map +1 -0
  152. package/dist/resumable-upload-threshold-CKv-Ry0l.js +24 -0
  153. package/dist/resumable-upload-threshold-CKv-Ry0l.js.map +1 -0
  154. package/dist/schema-edit/apply-schema-change.d.ts +10 -0
  155. package/dist/schema-edit/local-source.d.ts +29 -0
  156. package/dist/schema-edit/remote-source.d.ts +13 -3
  157. package/dist/schema-edit/source-editor.d.ts +28 -0
  158. package/dist/{schema-editor-routes-oIyuWl3L.js → schema-editor-routes-C11Tumyd.js} +54 -10
  159. package/dist/schema-editor-routes-C11Tumyd.js.map +1 -0
  160. package/dist/services/outbound-post.d.ts +50 -0
  161. package/dist/services/outbound-url-guard.d.ts +34 -5
  162. package/dist/services/routed-realtime-service.d.ts +5 -0
  163. package/dist/services/webhook-service.d.ts +66 -14
  164. package/dist/singleton.d.ts +9 -5
  165. package/dist/soft-delete-params-DfV3vVN5.js +668 -0
  166. package/dist/soft-delete-params-DfV3vVN5.js.map +1 -0
  167. package/dist/sql-export-routes-ClRwzIsC.js +240 -0
  168. package/dist/sql-export-routes-ClRwzIsC.js.map +1 -0
  169. package/dist/{src-CatHFUym.js → src-D5Y3N-S4.js} +2 -1
  170. package/dist/{src-CatHFUym.js.map → src-D5Y3N-S4.js.map} +1 -1
  171. package/dist/storage/GCSStorageController.d.ts +46 -2
  172. package/dist/storage/LocalStorageController.d.ts +67 -2
  173. package/dist/storage/S3StorageController.d.ts +37 -3
  174. package/dist/storage/image-transform.d.ts +5 -0
  175. package/dist/storage/maintenance-routes.d.ts +23 -0
  176. package/dist/storage/maintenance.d.ts +126 -0
  177. package/dist/storage/rendition-cache.d.ts +9 -11
  178. package/dist/storage/request-principals.d.ts +30 -0
  179. package/dist/storage/routes.d.ts +20 -0
  180. package/dist/storage/source-variables.d.ts +10 -0
  181. package/dist/storage/streams.d.ts +42 -0
  182. package/dist/storage/tus-handler.d.ts +46 -2
  183. package/dist/storage/types.d.ts +82 -7
  184. package/dist/storage/upload-validation.d.ts +13 -0
  185. package/dist/storage-resumable-VO-cMpse-C_YX71pO.js +125 -0
  186. package/dist/storage-resumable-VO-cMpse-C_YX71pO.js.map +1 -0
  187. package/dist/strings.es-BeZWAodn.js +256 -0
  188. package/dist/strings.es-BeZWAodn.js.map +1 -0
  189. package/dist/upload-validation-Dd-fnsbA.js +172 -0
  190. package/dist/upload-validation-Dd-fnsbA.js.map +1 -0
  191. package/dist/utils/byte-size.d.ts +10 -0
  192. package/dist/utils/compression.d.ts +6 -0
  193. package/dist/utils/load-failure.d.ts +14 -0
  194. package/package.json +5 -5
  195. package/dist/GCSStorageController-BSiP1c-f.js +0 -256
  196. package/dist/GCSStorageController-BSiP1c-f.js.map +0 -1
  197. package/dist/S3StorageController-CAwFRgjV.js +0 -276
  198. package/dist/S3StorageController-CAwFRgjV.js.map +0 -1
  199. package/dist/auth-DMLngxn_.js.map +0 -1
  200. package/dist/backup-CN0s50D2.js.map +0 -1
  201. package/dist/contract-routes-fz8i4pxs.js.map +0 -1
  202. package/dist/cron-loader-CwaANlOG.js +0 -118
  203. package/dist/cron-loader-CwaANlOG.js.map +0 -1
  204. package/dist/cron-routes-Bc-SB0Se.js.map +0 -1
  205. package/dist/cron-scheduler-CYQgco86.js.map +0 -1
  206. package/dist/cron-store-D2Q9-Aco.js +0 -300
  207. package/dist/cron-store-D2Q9-Aco.js.map +0 -1
  208. package/dist/dynamic-import-X40pTZUQ.js +0 -23
  209. package/dist/dynamic-import-X40pTZUQ.js.map +0 -1
  210. package/dist/function-loader-D7o5Epjj.js.map +0 -1
  211. package/dist/function-routes-CaNG4waN.js.map +0 -1
  212. package/dist/jobs-DqYNfquG.js.map +0 -1
  213. package/dist/jwt-R6bSPMjk.js.map +0 -1
  214. package/dist/openapi-generator-DAq_XVDu.js.map +0 -1
  215. package/dist/proxy-qRlqeUmO.js.map +0 -1
  216. package/dist/query-parser-BgiKJKvc.js.map +0 -1
  217. package/dist/request-timeout-DgH7j8qO.js.map +0 -1
  218. package/dist/schema-editor-routes-oIyuWl3L.js.map +0 -1
  219. package/dist/soft-delete-params-BWPilMPF.js +0 -59
  220. package/dist/soft-delete-params-BWPilMPF.js.map +0 -1
  221. package/dist/src-I3aG1PcY.js +0 -6870
  222. package/dist/src-I3aG1PcY.js.map +0 -1
  223. package/dist/types-BfKcm9do.js +0 -39
  224. package/dist/types-BfKcm9do.js.map +0 -1
@@ -10,6 +10,9 @@
10
10
  * present the same functionality through the pluggable `AuthAdapter` contract.
11
11
  */
12
12
  import type { AuthAdapter } from "@rebasepro/types";
13
+ import { type JwtService } from "./jwt.js";
14
+ import type { AuthLimiters } from "./rate-limiter.js";
15
+ import type { AccessControl } from "./access.js";
13
16
  import type { CaptchaConfig } from "./captcha.js";
14
17
  import type { AuthRepository, OAuthProvider } from "./interfaces.js";
15
18
  import type { AuthHooks } from "./auth-hooks.js";
@@ -23,6 +26,16 @@ import type { EmailService, EmailConfig } from "../email/index.js";
23
26
  export interface BuiltinAuthAdapterConfig {
24
27
  /** The bootstrapper-provided auth repository (users, roles, tokens). */
25
28
  authRepository: AuthRepository;
29
+ /**
30
+ * The backend this adapter signs and verifies tokens for —
31
+ * `backend.services.jwt`, or a service of your own from `createJwtService`.
32
+ * The process default (what `configureJwt` sets) when omitted.
33
+ */
34
+ jwt?: JwtService;
35
+ /** The backend's auth limiters, counting in its own store. The process default's set when omitted. */
36
+ limiters?: AuthLimiters;
37
+ /** The backend's access model, which the default role is checked against. The process default when omitted. */
38
+ access?: AccessControl;
26
39
  /** Email service for password resets, verification, etc. */
27
40
  emailService?: EmailService;
28
41
  /** Email configuration. */
@@ -26,6 +26,7 @@ import { z } from "zod";
26
26
  import type { HonoEnv } from "../api/types.js";
27
27
  import type { MiddlewareHandler } from "hono";
28
28
  import type { resolveAuthHooks } from "./auth-hooks.js";
29
+ import type { AuthLimiters } from "./rate-limiter.js";
29
30
  import type { AuthModuleConfig } from "./routes.js";
30
31
  /** How long an address-change link stays usable. */
31
32
  export declare const EMAIL_CHANGE_TTL_MS: number;
@@ -36,6 +37,8 @@ interface EmailChangeRoutesConfig {
36
37
  parseBody: <T>(schema: z.ZodSchema<T>, body: unknown) => T;
37
38
  /** A signed-in user, with the revocation watermark consulted. */
38
39
  requireLiveSession: MiddlewareHandler<HonoEnv>;
40
+ /** The backend's auth limiters. */
41
+ limiters: AuthLimiters;
39
42
  }
40
43
  export declare function mountEmailChangeRoutes(opts: EmailChangeRoutesConfig): void;
41
44
  export {};
@@ -40,7 +40,11 @@ export type ExpiredTokenSweepOutcome = "swept" | "claimed-elsewhere" | "unclaime
40
40
  export interface ExpiredTokenSweep {
41
41
  /** Sweep now, then once per interval. */
42
42
  start(): void;
43
- stop(): void;
43
+ /**
44
+ * No more ticks. Resolves once a tick already running has finished, so a
45
+ * caller about to close the pool can wait for the tick still using it.
46
+ */
47
+ stop(): Promise<void>;
44
48
  /** One tick: claim this interval's slot and, if it is ours, sweep. */
45
49
  runSlot(): Promise<ExpiredTokenSweepOutcome>;
46
50
  }
@@ -324,6 +324,16 @@ export interface UserRepository {
324
324
  * List users with server-side pagination, search, and sorting.
325
325
  */
326
326
  listUsersPaginated(options?: ListUsersOptions): Promise<PaginatedUsersResult>;
327
+ /**
328
+ * The ids of at most `limit` users, in no particular order. Answers "is
329
+ * there any user?" (`limit` 1) and "is this the only one?" (`limit` 2).
330
+ *
331
+ * `listUsersPaginated` answered those by counting the whole table and
332
+ * sorting it, on every anonymous `GET /auth/config` and every sign-up.
333
+ * Optional: a repository without it is asked through `listUsersPaginated`
334
+ * instead (`isUserTableEmpty` / `isOnlyUser` in `registration-policy.ts`).
335
+ */
336
+ firstUserIds?(limit: number): Promise<string[]>;
327
337
  /**
328
338
  * Update user's password hash. `null` removes the password: the account
329
339
  * then signs in only by link, code or provider.
@@ -1,5 +1,6 @@
1
1
  import { Hono } from "hono";
2
2
  import type { HonoEnv } from "../api/types.js";
3
+ import { type JwtService } from "./jwt.js";
3
4
  /**
4
5
  * `GET /.well-known/jwks.json` — the public keys that verify this issuer's
5
6
  * access tokens.
@@ -13,5 +14,8 @@ import type { HonoEnv } from "../api/types.js";
13
14
  * where every verifier looks — an issuer of `https://api.example.com` implies
14
15
  * `https://api.example.com/.well-known/jwks.json`, whatever the API happens to
15
16
  * be prefixed with.
17
+ *
18
+ * `jwt` is the issuer whose keys these are — a backend's own
19
+ * (`backend.services.jwt`), or the process default when omitted.
16
20
  */
17
- export declare function createJwksRoutes(): Hono<HonoEnv>;
21
+ export declare function createJwksRoutes(jwt?: JwtService): Hono<HonoEnv>;
@@ -74,6 +74,13 @@ export declare function signJwt(payload: JwtClaims, key: JwtSigningKey, options:
74
74
  export declare function verifyJwt(token: string, key: JwtVerificationKey, options: {
75
75
  algorithms: string[];
76
76
  }): Promise<JwtClaims>;
77
+ /**
78
+ * Whether a {@link verifyJwt} rejection says only that the token's `exp` has
79
+ * passed — the routine refusal that sends a client to refresh — rather than
80
+ * that the token is not one we signed. Here because the library decides how
81
+ * that is spelled.
82
+ */
83
+ export declare function isExpiredJwtError(error: unknown): boolean;
77
84
  /**
78
85
  * The token's unverified header — `kid` and `alg` — or an empty object.
79
86
  *
@@ -106,3 +106,7 @@ export declare function normalizePemFromEnv(value: string): string;
106
106
  export declare function toJwks(keys: ResolvedJwtKey[]): {
107
107
  keys: PublicJwk[];
108
108
  };
109
+ /** A verification key, as `jsonwebtoken.verify` would import it, once per string. */
110
+ export declare function importedVerificationKey<K>(key: K): K | KeyObject;
111
+ /** A signing key, as `jsonwebtoken.sign` would import it, once per string. */
112
+ export declare function importedSigningKey<K>(key: K): K | KeyObject;
@@ -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;
@@ -115,59 +117,276 @@ export interface AccessTokenPayload {
115
117
  */
116
118
  export declare function customClaimsOf(decoded: Record<string, unknown>): Record<string, unknown> | undefined;
117
119
  /**
118
- * Configure JWT settings - call this during initialization.
119
- * Validates the secret strength to prevent deployment with default/weak secrets.
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.
120
122
  */
121
- export declare function configureJwt(config: JwtConfig): void;
123
+ export declare const DEFAULT_REFRESH_EXPIRES_IN = "30d";
122
124
  /**
123
- * The public keys, in JWKS form, for `/.well-known/jwks.json`.
125
+ * One backend's tokens: what it signs with, what it verifies against, and how
126
+ * long what it mints lives.
124
127
  *
125
- * An empty `keys` array on a backend with no asymmetric keys configured is the
126
- * correct answer rather than a 404: it says "this issuer publishes none",
127
- * which a verifier can act on, where a 404 is indistinguishable from a
128
- * misconfigured URL.
129
- */
130
- export declare function getJwks(): {
131
- keys: PublicJwk[];
132
- };
133
- /**
134
- * The secret `configureJwt` was given, or undefined before it is called. For
135
- * `mfa-crypto.ts`, which falls back to it when no MFA key is set — the secret
136
- * passed in code, not only the one in `JWT_SECRET`.
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.
137
136
  */
138
- export declare function configuredJwtSecret(): string | undefined;
139
- /** Is this backend signing access tokens asymmetrically? */
140
- 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
+ }
141
333
  /**
142
- * 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.
143
337
  *
144
- * False on every backend that authenticates through an adapter — Firebase,
145
- * Clerk, anything with its own tokens — because nothing calls
146
- * {@link configureJwt} there. Signing paths still throw when it is false, since
147
- * asking for a token from a server that cannot mint one is a mistake worth
148
- * hearing about. Paths whose contract is *"tolerate the absence of auth"* must
149
- * ask first: `optionalAuth` crashing a request because this backend does not do
150
- * JWT is a 500 on a route that had already decided anonymous was acceptable.
338
+ * Unset lifetimes take the defaults — an hour for access tokens,
339
+ * {@link DEFAULT_REFRESH_EXPIRES_IN} for refresh tokens.
340
+ *
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
+ * ```
151
347
  */
152
- export declare function isJwtConfigured(): boolean;
348
+ export declare function createJwtService(config: JwtConfig): JwtService;
153
349
  /**
154
- * 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.
155
358
  */
156
- export declare function generateAccessToken(uid: string, roles: string[], aal?: "aal1" | "aal2", customClaims?: Record<string, unknown>,
359
+ export declare function configureJwt(config: JwtConfig): void;
157
360
  /**
158
- * Whether this session is a guest — anonymous sign-in rather than an
159
- * account. Written into the token so the RLS identity and the WebSocket
160
- * path can tell the two apart without a database lookup.
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`.
161
364
  */
162
- isAnonymous?: boolean,
365
+ export declare function defaultJwtService(): JwtService;
366
+ /** @internal See {@link defaultJwtService}. */
367
+ export declare function setDefaultJwtService(service: JwtService): void;
163
368
  /**
164
- * The sign-in this token belongs to — see {@link AccessTokenPayload.sid}.
165
- * Every token the auth routes mint carries one.
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.
166
372
  */
167
- sessionId?: string): 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
+ };
168
378
  /**
169
- * 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}.
170
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. */
171
390
  export declare function getAccessTokenExpiryMs(): number;
172
391
  /**
173
392
  * A lifetime setting in milliseconds, or null when it is not one.
@@ -181,28 +400,13 @@ export declare function getAccessTokenExpiryMs(): number;
181
400
  * (ms reads "3600" as 3.6 seconds) and a lifetime of zero or less.
182
401
  */
183
402
  export declare function parseDurationMs(value: string): number | null;
184
- /**
185
- * Get the expiration timestamp for an access token
186
- */
403
+ /** See {@link JwtService.getAccessTokenExpiry}. Answers for the process default. */
187
404
  export declare function getAccessTokenExpiry(): number;
188
- /**
189
- * Verify and decode an access token.
190
- *
191
- * Every token this server issues is signed with the same secret, so what a
192
- * token *is* comes from its claims, not from its signature. A download token
193
- * ({@link generateDownloadToken}) is therefore a validly-signed string that
194
- * must never authenticate anybody: it is scoped to one file path and handed out
195
- * in URLs, which is a far weaker thing to hold than a session.
196
- *
197
- * Today it is rejected below for want of an id — but only by luck, since
198
- * nothing stops a future download token from carrying one. So the purpose is
199
- * checked explicitly: a token minted for reading a file is not a token for
200
- * being a user.
201
- */
405
+ /** See {@link JwtService.verifyAccessToken}. Answers for the process default. */
202
406
  export declare function verifyAccessToken(token: string): Promise<AccessTokenPayload | null>;
203
407
  /**
204
- * Generate a random refresh token. Long-lived: 400 days by default, sliding —
205
- * see {@link getRefreshTokenTtlMs}.
408
+ * Generate a random refresh token. Long-lived: 30 days by default, sliding —
409
+ * see {@link JwtService.getRefreshTokenTtlMs}.
206
410
  */
207
411
  export declare function generateRefreshToken(): string;
208
412
  /**
@@ -216,49 +420,24 @@ export declare function hashRefreshToken(token: string): Promise<string>;
216
420
  * what is actually enforced, which is worse than knowing the ceiling.
217
421
  */
218
422
  export declare const MAX_COOKIE_AGE_MS: number;
219
- /**
220
- * How long a refresh token is valid for, in milliseconds.
221
- *
222
- * Every rotation issues a token with a fresh TTL, so this is a sliding window:
223
- * a user who visits at all keeps their session indefinitely, and one who
224
- * disappears loses it this long after their last visit. That is what both
225
- * Firebase and Supabase do by default, and it is the behaviour people mean
226
- * when they say they expect to still be signed in.
227
- */
423
+ /** See {@link JwtService.getRefreshTokenTtlMs}. Answers for the process default. */
228
424
  export declare function getRefreshTokenTtlMs(): number;
229
- /**
230
- * Calculate refresh token expiration date
231
- */
425
+ /** See {@link JwtService.getRefreshTokenExpiry}. Answers for the process default. */
232
426
  export declare function getRefreshTokenExpiry(): Date;
233
427
  /**
234
428
  * The `purpose` claim carried by a credential that stands between "first factor
235
429
  * accepted" and "session issued".
236
430
  *
237
431
  * A pre-auth token is NOT a session and must never be usable as one:
238
- * {@link verifyAccessToken} refuses any token carrying a `purpose`, so this
239
- * value cannot authenticate a request no matter which route it is presented to.
240
- * The only thing that reads it is the MFA challenge pair, which exchanges it —
241
- * 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.
242
436
  */
243
437
  export declare const MFA_PENDING_PURPOSE = "mfa-pending";
244
- /**
245
- * Mint the short-lived credential handed back with an `MFA_REQUIRED` response.
246
- *
247
- * Short-lived on purpose: it is the window in which a caller who has proven the
248
- * first factor may present the second, not a session to be carried around. Five
249
- * minutes matches the challenge TTL.
250
- */
438
+ /** See {@link JwtService.generateMfaPendingToken}. Answers for the process default. */
251
439
  export declare function generateMfaPendingToken(uid: string, expiresInSeconds?: number): Promise<string>;
252
- /**
253
- * Verify a pre-auth token and return the user it was minted for.
254
- *
255
- * Returns `null` for anything else — including a perfectly valid *access*
256
- * token, which must not be interchangeable with this one in either direction.
257
- *
258
- * `iat` comes back with the uid because this token is a first factor that was
259
- * accepted at that instant, and a sign-out everywhere after it has to void it
260
- * the way it voids an access token — see `isAccessTokenRevoked`.
261
- */
440
+ /** See {@link JwtService.verifyMfaPendingToken}. Answers for the process default. */
262
441
  export declare function verifyMfaPendingToken(token: string): Promise<{
263
442
  uid: string;
264
443
  iat?: number;
@@ -269,8 +448,8 @@ export interface DownloadTokenPayload {
269
448
  /**
270
449
  * The storage source the grant is good for, canonicalized by
271
450
  * {@link canonicalStorageId}. Always present on a decoded payload; see
272
- * {@link verifyDownloadToken} for how tokens minted before this claim
273
- * existed are read.
451
+ * {@link JwtService.verifyDownloadToken} for how tokens minted before this
452
+ * claim existed are read.
274
453
  */
275
454
  storageId: string;
276
455
  /**
@@ -281,54 +460,15 @@ export interface DownloadTokenPayload {
281
460
  */
282
461
  rl?: string;
283
462
  }
284
- /**
285
- * Generate a short-lived download token scoped to a specific file path or prefix
286
- * *within one storage source*.
287
- *
288
- * Both halves of that scope are load-bearing. A key is only unique inside its
289
- * own bucket, and a project with more than one source routinely holds the same
290
- * key in several of them — `avatars/u1.png` in `(default)` and in `media` are
291
- * different objects, quite possibly with different owners. A token that names
292
- * only the path is therefore a grant on every source at once: authorize a read
293
- * on the source whose `storageAuthorize` hook says yes, then spend the token
294
- * against `?storageId=` pointing somewhere else.
295
- *
296
- * `storageId` is optional here only because omitting it *is* the default
297
- * source, which is what the overwhelming majority of deployments have. A mint
298
- * site that forgets to pass a named source produces a default-scoped token,
299
- * which fails closed at `/file/*` rather than over-granting.
300
- */
463
+ /** See {@link JwtService.generateDownloadToken}. Answers for the process default. */
301
464
  export declare function generateDownloadToken(path: string, expiresInSeconds?: number, storageId?: string | null,
302
465
  /** The user minting it, so the reads it buys are charged to them. */
303
466
  principal?: string | null): Promise<string>;
304
- /**
305
- * Verify and decode a download token.
306
- *
307
- * A token minted before `storageId` existed carries no such claim. It is read
308
- * as a grant on the **default source** rather than on all of them: that is the
309
- * fail-closed reading, and it is what such a token almost always was, since a
310
- * named source has to be asked for explicitly. The cost is bounded by the
311
- * five-minute TTL — for at most that long after a deploy, an in-flight token
312
- * for a *named* source is refused and the client re-fetches `/metadata`.
313
- */
467
+ /** See {@link JwtService.verifyDownloadToken}. Answers for the process default. */
314
468
  export declare function verifyDownloadToken(token: string): Promise<DownloadTokenPayload | null>;
315
- /**
316
- * Sign a short-lived token that carries state across a redirect.
317
- *
318
- * The generalisation of the MFA-pending token: a signed blob the server hands
319
- * out and expects back, where the point is that the holder cannot edit it. The
320
- * OAuth authorize flow needs one to carry the authorization request across the
321
- * sign-in hop — without it, the endpoint the consent page posts to would mint a
322
- * code for whatever `client_id` and `redirect_uri` its caller typed, skipping
323
- * every check the authorize endpoint performs.
324
- *
325
- * The `purpose` is not decoration. {@link verifyAccessToken} refuses any token
326
- * that has one, so nothing minted here can be replayed as a session, and
327
- * {@link verifyPurposeToken} refuses a token whose purpose is not the one the
328
- * caller named — so a token minted for one hop cannot be spent on another.
329
- */
469
+ /** See {@link JwtService.signPurposeToken}. Answers for the process default. */
330
470
  export declare function signPurposeToken(purpose: string, claims: Record<string, unknown>, expiresInSeconds: number): Promise<string>;
331
- /** Verify a token minted by {@link signPurposeToken}, for one named purpose. */
471
+ /** See {@link JwtService.verifyPurposeToken}. Answers for the process default. */
332
472
  export declare function verifyPurposeToken<T>(purpose: string, token: string): Promise<T | null>;
333
473
  /** The `purpose` that marks a token as belonging to the MCP resource. */
334
474
  export declare const MCP_ACCESS_PURPOSE = "mcp-access";
@@ -345,37 +485,13 @@ export interface McpAccessTokenPayload {
345
485
  aud: string;
346
486
  iss: string;
347
487
  }
348
- /**
349
- * Mint an access token for the MCP endpoint.
350
- *
351
- * Deliberately **not** an ordinary session token, and the `purpose` claim is
352
- * what enforces that: {@link verifyAccessToken} refuses any token carrying one,
353
- * so a credential issued to a third-party MCP client — Claude, an IDE, anything
354
- * that completed the OAuth flow — cannot be replayed against `/api/data`,
355
- * `/api/admin` or the websocket. It buys exactly the one resource it names.
356
- *
357
- * That asymmetry matters more than it first looks. These tokens are handed to
358
- * software the user authorized but the operator never vetted, they live in that
359
- * software's storage, and they are the only credential in this system minted
360
- * for a third party. Without the purpose separation, "connect Claude to your
361
- * data" would silently mean "give Claude a full session".
362
- *
363
- * The audience is the canonical resource URI, and {@link verifyMcpAccessToken}
364
- * requires the caller to say which resource it is checking for. A token minted
365
- * for another Rebase project — or another path on this one — fails there.
366
- *
367
- * HS256 with the shared secret, like the download token: the authorization
368
- * server and the resource server are the same process, so nothing outside it
369
- * ever needs to verify one, and an asymmetric key here would be a second key
370
- * surface bought for nobody.
371
- */
488
+ /** See {@link JwtService.generateMcpAccessToken}. Answers for the process default. */
372
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>;
373
492
  /**
374
- * Verify an MCP access token **for a specific resource**.
375
- *
376
- * `expectedAudience` has no default. The MCP specification requires a resource
377
- * server to validate that a token was issued for it specifically, and a default
378
- * would be the thing that quietly turns that check off — the caller has to say
379
- * 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.
380
496
  */
381
- export declare function verifyMcpAccessToken(token: string, expectedAudience: string): Promise<McpAccessTokenPayload | null>;
497
+ export declare const processJwtService: JwtService;