@udibo/oauth2 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (375) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +174 -0
  3. package/SECURITY.md +77 -0
  4. package/esm/_dnt.polyfills.d.ts +17 -0
  5. package/esm/_dnt.polyfills.js +15 -0
  6. package/esm/adapters/hono/_common.d.ts +66 -0
  7. package/esm/adapters/hono/_common.js +108 -0
  8. package/esm/adapters/hono/authorization-server.d.ts +211 -0
  9. package/esm/adapters/hono/authorization-server.js +214 -0
  10. package/esm/adapters/hono/bff/auth-request-store.d.ts +164 -0
  11. package/esm/adapters/hono/bff/auth-request-store.js +154 -0
  12. package/esm/adapters/hono/bff/bff.d.ts +852 -0
  13. package/esm/adapters/hono/bff/bff.js +1194 -0
  14. package/esm/adapters/hono/bff/cookie-prefix.d.ts +72 -0
  15. package/esm/adapters/hono/bff/cookie-prefix.js +85 -0
  16. package/esm/adapters/hono/bff/mod.d.ts +19 -0
  17. package/esm/adapters/hono/bff/mod.js +19 -0
  18. package/esm/adapters/hono/bff/proxy.d.ts +108 -0
  19. package/esm/adapters/hono/bff/proxy.js +314 -0
  20. package/esm/adapters/hono/bff/session-store.d.ts +250 -0
  21. package/esm/adapters/hono/bff/session-store.js +216 -0
  22. package/esm/adapters/hono/bff/testing.d.ts +165 -0
  23. package/esm/adapters/hono/bff/testing.js +254 -0
  24. package/esm/adapters/hono/identity.d.ts +117 -0
  25. package/esm/adapters/hono/identity.js +215 -0
  26. package/esm/adapters/hono/log.d.ts +49 -0
  27. package/esm/adapters/hono/log.js +66 -0
  28. package/esm/adapters/hono/resource-server.d.ts +101 -0
  29. package/esm/adapters/hono/resource-server.js +108 -0
  30. package/esm/client/_http.d.ts +91 -0
  31. package/esm/client/_http.js +303 -0
  32. package/esm/client/base.d.ts +184 -0
  33. package/esm/client/base.js +93 -0
  34. package/esm/client/bff-client.d.ts +235 -0
  35. package/esm/client/bff-client.js +280 -0
  36. package/esm/client/browser-storage.d.ts +152 -0
  37. package/esm/client/browser-storage.js +246 -0
  38. package/esm/client/check.d.ts +114 -0
  39. package/esm/client/check.js +97 -0
  40. package/esm/client/direct-client.d.ts +707 -0
  41. package/esm/client/direct-client.js +1237 -0
  42. package/esm/client/discovery-cache.d.ts +138 -0
  43. package/esm/client/discovery-cache.js +124 -0
  44. package/esm/client/events.d.ts +54 -0
  45. package/esm/client/events.js +37 -0
  46. package/esm/client/mod.d.ts +35 -0
  47. package/esm/client/mod.js +33 -0
  48. package/esm/client/storage.d.ts +127 -0
  49. package/esm/client/storage.js +81 -0
  50. package/esm/deps/jsr.io/@std/assert/1.0.19/almost_equals.d.ts +29 -0
  51. package/esm/deps/jsr.io/@std/assert/1.0.19/almost_equals.js +47 -0
  52. package/esm/deps/jsr.io/@std/assert/1.0.19/array_includes.d.ts +28 -0
  53. package/esm/deps/jsr.io/@std/assert/1.0.19/array_includes.js +65 -0
  54. package/esm/deps/jsr.io/@std/assert/1.0.19/assert.d.ts +16 -0
  55. package/esm/deps/jsr.io/@std/assert/1.0.19/assert.js +23 -0
  56. package/esm/deps/jsr.io/@std/assert/1.0.19/assertion_error.d.ts +25 -0
  57. package/esm/deps/jsr.io/@std/assert/1.0.19/assertion_error.js +30 -0
  58. package/esm/deps/jsr.io/@std/assert/1.0.19/equal.d.ts +24 -0
  59. package/esm/deps/jsr.io/@std/assert/1.0.19/equal.js +193 -0
  60. package/esm/deps/jsr.io/@std/assert/1.0.19/equals.d.ts +36 -0
  61. package/esm/deps/jsr.io/@std/assert/1.0.19/equals.js +61 -0
  62. package/esm/deps/jsr.io/@std/assert/1.0.19/exists.d.ts +17 -0
  63. package/esm/deps/jsr.io/@std/assert/1.0.19/exists.js +27 -0
  64. package/esm/deps/jsr.io/@std/assert/1.0.19/fail.d.ts +14 -0
  65. package/esm/deps/jsr.io/@std/assert/1.0.19/fail.js +20 -0
  66. package/esm/deps/jsr.io/@std/assert/1.0.19/false.d.ts +18 -0
  67. package/esm/deps/jsr.io/@std/assert/1.0.19/false.js +23 -0
  68. package/esm/deps/jsr.io/@std/assert/1.0.19/greater.d.ts +19 -0
  69. package/esm/deps/jsr.io/@std/assert/1.0.19/greater.js +29 -0
  70. package/esm/deps/jsr.io/@std/assert/1.0.19/greater_or_equal.d.ts +19 -0
  71. package/esm/deps/jsr.io/@std/assert/1.0.19/greater_or_equal.js +29 -0
  72. package/esm/deps/jsr.io/@std/assert/1.0.19/instance_of.d.ts +22 -0
  73. package/esm/deps/jsr.io/@std/assert/1.0.19/instance_of.js +52 -0
  74. package/esm/deps/jsr.io/@std/assert/1.0.19/is_error.d.ts +24 -0
  75. package/esm/deps/jsr.io/@std/assert/1.0.19/is_error.js +53 -0
  76. package/esm/deps/jsr.io/@std/assert/1.0.19/less.d.ts +18 -0
  77. package/esm/deps/jsr.io/@std/assert/1.0.19/less.js +28 -0
  78. package/esm/deps/jsr.io/@std/assert/1.0.19/less_or_equal.d.ts +19 -0
  79. package/esm/deps/jsr.io/@std/assert/1.0.19/less_or_equal.js +29 -0
  80. package/esm/deps/jsr.io/@std/assert/1.0.19/match.d.ts +17 -0
  81. package/esm/deps/jsr.io/@std/assert/1.0.19/match.js +26 -0
  82. package/esm/deps/jsr.io/@std/assert/1.0.19/mod.d.ts +43 -0
  83. package/esm/deps/jsr.io/@std/assert/1.0.19/mod.js +45 -0
  84. package/esm/deps/jsr.io/@std/assert/1.0.19/not_equals.d.ts +26 -0
  85. package/esm/deps/jsr.io/@std/assert/1.0.19/not_equals.js +39 -0
  86. package/esm/deps/jsr.io/@std/assert/1.0.19/not_instance_of.d.ts +19 -0
  87. package/esm/deps/jsr.io/@std/assert/1.0.19/not_instance_of.js +29 -0
  88. package/esm/deps/jsr.io/@std/assert/1.0.19/not_match.d.ts +17 -0
  89. package/esm/deps/jsr.io/@std/assert/1.0.19/not_match.js +26 -0
  90. package/esm/deps/jsr.io/@std/assert/1.0.19/not_strict_equals.d.ts +22 -0
  91. package/esm/deps/jsr.io/@std/assert/1.0.19/not_strict_equals.js +32 -0
  92. package/esm/deps/jsr.io/@std/assert/1.0.19/object_match.d.ts +28 -0
  93. package/esm/deps/jsr.io/@std/assert/1.0.19/object_match.js +177 -0
  94. package/esm/deps/jsr.io/@std/assert/1.0.19/rejects.d.ts +41 -0
  95. package/esm/deps/jsr.io/@std/assert/1.0.19/rejects.js +53 -0
  96. package/esm/deps/jsr.io/@std/assert/1.0.19/strict_equals.d.ts +23 -0
  97. package/esm/deps/jsr.io/@std/assert/1.0.19/strict_equals.js +58 -0
  98. package/esm/deps/jsr.io/@std/assert/1.0.19/string_includes.d.ts +17 -0
  99. package/esm/deps/jsr.io/@std/assert/1.0.19/string_includes.js +26 -0
  100. package/esm/deps/jsr.io/@std/assert/1.0.19/throws.d.ts +44 -0
  101. package/esm/deps/jsr.io/@std/assert/1.0.19/throws.js +44 -0
  102. package/esm/deps/jsr.io/@std/assert/1.0.19/unimplemented.d.ts +14 -0
  103. package/esm/deps/jsr.io/@std/assert/1.0.19/unimplemented.js +20 -0
  104. package/esm/deps/jsr.io/@std/assert/1.0.19/unreachable.d.ts +14 -0
  105. package/esm/deps/jsr.io/@std/assert/1.0.19/unreachable.js +20 -0
  106. package/esm/deps/jsr.io/@std/async/1.5.0/delay.d.ts +44 -0
  107. package/esm/deps/jsr.io/@std/async/1.5.0/delay.js +84 -0
  108. package/esm/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.d.ts +39 -0
  109. package/esm/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.js +61 -0
  110. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common16.d.ts +22 -0
  111. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common16.js +51 -0
  112. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common32.d.ts +34 -0
  113. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common32.js +192 -0
  114. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common64.d.ts +34 -0
  115. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common64.js +113 -0
  116. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common_detach.d.ts +3 -0
  117. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common_detach.js +13 -0
  118. package/esm/deps/jsr.io/@std/encoding/1.0.11/_types.d.ts +8 -0
  119. package/esm/deps/jsr.io/@std/encoding/1.0.11/_types.js +2 -0
  120. package/esm/deps/jsr.io/@std/encoding/1.0.11/_validate_binary_like.d.ts +1 -0
  121. package/esm/deps/jsr.io/@std/encoding/1.0.11/_validate_binary_like.js +26 -0
  122. package/esm/deps/jsr.io/@std/encoding/1.0.11/ascii85.d.ts +60 -0
  123. package/esm/deps/jsr.io/@std/encoding/1.0.11/ascii85.js +152 -0
  124. package/esm/deps/jsr.io/@std/encoding/1.0.11/base32.d.ts +39 -0
  125. package/esm/deps/jsr.io/@std/encoding/1.0.11/base32.js +87 -0
  126. package/esm/deps/jsr.io/@std/encoding/1.0.11/base58.d.ts +39 -0
  127. package/esm/deps/jsr.io/@std/encoding/1.0.11/base58.js +131 -0
  128. package/esm/deps/jsr.io/@std/encoding/1.0.11/base64.d.ts +39 -0
  129. package/esm/deps/jsr.io/@std/encoding/1.0.11/base64.js +82 -0
  130. package/esm/deps/jsr.io/@std/encoding/1.0.11/base64url.d.ts +39 -0
  131. package/esm/deps/jsr.io/@std/encoding/1.0.11/base64url.js +72 -0
  132. package/esm/deps/jsr.io/@std/encoding/1.0.11/hex.d.ts +38 -0
  133. package/esm/deps/jsr.io/@std/encoding/1.0.11/hex.js +87 -0
  134. package/esm/deps/jsr.io/@std/encoding/1.0.11/mod.d.ts +97 -0
  135. package/esm/deps/jsr.io/@std/encoding/1.0.11/mod.js +99 -0
  136. package/esm/deps/jsr.io/@std/encoding/1.0.11/varint.d.ts +119 -0
  137. package/esm/deps/jsr.io/@std/encoding/1.0.11/varint.js +209 -0
  138. package/esm/deps/jsr.io/@std/http/1.1.3/status.d.ts +343 -0
  139. package/esm/deps/jsr.io/@std/http/1.1.3/status.js +343 -0
  140. package/esm/deps/jsr.io/@std/internal/1.0.14/assertion_state.d.ts +159 -0
  141. package/esm/deps/jsr.io/@std/internal/1.0.14/assertion_state.js +223 -0
  142. package/esm/deps/jsr.io/@std/internal/1.0.14/build_message.d.ts +79 -0
  143. package/esm/deps/jsr.io/@std/internal/1.0.14/build_message.js +116 -0
  144. package/esm/deps/jsr.io/@std/internal/1.0.14/diff.d.ts +139 -0
  145. package/esm/deps/jsr.io/@std/internal/1.0.14/diff.js +277 -0
  146. package/esm/deps/jsr.io/@std/internal/1.0.14/diff_str.d.ts +98 -0
  147. package/esm/deps/jsr.io/@std/internal/1.0.14/diff_str.js +181 -0
  148. package/esm/deps/jsr.io/@std/internal/1.0.14/format.d.ts +29 -0
  149. package/esm/deps/jsr.io/@std/internal/1.0.14/format.js +68 -0
  150. package/esm/deps/jsr.io/@std/internal/1.0.14/styles.d.ts +158 -0
  151. package/esm/deps/jsr.io/@std/internal/1.0.14/styles.js +206 -0
  152. package/esm/deps/jsr.io/@std/internal/1.0.14/types.d.ts +24 -0
  153. package/esm/deps/jsr.io/@std/internal/1.0.14/types.js +3 -0
  154. package/esm/deps/jsr.io/@std/testing/1.0.20/_test_suite.d.ts +91 -0
  155. package/esm/deps/jsr.io/@std/testing/1.0.20/_test_suite.js +347 -0
  156. package/esm/deps/jsr.io/@std/testing/1.0.20/bdd.d.ts +382 -0
  157. package/esm/deps/jsr.io/@std/testing/1.0.20/bdd.js +1110 -0
  158. package/esm/deps/jsr.io/@udibo/http-error/0.11.1/mod.d.ts +363 -0
  159. package/esm/deps/jsr.io/@udibo/http-error/0.11.1/mod.js +616 -0
  160. package/esm/errors.d.ts +203 -0
  161. package/esm/errors.js +287 -0
  162. package/esm/identity/captcha.d.ts +147 -0
  163. package/esm/identity/captcha.js +64 -0
  164. package/esm/identity/delivery.d.ts +96 -0
  165. package/esm/identity/delivery.js +41 -0
  166. package/esm/identity/errors.d.ts +39 -0
  167. package/esm/identity/errors.js +46 -0
  168. package/esm/identity/events.d.ts +242 -0
  169. package/esm/identity/events.js +39 -0
  170. package/esm/identity/external/_shared.d.ts +86 -0
  171. package/esm/identity/external/_shared.js +107 -0
  172. package/esm/identity/external/_token-exchange.d.ts +61 -0
  173. package/esm/identity/external/_token-exchange.js +179 -0
  174. package/esm/identity/external/apple-client-secret.d.ts +82 -0
  175. package/esm/identity/external/apple-client-secret.js +133 -0
  176. package/esm/identity/external/apple.d.ts +64 -0
  177. package/esm/identity/external/apple.js +248 -0
  178. package/esm/identity/external/discord.d.ts +38 -0
  179. package/esm/identity/external/discord.js +62 -0
  180. package/esm/identity/external/errors.d.ts +48 -0
  181. package/esm/identity/external/errors.js +36 -0
  182. package/esm/identity/external/flow.d.ts +107 -0
  183. package/esm/identity/external/flow.js +158 -0
  184. package/esm/identity/external/github.d.ts +42 -0
  185. package/esm/identity/external/github.js +164 -0
  186. package/esm/identity/external/google.d.ts +52 -0
  187. package/esm/identity/external/google.js +38 -0
  188. package/esm/identity/external/mod.d.ts +63 -0
  189. package/esm/identity/external/mod.js +61 -0
  190. package/esm/identity/external/oauth2.d.ts +110 -0
  191. package/esm/identity/external/oauth2.js +158 -0
  192. package/esm/identity/external/oidc.d.ts +81 -0
  193. package/esm/identity/external/oidc.js +250 -0
  194. package/esm/identity/external/provider.d.ts +132 -0
  195. package/esm/identity/external/provider.js +12 -0
  196. package/esm/identity/hibp.d.ts +67 -0
  197. package/esm/identity/hibp.js +87 -0
  198. package/esm/identity/identifier.d.ts +44 -0
  199. package/esm/identity/identifier.js +47 -0
  200. package/esm/identity/lockout.d.ts +155 -0
  201. package/esm/identity/lockout.js +117 -0
  202. package/esm/identity/mfa/mod.d.ts +42 -0
  203. package/esm/identity/mfa/mod.js +42 -0
  204. package/esm/identity/mfa/recovery-codes.d.ts +96 -0
  205. package/esm/identity/mfa/recovery-codes.js +80 -0
  206. package/esm/identity/mfa/service.d.ts +338 -0
  207. package/esm/identity/mfa/service.js +351 -0
  208. package/esm/identity/mfa/totp.d.ts +186 -0
  209. package/esm/identity/mfa/totp.js +194 -0
  210. package/esm/identity/migration.d.ts +155 -0
  211. package/esm/identity/migration.js +243 -0
  212. package/esm/identity/mod.d.ts +65 -0
  213. package/esm/identity/mod.js +64 -0
  214. package/esm/identity/otp.d.ts +255 -0
  215. package/esm/identity/otp.js +245 -0
  216. package/esm/identity/password-policy.d.ts +45 -0
  217. package/esm/identity/password-policy.js +60 -0
  218. package/esm/identity/password.d.ts +171 -0
  219. package/esm/identity/password.js +160 -0
  220. package/esm/identity/rate-limit.d.ts +192 -0
  221. package/esm/identity/rate-limit.js +168 -0
  222. package/esm/identity/service.d.ts +579 -0
  223. package/esm/identity/service.js +835 -0
  224. package/esm/identity/session.d.ts +122 -0
  225. package/esm/identity/session.js +48 -0
  226. package/esm/identity/token-flow.d.ts +214 -0
  227. package/esm/identity/token-flow.js +173 -0
  228. package/esm/models/authentication.d.ts +24 -0
  229. package/esm/models/authentication.js +1 -0
  230. package/esm/models/authorization-code.d.ts +63 -0
  231. package/esm/models/authorization-code.js +1 -0
  232. package/esm/models/authorization.d.ts +165 -0
  233. package/esm/models/authorization.js +160 -0
  234. package/esm/models/client.d.ts +78 -0
  235. package/esm/models/client.js +1 -0
  236. package/esm/models/device-authorization.d.ts +30 -0
  237. package/esm/models/device-authorization.js +1 -0
  238. package/esm/models/responses.d.ts +93 -0
  239. package/esm/models/responses.js +1 -0
  240. package/esm/models/scope.d.ts +81 -0
  241. package/esm/models/scope.js +125 -0
  242. package/esm/models/token.d.ts +135 -0
  243. package/esm/models/token.js +1 -0
  244. package/esm/package.json +3 -0
  245. package/esm/react/callback.d.ts +52 -0
  246. package/esm/react/callback.js +71 -0
  247. package/esm/react/components/class-names.d.ts +91 -0
  248. package/esm/react/components/class-names.js +118 -0
  249. package/esm/react/components/internal.d.ts +62 -0
  250. package/esm/react/components/internal.js +102 -0
  251. package/esm/react/components/mfa-challenge-form.d.ts +66 -0
  252. package/esm/react/components/mfa-challenge-form.js +46 -0
  253. package/esm/react/components/mfa-enrollment-form.d.ts +83 -0
  254. package/esm/react/components/mfa-enrollment-form.js +41 -0
  255. package/esm/react/components/mod.d.ts +103 -0
  256. package/esm/react/components/mod.js +93 -0
  257. package/esm/react/components/request-password-reset-form.d.ts +61 -0
  258. package/esm/react/components/request-password-reset-form.js +41 -0
  259. package/esm/react/components/reset-password-form.d.ts +66 -0
  260. package/esm/react/components/reset-password-form.js +56 -0
  261. package/esm/react/components/sign-in-form.d.ts +74 -0
  262. package/esm/react/components/sign-in-form.js +43 -0
  263. package/esm/react/components/sign-up-form.d.ts +85 -0
  264. package/esm/react/components/sign-up-form.js +57 -0
  265. package/esm/react/components/types.d.ts +208 -0
  266. package/esm/react/components/types.js +14 -0
  267. package/esm/react/components/use-auth-form.d.ts +118 -0
  268. package/esm/react/components/use-auth-form.js +172 -0
  269. package/esm/react/components/user-menu.d.ts +79 -0
  270. package/esm/react/components/user-menu.js +73 -0
  271. package/esm/react/context.d.ts +51 -0
  272. package/esm/react/context.js +16 -0
  273. package/esm/react/mod.d.ts +26 -0
  274. package/esm/react/mod.js +26 -0
  275. package/esm/react/provider.d.ts +40 -0
  276. package/esm/react/provider.js +189 -0
  277. package/esm/react/require-auth.d.ts +31 -0
  278. package/esm/react/require-auth.js +37 -0
  279. package/esm/react/testing.d.ts +322 -0
  280. package/esm/react/testing.js +461 -0
  281. package/esm/react/use-authorization.d.ts +31 -0
  282. package/esm/react/use-authorization.js +36 -0
  283. package/esm/react/use-oauth2.d.ts +112 -0
  284. package/esm/react/use-oauth2.js +127 -0
  285. package/esm/server/authorization-server.d.ts +736 -0
  286. package/esm/server/authorization-server.js +1304 -0
  287. package/esm/server/client-authentication.d.ts +28 -0
  288. package/esm/server/client-authentication.js +51 -0
  289. package/esm/server/grants/authorization-code.d.ts +179 -0
  290. package/esm/server/grants/authorization-code.js +232 -0
  291. package/esm/server/grants/client-credentials.d.ts +52 -0
  292. package/esm/server/grants/client-credentials.js +53 -0
  293. package/esm/server/grants/device-authorization.d.ts +103 -0
  294. package/esm/server/grants/device-authorization.js +156 -0
  295. package/esm/server/grants/grant.d.ts +165 -0
  296. package/esm/server/grants/grant.js +173 -0
  297. package/esm/server/grants/password.d.ts +80 -0
  298. package/esm/server/grants/password.js +92 -0
  299. package/esm/server/grants/refresh-token.d.ts +80 -0
  300. package/esm/server/grants/refresh-token.js +136 -0
  301. package/esm/server/introspection-token-reader.d.ts +153 -0
  302. package/esm/server/introspection-token-reader.js +164 -0
  303. package/esm/server/jwks-token-reader.d.ts +263 -0
  304. package/esm/server/jwks-token-reader.js +508 -0
  305. package/esm/server/mod.d.ts +23 -0
  306. package/esm/server/mod.js +15 -0
  307. package/esm/server/public-suffix/mod.d.ts +62 -0
  308. package/esm/server/public-suffix/mod.js +103 -0
  309. package/esm/server/public-suffix/rules.d.ts +23 -0
  310. package/esm/server/public-suffix/rules.js +23 -0
  311. package/esm/server/redirect-uri.d.ts +187 -0
  312. package/esm/server/redirect-uri.js +331 -0
  313. package/esm/server/resource-server.d.ts +286 -0
  314. package/esm/server/resource-server.js +365 -0
  315. package/esm/server/services/authorization-code.d.ts +84 -0
  316. package/esm/server/services/authorization-code.js +35 -0
  317. package/esm/server/services/client.d.ts +35 -0
  318. package/esm/server/services/client.js +1 -0
  319. package/esm/server/services/device-authorization.d.ts +134 -0
  320. package/esm/server/services/device-authorization.js +7 -0
  321. package/esm/server/services/token.d.ts +242 -0
  322. package/esm/server/services/token.js +78 -0
  323. package/esm/server/services/user.d.ts +29 -0
  324. package/esm/server/services/user.js +7 -0
  325. package/esm/server/signing-keys.d.ts +201 -0
  326. package/esm/server/signing-keys.js +225 -0
  327. package/esm/server/utils/hash.d.ts +6 -0
  328. package/esm/server/utils/hash.js +11 -0
  329. package/esm/testing/contract/authorization-code.d.ts +37 -0
  330. package/esm/testing/contract/authorization-code.js +93 -0
  331. package/esm/testing/contract/client.d.ts +85 -0
  332. package/esm/testing/contract/client.js +126 -0
  333. package/esm/testing/contract/device-authorization.d.ts +37 -0
  334. package/esm/testing/contract/device-authorization.js +193 -0
  335. package/esm/testing/contract/lockout-store.d.ts +47 -0
  336. package/esm/testing/contract/lockout-store.js +122 -0
  337. package/esm/testing/contract/mfa-store.d.ts +50 -0
  338. package/esm/testing/contract/mfa-store.js +226 -0
  339. package/esm/testing/contract/mod.d.ts +39 -0
  340. package/esm/testing/contract/mod.js +39 -0
  341. package/esm/testing/contract/otp-store.d.ts +48 -0
  342. package/esm/testing/contract/otp-store.js +197 -0
  343. package/esm/testing/contract/rate-limit-store.d.ts +52 -0
  344. package/esm/testing/contract/rate-limit-store.js +105 -0
  345. package/esm/testing/contract/token-flow-store.d.ts +54 -0
  346. package/esm/testing/contract/token-flow-store.js +179 -0
  347. package/esm/testing/contract/token-reader.d.ts +77 -0
  348. package/esm/testing/contract/token-reader.js +78 -0
  349. package/esm/testing/contract/token.d.ts +61 -0
  350. package/esm/testing/contract/token.js +287 -0
  351. package/esm/testing/contract/user.d.ts +63 -0
  352. package/esm/testing/contract/user.js +75 -0
  353. package/esm/testing/mod.d.ts +34 -0
  354. package/esm/testing/mod.js +34 -0
  355. package/esm/testing/server.d.ts +197 -0
  356. package/esm/testing/server.js +193 -0
  357. package/esm/testing/services.d.ts +373 -0
  358. package/esm/testing/services.js +703 -0
  359. package/esm/utils/_buffer.d.ts +10 -0
  360. package/esm/utils/_buffer.js +12 -0
  361. package/esm/utils/_timing-safe.d.ts +13 -0
  362. package/esm/utils/_timing-safe.js +22 -0
  363. package/esm/utils/authentication-context.d.ts +3 -0
  364. package/esm/utils/authentication-context.js +14 -0
  365. package/esm/utils/basic-auth.d.ts +50 -0
  366. package/esm/utils/basic-auth.js +106 -0
  367. package/esm/utils/crypto.d.ts +97 -0
  368. package/esm/utils/crypto.js +162 -0
  369. package/esm/utils/pkce.d.ts +151 -0
  370. package/esm/utils/pkce.js +179 -0
  371. package/esm/utils/text.d.ts +24 -0
  372. package/esm/utils/text.js +28 -0
  373. package/esm/utils/url.d.ts +66 -0
  374. package/esm/utils/url.js +90 -0
  375. package/package.json +92 -0
@@ -0,0 +1,579 @@
1
+ /**
2
+ * `IdentityService` — composable functions for an app that owns its login.
3
+ *
4
+ * Orchestrates the identity primitives ({@link PasswordIdentityService},
5
+ * {@link TokenFlowService}, delivery hooks, {@link RevocableSessionService})
6
+ * over an **app-owned** {@link IdentityUserStore} into the flows a single app
7
+ * needs: sign-up, sign-in, password reset, email verification, and passwordless
8
+ * sign-in (magic links + one-time codes). These are plain
9
+ * methods you call from your own routes/loaders/actions — there is no opinionated
10
+ * mounted framework here. A thin, optional Hono route factory lives in
11
+ * `@udibo/oauth2/hono/identity` for apps that want the endpoints mounted.
12
+ *
13
+ * Storage-agnostic by design: every flow addresses users by opaque id and the
14
+ * {@link IdentityUserStore} is yours — back it with whatever database, ORM, and
15
+ * schema your app already uses. The library composes the flows; it never owns
16
+ * your tables. It stays below the turnkey-identity-service line.
17
+ *
18
+ * @module
19
+ */
20
+ import { type DeliveryHooks } from "./delivery.js";
21
+ import type { AccountLockoutLike } from "./lockout.js";
22
+ import { type PasswordCredential, type PasswordHasherLike } from "./password.js";
23
+ import { type TokenFlowService } from "./token-flow.js";
24
+ import type { RevocableSessionService } from "./session.js";
25
+ import { type PasswordPolicy } from "./password-policy.js";
26
+ import { type RateLimiterLike } from "./rate-limit.js";
27
+ import { type OtpStore } from "./otp.js";
28
+ import { type IdentityEventHook } from "./events.js";
29
+ import { type LegacyPasswordVerifier } from "./migration.js";
30
+ /** The minimum the identity flows require of your user record. */
31
+ export interface IdentityUser {
32
+ /** Opaque user id the flows address users by; never interpreted by the library. */
33
+ id: string;
34
+ }
35
+ /**
36
+ * App-owned user storage the identity flows orchestrate. You implement it over
37
+ * your own database/ORM; the flows only ever address users by opaque id, so the
38
+ * backing store stays entirely yours.
39
+ */
40
+ export interface IdentityUserStore<User extends IdentityUser> {
41
+ /**
42
+ * Create a user from a sign-up `profile` (your app's fields — validate them)
43
+ * plus the hashed password credential.
44
+ */
45
+ create(profile: Record<string, unknown>, credential: PasswordCredential): Promise<User>;
46
+ /** Find a user by a sign-in identifier (email/username/phone). */
47
+ findByIdentifier(identifier: string): Promise<User | undefined>;
48
+ /** Find a user by email (password-reset / re-verification requests). */
49
+ findByEmail(email: string): Promise<User | undefined>;
50
+ /**
51
+ * The user's stored password credential, or `undefined`.
52
+ *
53
+ * Must reflect every write committed before a
54
+ * {@link IdentityUserStore.replaceCredential} call returned `false` — read
55
+ * the primary, never a cache, a lagging replica, or a snapshot shared with
56
+ * the compare-and-set. The service re-reads through this to decide a sign-in
57
+ * that lost the compare-and-set, so a stale read lets a password retired by
58
+ * the winning write still sign in.
59
+ */
60
+ getCredential(userId: string): Promise<PasswordCredential | undefined>;
61
+ /** Replace the user's password credential (reset / change). */
62
+ setCredential(userId: string, credential: PasswordCredential): Promise<void>;
63
+ /**
64
+ * Atomically replace the credential only if it still equals `expected`.
65
+ * `undefined` expects no native credential, for an imported-password upgrade.
66
+ * Return `false` without writing if anything changed. Compare all stored
67
+ * credential fields in the same database operation as the write, never read
68
+ * then write. On `false` the service re-reads the credential and re-verifies
69
+ * the password against it, so a concurrent sign-in that rehashed first still
70
+ * lets this one in while a reset or change to a different password rejects
71
+ * it. Without this capability, sign-in succeeds but automatic rehash and
72
+ * imported credential upgrades are skipped; explicit password resets still
73
+ * work.
74
+ */
75
+ replaceCredential?(userId: string, expected: PasswordCredential | undefined, credential: PasswordCredential): Promise<boolean>;
76
+ /**
77
+ * Mark the user's email verified. Omit if you don't verify email.
78
+ *
79
+ * `email` is the address the verification token was **issued for**, when the
80
+ * token carried one. Your implementation must only flip the flag when the
81
+ * user's current email still equals it (`WHERE id = $userId AND email =
82
+ * $email`) — otherwise a link minted for one address verifies whatever
83
+ * address the account holds when the link is clicked, letting an attacker
84
+ * mark a victim's address verified by changing the account email after
85
+ * requesting the link.
86
+ *
87
+ * Must be idempotent: it runs before the single-use token is consumed, so a
88
+ * retried link calls it again.
89
+ */
90
+ markEmailVerified?(userId: string, email?: string): Promise<void>;
91
+ /**
92
+ * The user's imported foreign password hash (bcrypt/argon2/PBKDF2/… PHC
93
+ * string), or `null` once migrated or never imported. Implement it — alongside
94
+ * a `legacyCredential` column and {@link IdentityUserStore.clearLegacyCredential}
95
+ * — to enable upgrade-on-login: {@link IdentityService.signIn} verifies this
96
+ * hash with the configured `legacyVerifiers` only while the user has no
97
+ * native credential (the native credential, once set, is authoritative —
98
+ * a wrong password never falls back to the imported hash). Only consulted
99
+ * when `legacyVerifiers` is set.
100
+ */
101
+ getLegacyCredential?(userId: string): Promise<string | null>;
102
+ /**
103
+ * Drop the user's imported foreign hash once it is superseded — after a
104
+ * successful upgrade-on-login and after {@link IdentityService.resetPassword}.
105
+ * **Implement this whenever you implement {@link getLegacyCredential}:** a
106
+ * lingering foreign hash keeps the old imported password alive as a
107
+ * fallback — ignored while a native credential exists, but it would come
108
+ * back to life if the native credential is ever removed. Called at most
109
+ * once per user per supersession.
110
+ */
111
+ clearLegacyCredential?(userId: string): Promise<void>;
112
+ }
113
+ /**
114
+ * Per-flow limiter overrides for {@link IdentityServiceOptions.rateLimiters}.
115
+ * One key per throttled flow, each falling back to
116
+ * {@link IdentityServiceOptions.rateLimiter} when unset. `signInCode` covers
117
+ * both requesting and verifying a code — they share the `otp:signin:` key.
118
+ */
119
+ export interface IdentityRateLimiters {
120
+ /** `signin:<identifier>` — {@link IdentityService.signIn}. */
121
+ signIn?: RateLimiterLike;
122
+ /** `pwreset:<email>` — {@link IdentityService.requestPasswordReset}. */
123
+ passwordReset?: RateLimiterLike;
124
+ /** `verifyemail:<userId>` — {@link IdentityService.requestEmailVerification}. */
125
+ emailVerification?: RateLimiterLike;
126
+ /** `unlock:<userId>` — {@link IdentityService.requestAccountUnlock}. */
127
+ accountUnlock?: RateLimiterLike;
128
+ /** `pwless:<email>` — {@link IdentityService.requestSignInLink}. */
129
+ signInLink?: RateLimiterLike;
130
+ /** `otp:signin:<email>` — request and verify of a sign-in code. */
131
+ signInCode?: RateLimiterLike;
132
+ }
133
+ /** Options for {@link IdentityService}. */
134
+ export interface IdentityServiceOptions<User extends IdentityUser> {
135
+ /** App-owned user storage. */
136
+ users: IdentityUserStore<User>;
137
+ /** Token flow for verify/reset links. Required for those flows. */
138
+ tokens?: TokenFlowService;
139
+ /**
140
+ * Password hasher. Defaults to a new {@link PasswordIdentityService}
141
+ * (PBKDF2-SHA-256). Any {@link PasswordHasherLike} works, so argon2 or scrypt
142
+ * plug in with your own dependency. When the hasher implements
143
+ * `needsRehash`, {@link IdentityService.signIn} transparently re-hashes and
144
+ * stores a credential whose work factor has fallen behind, when the user
145
+ * store implements `replaceCredential`.
146
+ */
147
+ passwords?: PasswordHasherLike;
148
+ /**
149
+ * Foreign password-hash verifiers for **upgrade-on-login**, tried in order.
150
+ * When set, {@link IdentityService.signIn} — for a user with no native
151
+ * credential yet — reads the imported hash via
152
+ * {@link IdentityUserStore.getLegacyCredential} and verifies it with the first
153
+ * verifier whose `canVerify` accepts it. On a match it rehashes the password
154
+ * into the native format ({@link IdentityUserStore.replaceCredential}), clears the
155
+ * imported hash ({@link IdentityUserStore.clearLegacyCredential}), emits a
156
+ * `password.upgraded` event, and signs the user in. The package ships
157
+ * {@link pbkdf2Verifier} built-in; bcrypt/argon2/scrypt are bring-your-own via
158
+ * the {@link LegacyPasswordVerifier} seam (no dep-free implementation exists).
159
+ */
160
+ legacyVerifiers?: LegacyPasswordVerifier[];
161
+ /**
162
+ * Minimum wall-clock duration of a **failed** {@link IdentityService.signIn},
163
+ * in ms. Defaults to `250`. Every rejection — unknown identifier, locked
164
+ * account, no password set, wrong native password, wrong imported password —
165
+ * is held to the same deadline measured from the call's first statement, so
166
+ * the response time reveals nothing about which branch ran.
167
+ *
168
+ * Set it above the cost of your slowest configured
169
+ * {@link IdentityServiceOptions.legacyVerifiers} plus one password hash —
170
+ * that is the expensive branch (a foreign KDF the native branch never runs),
171
+ * and without a floor above it an unauthenticated caller can separate the
172
+ * accounts still carrying an imported hash from the migrated ones by response
173
+ * time alone. A branch that outruns the floor returns as soon as its own work
174
+ * finishes: whatever it spends *above* the floor stays visible, so raising a
175
+ * work factor means re-checking this number.
176
+ *
177
+ * `0` disables the floor entirely, which restores that signal in full — the
178
+ * one value that turns it off. Anything else out of range (negative, `NaN`,
179
+ * `Infinity`) falls back to the default rather than to no floor.
180
+ * Successful sign-ins are never delayed.
181
+ */
182
+ failedSignInFloorMs?: number;
183
+ /** Session revocation, called on a successful password reset. Optional. */
184
+ sessions?: RevocableSessionService;
185
+ /** Delivery transports for verify/reset links. Optional. */
186
+ delivery?: DeliveryHooks;
187
+ /**
188
+ * Base URL (origin, or origin + prefix) used to build the action links
189
+ * passed to delivery hooks. When omitted, hooks receive only the raw `token`.
190
+ */
191
+ baseUrl?: string;
192
+ /**
193
+ * Token lifetimes in ms. Defaults: password reset 1h, email verification 24h,
194
+ * account unlock 1h, sign-in link 15m. A per-call `ttlMs` — currently only
195
+ * {@link IdentityService.requestSignInLink} takes one — overrides the
196
+ * configured default for that request. One-time sign-in **codes** are not
197
+ * tokens; their lifetime is {@link IdentityServiceOptions.otp}'s `ttlMs`.
198
+ */
199
+ ttl?: {
200
+ passwordReset?: number;
201
+ emailVerification?: number;
202
+ accountUnlock?: number;
203
+ signInLink?: number;
204
+ };
205
+ /**
206
+ * One-time sign-in codes ("email me a code"). When set,
207
+ * {@link IdentityService.requestSignInCode} and
208
+ * {@link IdentityService.verifySignInCode} run an {@link EmailOtpService}
209
+ * over the app-owned store. Storage and code shape only — the code flow's
210
+ * single throttle is `rateLimiters.signInCode` (falling back to
211
+ * {@link rateLimiter}) under the key `otp:signin:<email>`, so a request for
212
+ * a known email is throttled exactly like one for an unknown email.
213
+ */
214
+ otp?: {
215
+ /** App-owned code storage. */
216
+ store: OtpStore;
217
+ /** Code length in digits. Defaults to `6`. */
218
+ digits?: number;
219
+ /** Code lifetime in ms. Defaults to 10 minutes. */
220
+ ttlMs?: number;
221
+ /** Wrong-attempt budget before the code locks. Defaults to `5`. */
222
+ maxAttempts?: number;
223
+ };
224
+ /**
225
+ * Password policy enforced by {@link IdentityService.signUp} and
226
+ * {@link IdentityService.resetPassword} before hashing — always, not only
227
+ * when you configure one. Omitting it leaves the
228
+ * {@link PasswordPolicy} defaults in force: 8–256 characters, no composition
229
+ * rules, no extra validators. The maximum is a DoS guard on the hash input
230
+ * (the hasher itself has none), so every password the app can **store** is
231
+ * bounded in every configuration. {@link IdentityService.signIn} is outside
232
+ * the policy by design — it hashes whatever the request carries, because the
233
+ * equal-work path that hides an unknown identifier has to run on the
234
+ * submitted password as-is. A violation — including a non-string password,
235
+ * which the hasher would otherwise `String`-coerce — throws
236
+ * {@link IdentityError} `weak_password`.
237
+ */
238
+ passwordPolicy?: PasswordPolicy;
239
+ /**
240
+ * Auth-flow rate limiter. When set, {@link IdentityService.signIn} throttles
241
+ * by identifier — an unknown and a known identifier throttle identically, so
242
+ * the limit can't be used to enumerate accounts — throws
243
+ * {@link IdentityError} `rate_limited` (with `retryAfterMs`) when exceeded,
244
+ * and resets the counter on a successful sign-in. Every other flow throttles
245
+ * on the same limiter with its own key: the email-sending requests
246
+ * ({@link IdentityService.requestPasswordReset} per case-folded email,
247
+ * {@link IdentityService.requestEmailVerification} and
248
+ * {@link IdentityService.requestAccountUnlock} per user) and the passwordless
249
+ * flows (`pwless:<email>` for sign-in links, `otp:signin:<email>` for sign-in
250
+ * codes — request and verify share the key; a successful verify resets it),
251
+ * so none of them can drive unbounded sends. IP-based limiting stays a
252
+ * route-layer concern: the service has no request context, which is the
253
+ * correct seam.
254
+ *
255
+ * This is the **default** for every flow; {@link rateLimiters} overrides it
256
+ * per flow when one threshold cannot serve them all.
257
+ */
258
+ rateLimiter?: RateLimiterLike;
259
+ /**
260
+ * Per-flow limiter overrides. Set one when a single threshold cannot serve
261
+ * every flow — a limit tuned as a sign-in floor is usually far too permissive
262
+ * for the four flows that make the server **send an email to a
263
+ * caller-supplied address** (`passwordReset`, `emailVerification`,
264
+ * `accountUnlock`, `signInLink`, plus `signInCode`), which typically want a
265
+ * handful of requests per hour rather than per 15 minutes.
266
+ *
267
+ * Each entry is a whole {@link RateLimiterLike} — build one
268
+ * {@link RateLimiter} per flow (they can share a {@link RateLimitStore}; the
269
+ * key prefixes already keep their counters disjoint) or bring your own.
270
+ * Entries left unset fall back to {@link rateLimiter}, so adding this option
271
+ * never changes an existing caller's behavior.
272
+ *
273
+ * @example Throttle the email-sending flows harder than sign-in
274
+ * ```ts
275
+ * const emailFlow = new RateLimiter({
276
+ * store: sharedStore,
277
+ * limit: 3,
278
+ * windowMs: 60 * 60_000,
279
+ * });
280
+ * const identity = new IdentityService<AppUser>({
281
+ * users: userStore,
282
+ * rateLimiter: new RateLimiter({ store: sharedStore }),
283
+ * rateLimiters: {
284
+ * passwordReset: emailFlow,
285
+ * emailVerification: emailFlow,
286
+ * accountUnlock: emailFlow,
287
+ * signInLink: emailFlow,
288
+ * signInCode: emailFlow,
289
+ * },
290
+ * });
291
+ * ```
292
+ */
293
+ rateLimiters?: IdentityRateLimiters;
294
+ /**
295
+ * Failed-attempt account lockout. When set, {@link IdentityService.signIn}
296
+ * records consecutive wrong-password failures per account and — once the
297
+ * threshold locks the account — rejects further attempts with the same
298
+ * uniform, timing-equalized `null` an unknown identifier gets (no lockout
299
+ * oracle). A successful sign-in resets the count;
300
+ * {@link IdentityService.unlockAccount} clears a lock via an emailed
301
+ * single-use token.
302
+ */
303
+ lockout?: AccountLockoutLike;
304
+ /**
305
+ * How the attack protections respond when tripped. `"enforce"` (the safe
306
+ * default) blocks: rate limiting throws and a locked account can't sign in.
307
+ * `"log-only"` never blocks — events still fire (with `enforced: false`) so
308
+ * adopters can observe thresholds before turning enforcement on.
309
+ */
310
+ protectionMode?: "enforce" | "log-only";
311
+ /**
312
+ * Called with an {@link IdentityEvent} after each flow outcome — the seam for
313
+ * audit capture. Awaited, but isolated: a rejection is logged and swallowed
314
+ * so observability can never break the auth flow. Optional; no-op when
315
+ * absent.
316
+ */
317
+ onEvent?: IdentityEventHook;
318
+ }
319
+ /**
320
+ * Outcome of {@link IdentityService.verifyEmail}. `success` carries the verified
321
+ * user; `expired` and `invalid` are distinguished so the UI can offer to resend
322
+ * an expired link rather than showing one generic error.
323
+ */
324
+ export type VerifyEmailResult = {
325
+ status: "success";
326
+ userId: string;
327
+ email?: string;
328
+ } | {
329
+ status: "expired";
330
+ } | {
331
+ status: "invalid";
332
+ };
333
+ /**
334
+ * Outcome of {@link IdentityService.consumeSignInLink}. `expired` and
335
+ * `invalid` are distinguished so the UI can offer a fresh link for an expired
336
+ * one. No session is created — do that in your app on `success`.
337
+ */
338
+ export type ConsumeSignInLinkResult = {
339
+ status: "success";
340
+ userId: string;
341
+ } | {
342
+ status: "expired";
343
+ } | {
344
+ status: "invalid";
345
+ };
346
+ /**
347
+ * Outcome of {@link IdentityService.verifySignInCode}. Deliberately only
348
+ * `success` vs `invalid`: a known email whose code expired or hit its attempt
349
+ * cap collapses to `invalid`, identical to an unknown email, so the caller-
350
+ * facing result is not an account-enumeration oracle. The precise reason
351
+ * (`expired`/`locked`/`unknown_email`) is available server-side via the
352
+ * `signin_code.failed` event.
353
+ */
354
+ export type VerifySignInCodeResult = {
355
+ status: "success";
356
+ userId: string;
357
+ } | {
358
+ status: "invalid";
359
+ };
360
+ /**
361
+ * Outcome of {@link IdentityService.unlockAccount}. `expired` and `invalid`
362
+ * are distinguished so the UI can offer a fresh link for an expired one.
363
+ */
364
+ export type UnlockAccountResult = {
365
+ status: "success";
366
+ userId: string;
367
+ } | {
368
+ status: "expired";
369
+ } | {
370
+ status: "invalid";
371
+ };
372
+ /**
373
+ * Composable own-auth flows. Construct once with your dependencies and call the
374
+ * methods from your routes; the credential form, copy, and session creation stay
375
+ * in your app.
376
+ */
377
+ export declare class IdentityService<User extends IdentityUser> {
378
+ #private;
379
+ /** Wires the user store and optional collaborators; applies the TTL and hasher defaults. */
380
+ constructor(options: IdentityServiceOptions<User>);
381
+ /**
382
+ * Create a user with a hashed password. `profile` is your app's own fields.
383
+ *
384
+ * @throws {IdentityError} `weak_password` when `password` fails the password
385
+ * policy — including the 8–256 character defaults that apply when
386
+ * {@link IdentityServiceOptions.passwordPolicy} is omitted, and a non-string
387
+ * password (the hash would `String`-coerce it).
388
+ */
389
+ signUp(input: {
390
+ password: string;
391
+ profile: Record<string, unknown>;
392
+ }): Promise<User>;
393
+ /**
394
+ * Verify credentials; returns the user, or `null` for an unknown identifier or
395
+ * wrong password (don't reveal which). Establishing a session is your app's
396
+ * job — do it on a non-null result.
397
+ *
398
+ * The throttle window is keyed on the identifier as submitted (trimmed, not
399
+ * case-folded), so pass the same normalized form you resolve accounts by —
400
+ * otherwise casing variants of one account each get their own window, and
401
+ * the identifiers you later hand {@link IdentityService.resetSignInThrottle}
402
+ * won't match the ones that filled it.
403
+ *
404
+ * Every rejection is held to
405
+ * {@link IdentityServiceOptions.failedSignInFloorMs} (250 ms by default),
406
+ * measured from entry, so an unknown identifier, a locked account, a wrong
407
+ * native password, and a wrong password against an imported hash all take the
408
+ * same time — the branch that runs a foreign KDF is not visible from
409
+ * outside. A success returns as soon as it is done.
410
+ *
411
+ * @throws {IdentityError} `rate_limited` (with `retryAfterMs`) when a
412
+ * `rateLimiter` is configured, the identifier's limit is hit, and
413
+ * `protectionMode` is `"enforce"`. Rate-limit rejections throw before the
414
+ * account lookup and are not held to the floor.
415
+ */
416
+ signIn(input: {
417
+ identifier: string;
418
+ password: string;
419
+ }): Promise<User | null>;
420
+ /**
421
+ * Clear the sign-in rate-limit window for one identifier. Call it after a
422
+ * flow that proves account ownership (account unlock, password reset) with
423
+ * each identifier the user signs in with — otherwise the failed attempts
424
+ * that caused the lockout still fill the window and the user's next sign-in
425
+ * is rejected as rate-limited despite being unlocked. No-op without a
426
+ * `rateLimiter`.
427
+ */
428
+ resetSignInThrottle(identifier: string): Promise<void>;
429
+ /**
430
+ * Enumeration-safe: always resolves or throws identically whether or not the
431
+ * email maps to a user. If it does, mints a single-use reset token and calls
432
+ * `delivery.sendPasswordReset`. With a `rateLimiter`, requests throttle per
433
+ * target email, case-folded so casing variants share one window — the check
434
+ * runs before the lookup, so a 429 reveals nothing —
435
+ * and throw {@link IdentityError} `rate_limited` when exceeded; catch it and
436
+ * return your uniform success response. Give it a tighter threshold than
437
+ * sign-in via `rateLimiters.passwordReset`.
438
+ */
439
+ requestPasswordReset(email: string): Promise<void>;
440
+ /**
441
+ * Consume a reset token, set the new password, and (if a `sessions` service
442
+ * was configured) revoke the user's other sessions. Clears any failed-attempt
443
+ * lockout — the emailed token proves the same account ownership the unlock
444
+ * flow does. Returns `{ userId }`, or `null` for an invalid/expired/used
445
+ * token.
446
+ *
447
+ * A reset is the user's "lock everyone else out" action, so the outstanding
448
+ * passwordless credentials for the same account are voided too: sign-in links
449
+ * (needs a token store with `deleteBySubject` — without it they stay
450
+ * redeemable until they expire) and, when an `otp` service is configured, the
451
+ * pending sign-in code. Neither can fail the reset: a store that throws is
452
+ * logged and the reset still completes, since the password has already
453
+ * changed by then.
454
+ *
455
+ * Sessions are revoked **after** the password is changed. If that revocation
456
+ * throws, the reset is reported failed — a `password_reset.failed`
457
+ * (`session_revocation_failed`) event fires, no `password_reset.completed`
458
+ * fires, and the error rethrows — rather than silently returning success with
459
+ * the user's old sessions still live. Retry the reset to clear them.
460
+ *
461
+ * @throws {IdentityError} `weak_password` when `password` fails the password
462
+ * policy — including the 8–256 character defaults that apply when
463
+ * {@link IdentityServiceOptions.passwordPolicy} is omitted. The token is left
464
+ * unconsumed, so the user's link still works.
465
+ */
466
+ resetPassword(input: {
467
+ token: string;
468
+ password: string;
469
+ }): Promise<{
470
+ userId: string;
471
+ } | null>;
472
+ /**
473
+ * Mint + deliver an email-verification link for a user. Typically called
474
+ * right after sign-up, or from an authenticated "resend" action — not exposed
475
+ * as an unauthenticated route (you'd be emailing arbitrary user ids). With a
476
+ * `rateLimiter` (or a tighter `rateLimiters.emailVerification`), requests
477
+ * throttle per user and throw {@link IdentityError} `rate_limited` when
478
+ * exceeded — surface it as a friendly cooldown.
479
+ */
480
+ requestEmailVerification(input: {
481
+ userId: string;
482
+ email: string;
483
+ }): Promise<void>;
484
+ /**
485
+ * Consume a verification token and mark the user's email verified.
486
+ *
487
+ * Returns a discriminated {@link VerifyEmailResult} so the UI can tell an
488
+ * **expired** link (offer to resend) from a generically **invalid** one — the
489
+ * `inspect()` distinction, surfaced through the flow. A `valid` token is
490
+ * consumed; a lost race (consumed between inspect and consume) reports
491
+ * `invalid`.
492
+ *
493
+ * The email is marked verified **before** the token is consumed, so a throw
494
+ * from `markEmailVerified` leaves the single-use link unspent and the user
495
+ * can retry with the same link (`markEmailVerified` must be idempotent).
496
+ *
497
+ * The address the token was issued for is passed to
498
+ * {@link IdentityUserStore.markEmailVerified} alongside the user id, so a
499
+ * store that predicates on both never verifies an address the link was not
500
+ * minted for.
501
+ */
502
+ verifyEmail(token: string): Promise<VerifyEmailResult>;
503
+ /**
504
+ * Mint + deliver a single-use account-unlock link after a lockout. Call it
505
+ * with the locked account's email (typically from your `lockout` event
506
+ * handler — the service only knows opaque user ids). Requires `tokens` and
507
+ * a `delivery.sendAccountUnlock` hook to actually send. With a `rateLimiter`
508
+ * (or a tighter `rateLimiters.accountUnlock`), requests throttle per user and
509
+ * throw {@link IdentityError} `rate_limited` when exceeded.
510
+ */
511
+ requestAccountUnlock(input: {
512
+ userId: string;
513
+ email: string;
514
+ }): Promise<void>;
515
+ /**
516
+ * Consume an unlock token and clear the account's lockout state (failures
517
+ * and lock). The self-service unlock path: the emailed link lands here.
518
+ */
519
+ unlockAccount(token: string): Promise<UnlockAccountResult>;
520
+ /**
521
+ * Passwordless request: always resolves with the same `void` result. If the
522
+ * email maps to a user, mints a single-use sign-in token (invalidating any
523
+ * outstanding one) and calls `delivery.sendSignInLink`; an unknown email does
524
+ * neither, so the **return value** never reveals whether an account exists.
525
+ * The synchronous path is not fully timing-uniform, though — only the
526
+ * known-email branch awaits token minting and delivery — so send email from a
527
+ * background queue and apply IP-level throttling at the route to close the
528
+ * residual latency/side-channel oracle. Throttled per email (case-folded,
529
+ * key `pwless:<email>`) when a `rateLimiter` — or a tighter
530
+ * `rateLimiters.signInLink` — is configured; throws {@link IdentityError}
531
+ * `rate_limited` in enforce mode. Default link lifetime is 15 minutes.
532
+ */
533
+ requestSignInLink(email: string, options?: {
534
+ ttlMs?: number;
535
+ }): Promise<void>;
536
+ /**
537
+ * Consume a sign-in link token (single-use). `success` carries the `userId`
538
+ * to sign in; establishing the session — and running your MFA gate first —
539
+ * stays your app's job. So does re-resolving the user: a user deleted or
540
+ * disabled since the link was minted must be treated as `invalid` by your
541
+ * user store, not signed in. `expired` and `invalid` are distinguished so
542
+ * the UI can offer a fresh link.
543
+ */
544
+ consumeSignInLink(token: string): Promise<ConsumeSignInLinkResult>;
545
+ /**
546
+ * Passwordless request: always resolves with the same `void` result. If the
547
+ * email maps to a user, mints a one-time numeric code (invalidating any
548
+ * outstanding one) and calls `delivery.sendSignInCode`; an unknown email does
549
+ * neither, so the **return value** never reveals whether an account exists.
550
+ * As with {@link IdentityService.requestSignInLink}, only the known-email
551
+ * branch awaits code minting and delivery, so send from a background queue
552
+ * and throttle by IP at the route to close the residual timing oracle.
553
+ * Requires the `otp` option. Throttled per email (case-folded, key
554
+ * `otp:signin:<email>`, shared with {@link IdentityService.verifySignInCode})
555
+ * when a `rateLimiter` — or a tighter `rateLimiters.signInCode` — is
556
+ * configured; throws {@link IdentityError} `rate_limited` in enforce mode.
557
+ * That is the flow's only throttle, and it runs before the lookup, so a
558
+ * known email can never be rate-limited on a request an unknown one survives.
559
+ * A throwing `sendSignInCode` is trapped like the link hooks (see
560
+ * {@link DeliveryHooks}): that exact code is invalidated — never a newer one a
561
+ * retry may have delivered meanwhile — a `delivery.failed` event is emitted,
562
+ * and the call still resolves `void`, so a mailer outage is not an enumeration
563
+ * oracle either.
564
+ */
565
+ requestSignInCode(email: string): Promise<void>;
566
+ /**
567
+ * Verify a one-time sign-in code. An unknown email performs the same hash
568
+ * work as a known one and reports plain `invalid` — the result is not an
569
+ * enumeration oracle. Wrong tries spend the code's attempt budget (`locked`
570
+ * once it runs out); success consumes the code (single-use), resets the
571
+ * flow's throttle window, and carries the `userId` to sign in — session
572
+ * creation and your MFA gate stay your app's job, as does treating a
573
+ * since-deleted/disabled user as a failed sign-in.
574
+ */
575
+ verifySignInCode(input: {
576
+ email: string;
577
+ code: string;
578
+ }): Promise<VerifySignInCodeResult>;
579
+ }