better-auth 1.7.0-beta.5 → 1.7.0-beta.7

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 (272) hide show
  1. package/dist/_virtual/_rolldown/runtime.mjs +1 -10
  2. package/dist/api/index.d.mts +3 -3
  3. package/dist/api/index.mjs +4 -5
  4. package/dist/api/middlewares/origin-check.mjs +5 -1
  5. package/dist/api/rate-limiter/index.mjs +213 -95
  6. package/dist/api/routes/account.mjs +29 -11
  7. package/dist/api/routes/callback.mjs +13 -5
  8. package/dist/api/routes/email-verification.mjs +19 -6
  9. package/dist/api/routes/index.d.mts +1 -1
  10. package/dist/api/routes/password.mjs +3 -4
  11. package/dist/api/routes/session.d.mts +12 -1
  12. package/dist/api/routes/session.mjs +94 -83
  13. package/dist/api/routes/sign-in.mjs +10 -7
  14. package/dist/api/routes/sign-up.mjs +2 -2
  15. package/dist/api/routes/update-session.mjs +2 -3
  16. package/dist/api/routes/update-user.mjs +10 -12
  17. package/dist/auth/base.mjs +11 -7
  18. package/dist/client/config.d.mts +88 -0
  19. package/dist/client/equality.d.mts +19 -0
  20. package/dist/client/equality.mjs +42 -0
  21. package/dist/client/index.d.mts +5 -4
  22. package/dist/client/index.mjs +2 -1
  23. package/dist/client/lynx/index.d.mts +21 -118
  24. package/dist/client/path-to-object.d.mts +5 -2
  25. package/dist/client/plugins/index.d.mts +4 -3
  26. package/dist/client/plugins/index.mjs +4 -2
  27. package/dist/client/query.d.mts +4 -3
  28. package/dist/client/query.mjs +27 -17
  29. package/dist/client/react/index.d.mts +21 -118
  30. package/dist/client/session-atom.d.mts +11 -0
  31. package/dist/client/session-atom.mjs +129 -4
  32. package/dist/client/session-refresh.d.mts +3 -18
  33. package/dist/client/session-refresh.mjs +38 -49
  34. package/dist/client/solid/index.d.mts +20 -112
  35. package/dist/client/svelte/index.d.mts +21 -118
  36. package/dist/client/types.d.mts +27 -16
  37. package/dist/client/vanilla.d.mts +20 -118
  38. package/dist/client/vue/index.d.mts +37 -145
  39. package/dist/context/create-context.mjs +14 -2
  40. package/dist/context/helpers.mjs +5 -4
  41. package/dist/context/store-capabilities.mjs +12 -0
  42. package/dist/cookies/index.d.mts +7 -0
  43. package/dist/cookies/index.mjs +49 -19
  44. package/dist/cookies/session-store.d.mts +0 -17
  45. package/dist/cookies/session-store.mjs +42 -51
  46. package/dist/db/internal-adapter.mjs +43 -13
  47. package/dist/index.d.mts +2 -2
  48. package/dist/index.mjs +2 -2
  49. package/dist/oauth2/errors.mjs +1 -0
  50. package/dist/oauth2/index.d.mts +2 -2
  51. package/dist/oauth2/index.mjs +2 -2
  52. package/dist/oauth2/state.d.mts +14 -1
  53. package/dist/oauth2/state.mjs +13 -2
  54. package/dist/{packages/better-auth/package.mjs → package.mjs} +1 -1
  55. package/dist/plugins/access/access.mjs +49 -19
  56. package/dist/plugins/admin/routes.mjs +10 -3
  57. package/dist/plugins/captcha/constants.mjs +8 -1
  58. package/dist/plugins/captcha/index.mjs +17 -13
  59. package/dist/plugins/captcha/types.d.mts +25 -0
  60. package/dist/plugins/captcha/verify-handlers/captchafox.mjs +2 -0
  61. package/dist/plugins/captcha/verify-handlers/cloudflare-turnstile.mjs +7 -2
  62. package/dist/plugins/captcha/verify-handlers/google-recaptcha.mjs +7 -2
  63. package/dist/plugins/captcha/verify-handlers/h-captcha.mjs +2 -0
  64. package/dist/plugins/device-authorization/index.d.mts +3 -0
  65. package/dist/plugins/device-authorization/routes.mjs +123 -100
  66. package/dist/plugins/email-otp/index.mjs +1 -1
  67. package/dist/plugins/email-otp/otp-token.mjs +1 -1
  68. package/dist/plugins/email-otp/routes.mjs +23 -53
  69. package/dist/plugins/generic-oauth/index.d.mts +2 -2
  70. package/dist/plugins/generic-oauth/index.mjs +26 -17
  71. package/dist/plugins/generic-oauth/types.d.mts +43 -4
  72. package/dist/plugins/haveibeenpwned/index.d.mts +1 -1
  73. package/dist/plugins/haveibeenpwned/index.mjs +5 -1
  74. package/dist/plugins/index.d.mts +7 -6
  75. package/dist/plugins/index.mjs +6 -5
  76. package/dist/plugins/jwt/adapter.mjs +21 -2
  77. package/dist/plugins/jwt/cookie-cache.mjs +117 -0
  78. package/dist/plugins/jwt/index.d.mts +8 -0
  79. package/dist/plugins/jwt/index.mjs +6 -6
  80. package/dist/plugins/jwt/schema.d.mts +8 -0
  81. package/dist/plugins/jwt/schema.mjs +8 -0
  82. package/dist/plugins/jwt/sign.d.mts +51 -2
  83. package/dist/plugins/jwt/sign.mjs +52 -6
  84. package/dist/plugins/jwt/types.d.mts +36 -0
  85. package/dist/plugins/jwt/utils.mjs +6 -3
  86. package/dist/plugins/last-login-method/client.d.mts +10 -0
  87. package/dist/plugins/last-login-method/client.mjs +4 -1
  88. package/dist/plugins/multi-session/index.mjs +7 -5
  89. package/dist/plugins/oauth-popup/client.d.mts +82 -0
  90. package/dist/plugins/oauth-popup/client.mjs +203 -0
  91. package/dist/plugins/oauth-popup/constants.d.mts +11 -0
  92. package/dist/plugins/oauth-popup/constants.mjs +11 -0
  93. package/dist/plugins/oauth-popup/error-codes.d.mts +11 -0
  94. package/dist/plugins/oauth-popup/error-codes.mjs +10 -0
  95. package/dist/plugins/oauth-popup/index.d.mts +67 -0
  96. package/dist/plugins/oauth-popup/index.mjs +232 -0
  97. package/dist/plugins/oauth-popup/types.d.mts +30 -0
  98. package/dist/plugins/oauth-proxy/index.mjs +3 -3
  99. package/dist/plugins/oauth-proxy/utils.mjs +16 -2
  100. package/dist/plugins/one-tap/client.mjs +12 -6
  101. package/dist/plugins/one-tap/index.d.mts +1 -2
  102. package/dist/plugins/one-tap/index.mjs +13 -8
  103. package/dist/plugins/one-time-token/index.mjs +1 -3
  104. package/dist/plugins/open-api/generator.d.mts +67 -58
  105. package/dist/plugins/open-api/generator.mjs +241 -107
  106. package/dist/plugins/open-api/index.d.mts +2 -2
  107. package/dist/plugins/organization/adapter.d.mts +33 -7
  108. package/dist/plugins/organization/adapter.mjs +219 -44
  109. package/dist/plugins/organization/client.d.mts +4 -4
  110. package/dist/plugins/organization/organization.mjs +16 -0
  111. package/dist/plugins/organization/routes/crud-access-control.mjs +1 -1
  112. package/dist/plugins/organization/routes/crud-invites.mjs +49 -33
  113. package/dist/plugins/organization/routes/crud-members.mjs +59 -6
  114. package/dist/plugins/organization/routes/crud-team.d.mts +5 -8
  115. package/dist/plugins/organization/routes/crud-team.mjs +40 -3
  116. package/dist/plugins/organization/schema.d.mts +14 -0
  117. package/dist/plugins/organization/types.d.mts +2 -2
  118. package/dist/plugins/phone-number/index.d.mts +12 -0
  119. package/dist/plugins/phone-number/index.mjs +2 -1
  120. package/dist/plugins/phone-number/routes.mjs +80 -44
  121. package/dist/plugins/siwe/index.mjs +2 -3
  122. package/dist/plugins/two-factor/backup-codes/index.mjs +5 -4
  123. package/dist/plugins/two-factor/otp/index.mjs +11 -13
  124. package/dist/plugins/two-factor/totp/index.mjs +1 -1
  125. package/dist/plugins/two-factor/verify-two-factor.mjs +6 -2
  126. package/dist/plugins/username/index.mjs +6 -6
  127. package/dist/state.d.mts +6 -0
  128. package/dist/state.mjs +3 -1
  129. package/dist/test-utils/http-test-instance.d.mts +9 -3
  130. package/dist/test-utils/http-test-instance.mjs +49 -8
  131. package/dist/test-utils/test-instance.d.mts +3 -16135
  132. package/dist/utils/index.d.mts +1 -1
  133. package/dist/version.mjs +1 -1
  134. package/package.json +10 -35
  135. package/dist/node_modules/.pnpm/clipboardy@4.0.0/node_modules/clipboardy/index.mjs +0 -32
  136. package/dist/node_modules/.pnpm/clipboardy@4.0.0/node_modules/clipboardy/lib/linux.mjs +0 -55
  137. package/dist/node_modules/.pnpm/clipboardy@4.0.0/node_modules/clipboardy/lib/macos.mjs +0 -26
  138. package/dist/node_modules/.pnpm/clipboardy@4.0.0/node_modules/clipboardy/lib/termux.mjs +0 -39
  139. package/dist/node_modules/.pnpm/clipboardy@4.0.0/node_modules/clipboardy/lib/windows.mjs +0 -19
  140. package/dist/node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/chunks/prompt.mjs +0 -845
  141. package/dist/node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/core.mjs +0 -386
  142. package/dist/node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/index.mjs +0 -320
  143. package/dist/node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/shared/consola.DRwqZj3T.mjs +0 -62
  144. package/dist/node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/shared/consola.DXBYu-KD.mjs +0 -190
  145. package/dist/node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/utils.mjs +0 -2
  146. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/index.mjs +0 -29
  147. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/enoent.mjs +0 -42
  148. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.mjs +0 -67
  149. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/escape.mjs +0 -23
  150. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.mjs +0 -22
  151. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.mjs +0 -36
  152. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/adapters/node.d.mts +0 -292
  153. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/adapters/node.mjs +0 -127
  154. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/index.d.mts +0 -145
  155. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/shared/crossws.BQXMA5bH.d.mts +0 -298
  156. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/shared/crossws.By9qWDAI.mjs +0 -9
  157. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/shared/crossws.CipVM6lf.mjs +0 -3549
  158. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/shared/crossws.D9ehKjSh.mjs +0 -66
  159. package/dist/node_modules/.pnpm/crossws@0.3.5/node_modules/crossws/dist/shared/crossws.DfCzGthR.mjs +0 -227
  160. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/index.mjs +0 -224
  161. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/command.mjs +0 -52
  162. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/error.mjs +0 -54
  163. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/kill.mjs +0 -62
  164. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/pipe.mjs +0 -26
  165. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/promise.mjs +0 -32
  166. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/stdio.mjs +0 -19
  167. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/stream.mjs +0 -98
  168. package/dist/node_modules/.pnpm/execa@8.0.1/node_modules/execa/lib/verbose.mjs +0 -15
  169. package/dist/node_modules/.pnpm/get-port-please@3.2.0/node_modules/get-port-please/dist/index.d.mts +0 -15
  170. package/dist/node_modules/.pnpm/get-port-please@3.2.0/node_modules/get-port-please/dist/index.mjs +0 -220
  171. package/dist/node_modules/.pnpm/get-stream@8.0.1/node_modules/get-stream/source/array-buffer.mjs +0 -54
  172. package/dist/node_modules/.pnpm/get-stream@8.0.1/node_modules/get-stream/source/array.mjs +0 -2
  173. package/dist/node_modules/.pnpm/get-stream@8.0.1/node_modules/get-stream/source/buffer.mjs +0 -14
  174. package/dist/node_modules/.pnpm/get-stream@8.0.1/node_modules/get-stream/source/contents.mjs +0 -76
  175. package/dist/node_modules/.pnpm/get-stream@8.0.1/node_modules/get-stream/source/index.mjs +0 -6
  176. package/dist/node_modules/.pnpm/get-stream@8.0.1/node_modules/get-stream/source/string.mjs +0 -35
  177. package/dist/node_modules/.pnpm/get-stream@8.0.1/node_modules/get-stream/source/utils.mjs +0 -10
  178. package/dist/node_modules/.pnpm/http-shutdown@1.2.2/node_modules/http-shutdown/index.mjs +0 -76
  179. package/dist/node_modules/.pnpm/human-signals@5.0.0/node_modules/human-signals/build/src/core.mjs +0 -274
  180. package/dist/node_modules/.pnpm/human-signals@5.0.0/node_modules/human-signals/build/src/main.mjs +0 -44
  181. package/dist/node_modules/.pnpm/human-signals@5.0.0/node_modules/human-signals/build/src/realtime.mjs +0 -15
  182. package/dist/node_modules/.pnpm/human-signals@5.0.0/node_modules/human-signals/build/src/signals.mjs +0 -23
  183. package/dist/node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.mjs +0 -24
  184. package/dist/node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.mjs +0 -18
  185. package/dist/node_modules/.pnpm/is-stream@3.0.0/node_modules/is-stream/index.mjs +0 -9
  186. package/dist/node_modules/.pnpm/is-wsl@3.1.1/node_modules/is-wsl/index.mjs +0 -20
  187. package/dist/node_modules/.pnpm/is64bit@2.0.0/node_modules/is64bit/index.mjs +0 -13
  188. package/dist/node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.mjs +0 -47
  189. package/dist/node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/mode.mjs +0 -33
  190. package/dist/node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/windows.mjs +0 -33
  191. package/dist/node_modules/.pnpm/listhen@1.9.0/node_modules/listhen/dist/chunks/xdg-open.mjs +0 -1070
  192. package/dist/node_modules/.pnpm/listhen@1.9.0/node_modules/listhen/dist/index.mjs +0 -619
  193. package/dist/node_modules/.pnpm/listhen@1.9.0/node_modules/listhen/dist/shared/listhen.1c46e31d.d.mts +0 -83
  194. package/dist/node_modules/.pnpm/merge-stream@2.0.0/node_modules/merge-stream/index.mjs +0 -38
  195. package/dist/node_modules/.pnpm/mimic-fn@4.0.0/node_modules/mimic-fn/index.mjs +0 -38
  196. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/aes.mjs +0 -597
  197. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/aesCipherSuites.mjs +0 -195
  198. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/asn1-validator.mjs +0 -76
  199. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/asn1.mjs +0 -967
  200. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/baseN.mjs +0 -137
  201. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/cipher.mjs +0 -186
  202. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/cipherModes.mjs +0 -597
  203. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/des.mjs +0 -1187
  204. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/ed25519.mjs +0 -1029
  205. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/forge.mjs +0 -15
  206. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/hmac.mjs +0 -107
  207. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/index.mjs +0 -66
  208. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/jsbn.mjs +0 -1334
  209. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/kem.mjs +0 -146
  210. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/log.mjs +0 -241
  211. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/md.all.mjs +0 -24
  212. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/md.mjs +0 -18
  213. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/md5.mjs +0 -324
  214. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/mgf.mjs +0 -20
  215. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/mgf1.mjs +0 -44
  216. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/oids.mjs +0 -154
  217. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pbe.mjs +0 -815
  218. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pbkdf2.mjs +0 -125
  219. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pem.mjs +0 -175
  220. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pkcs1.mjs +0 -200
  221. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pkcs12.mjs +0 -724
  222. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pkcs7.mjs +0 -642
  223. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pkcs7asn1.mjs +0 -405
  224. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pki.mjs +0 -101
  225. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/prime.mjs +0 -193
  226. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/prng.mjs +0 -290
  227. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/pss.mjs +0 -141
  228. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/random.mjs +0 -141
  229. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/rc2.mjs +0 -538
  230. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/rsa.mjs +0 -1309
  231. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/sha1.mjs +0 -230
  232. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/sha256.mjs +0 -267
  233. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/sha512.mjs +0 -413
  234. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/ssh.mjs +0 -194
  235. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/tls.mjs +0 -3655
  236. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/util.mjs +0 -2117
  237. package/dist/node_modules/.pnpm/node-forge@1.4.0/node_modules/node-forge/lib/x509.mjs +0 -2168
  238. package/dist/node_modules/.pnpm/npm-run-path@5.3.0/node_modules/npm-run-path/index.mjs +0 -34
  239. package/dist/node_modules/.pnpm/onetime@6.0.0/node_modules/onetime/index.mjs +0 -26
  240. package/dist/node_modules/.pnpm/path-key@3.1.1/node_modules/path-key/index.mjs +0 -14
  241. package/dist/node_modules/.pnpm/path-key@4.0.0/node_modules/path-key/index.mjs +0 -8
  242. package/dist/node_modules/.pnpm/pathe@1.1.2/node_modules/pathe/dist/shared/pathe.ff20891b.mjs +0 -176
  243. package/dist/node_modules/.pnpm/shebang-command@2.0.0/node_modules/shebang-command/index.mjs +0 -17
  244. package/dist/node_modules/.pnpm/shebang-regex@3.0.0/node_modules/shebang-regex/index.mjs +0 -8
  245. package/dist/node_modules/.pnpm/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/index.mjs +0 -169
  246. package/dist/node_modules/.pnpm/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/signals.mjs +0 -33
  247. package/dist/node_modules/.pnpm/std-env@3.10.0/node_modules/std-env/dist/index.mjs +0 -171
  248. package/dist/node_modules/.pnpm/strip-final-newline@3.0.0/node_modules/strip-final-newline/index.mjs +0 -10
  249. package/dist/node_modules/.pnpm/system-architecture@0.1.0/node_modules/system-architecture/index.mjs +0 -16
  250. package/dist/node_modules/.pnpm/uncrypto@0.1.3/node_modules/uncrypto/dist/crypto.node.mjs +0 -7
  251. package/dist/node_modules/.pnpm/untun@0.1.3/node_modules/untun/dist/chunks/index.mjs +0 -154
  252. package/dist/node_modules/.pnpm/untun@0.1.3/node_modules/untun/dist/index.mjs +0 -34
  253. package/dist/node_modules/.pnpm/uqr@0.1.2/node_modules/uqr/dist/index.mjs +0 -896
  254. package/dist/node_modules/.pnpm/which@2.0.2/node_modules/which/which.mjs +0 -76
  255. package/dist/plugins/mcp/authorize.mjs +0 -134
  256. package/dist/plugins/mcp/client/adapters.d.mts +0 -56
  257. package/dist/plugins/mcp/client/adapters.mjs +0 -117
  258. package/dist/plugins/mcp/client/index.d.mts +0 -44
  259. package/dist/plugins/mcp/client/index.mjs +0 -152
  260. package/dist/plugins/mcp/index.d.mts +0 -457
  261. package/dist/plugins/mcp/index.mjs +0 -770
  262. package/dist/plugins/oidc-provider/authorize.mjs +0 -204
  263. package/dist/plugins/oidc-provider/client.d.mts +0 -16
  264. package/dist/plugins/oidc-provider/client.mjs +0 -15
  265. package/dist/plugins/oidc-provider/error.mjs +0 -24
  266. package/dist/plugins/oidc-provider/index.d.mts +0 -705
  267. package/dist/plugins/oidc-provider/index.mjs +0 -1122
  268. package/dist/plugins/oidc-provider/schema.d.mts +0 -159
  269. package/dist/plugins/oidc-provider/schema.mjs +0 -129
  270. package/dist/plugins/oidc-provider/types.d.mts +0 -517
  271. package/dist/plugins/oidc-provider/utils/prompt.mjs +0 -16
  272. package/dist/plugins/oidc-provider/utils.mjs +0 -12
@@ -1,12 +1,8 @@
1
- import { createRequire } from "node:module";
2
1
  //#region \0rolldown/runtime.js
3
- var __create = Object.create;
4
2
  var __defProp = Object.defineProperty;
5
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
10
6
  var __exportAll = (all, no_symbols) => {
11
7
  let target = {};
12
8
  for (var name in all) __defProp(target, name, {
@@ -27,10 +23,5 @@ var __copyProps = (to, from, except, desc) => {
27
23
  return to;
28
24
  };
29
25
  var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
30
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
31
- value: mod,
32
- enumerable: true
33
- }) : target, mod));
34
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
35
26
  //#endregion
36
- export { __commonJSMin, __exportAll, __reExport, __require, __toESM };
27
+ export { __exportAll, __reExport };
@@ -11,7 +11,7 @@ import { createEmailVerificationToken, sendVerificationEmail, sendVerificationEm
11
11
  import { error } from "./routes/error.mjs";
12
12
  import { ok } from "./routes/ok.mjs";
13
13
  import { requestPasswordReset, requestPasswordResetCallback, resetPassword, verifyPassword } from "./routes/password.mjs";
14
- import { freshSessionMiddleware, getSession, getSessionFromCtx, listSessions, requestOnlySessionMiddleware, revokeOtherSessions, revokeSession, revokeSessions, sensitiveSessionMiddleware, sessionMiddleware } from "./routes/session.mjs";
14
+ import { freshSessionMiddleware, getSession, getSessionFromCtx, isStateful, listSessions, requestOnlySessionMiddleware, revokeOtherSessions, revokeSession, revokeSessions, sensitiveSessionMiddleware, sessionMiddleware } from "./routes/session.mjs";
15
15
  import { signInEmail, signInSocial } from "./routes/sign-in.mjs";
16
16
  import { signOut } from "./routes/sign-out.mjs";
17
17
  import { signUpEmail } from "./routes/sign-up.mjs";
@@ -25,7 +25,7 @@ import { InternalLogger } from "@better-auth/core/env";
25
25
  import { APIError } from "@better-auth/core/error";
26
26
  import * as _better_auth_core_oauth20 from "@better-auth/core/oauth2";
27
27
  import * as better_call0 from "better-call";
28
- import { AuthEndpoint, AuthMiddleware, createAuthEndpoint, createAuthMiddleware, optionsMiddleware } from "@better-auth/core/api";
28
+ import { AuthEndpoint, AuthMiddleware, NO_STORE_HEADERS, createAuthEndpoint, createAuthMiddleware, optionsMiddleware } from "@better-auth/core/api";
29
29
  import * as zod from "zod";
30
30
  import * as zod_v4_core0 from "zod/v4/core";
31
31
 
@@ -3989,4 +3989,4 @@ declare const router: <Option extends BetterAuthOptions>(ctx: AuthContext, optio
3989
3989
  } extends infer T_2 ? { [K in keyof T_2 as K extends keyof T_1 ? never : K]: T_2[K] } : never) & T_1> : never : never : never;
3990
3990
  };
3991
3991
  //#endregion
3992
- export { APIError, type AuthEndpoint, type AuthMiddleware, type DispatchContext, accountInfo, addOAuthServerContext, callbackOAuth, changeEmail, changePassword, checkEndpointConflicts, createAuthEndpoint, createAuthMiddleware, createEmailVerificationToken, deleteUser, deleteUserCallback, dispatchAuthEndpoint, error, formCsrfMiddleware, freshSessionMiddleware, getAccessToken, getEndpoints, getIp, getOAuthState, getSession, getSessionFromCtx, getShouldSkipSessionRefresh, isAPIError, linkSocialAccount, listSessions, listUserAccounts, ok, optionsMiddleware, originCheck, originCheckMiddleware, refreshToken, requestOnlySessionMiddleware, requestPasswordReset, requestPasswordResetCallback, requireOrgRole, requireResourceOwnership, resetPassword, revokeOtherSessions, revokeSession, revokeSessions, router, sendVerificationEmail, sendVerificationEmailFn, sensitiveSessionMiddleware, sessionMiddleware, setPassword, setShouldSkipSessionRefresh, signInEmail, signInSocial, signOut, signUpEmail, unlinkAccount, updateSession, updateUser, verifyEmail, verifyPassword };
3992
+ export { APIError, type AuthEndpoint, type AuthMiddleware, type DispatchContext, NO_STORE_HEADERS, accountInfo, addOAuthServerContext, callbackOAuth, changeEmail, changePassword, checkEndpointConflicts, createAuthEndpoint, createAuthMiddleware, createEmailVerificationToken, deleteUser, deleteUserCallback, dispatchAuthEndpoint, error, formCsrfMiddleware, freshSessionMiddleware, getAccessToken, getEndpoints, getIp, getOAuthState, getSession, getSessionFromCtx, getShouldSkipSessionRefresh, isAPIError, isStateful, linkSocialAccount, listSessions, listUserAccounts, ok, optionsMiddleware, originCheck, originCheckMiddleware, refreshToken, requestOnlySessionMiddleware, requestPasswordReset, requestPasswordResetCallback, requireOrgRole, requireResourceOwnership, resetPassword, revokeOtherSessions, revokeSession, revokeSessions, router, sendVerificationEmail, sendVerificationEmailFn, sensitiveSessionMiddleware, sessionMiddleware, setPassword, setShouldSkipSessionRefresh, signInEmail, signInSocial, signOut, signUpEmail, unlinkAccount, updateSession, updateUser, verifyEmail, verifyPassword };
@@ -2,10 +2,10 @@ import { isAPIError } from "../utils/is-api-error.mjs";
2
2
  import { requireOrgRole, requireResourceOwnership } from "./middlewares/authorization.mjs";
3
3
  import { formCsrfMiddleware, originCheck, originCheckMiddleware } from "./middlewares/origin-check.mjs";
4
4
  import { getIp } from "../utils/get-request-ip.mjs";
5
- import { onRequestRateLimit, onResponseRateLimit } from "./rate-limiter/index.mjs";
5
+ import { onRequestRateLimit } from "./rate-limiter/index.mjs";
6
6
  import { addOAuthServerContext, getOAuthState } from "./state/oauth.mjs";
7
7
  import { getShouldSkipSessionRefresh, setShouldSkipSessionRefresh } from "./state/should-session-refresh.mjs";
8
- import { freshSessionMiddleware, getSession, getSessionFromCtx, listSessions, requestOnlySessionMiddleware, revokeOtherSessions, revokeSession, revokeSessions, sensitiveSessionMiddleware, sessionMiddleware } from "./routes/session.mjs";
8
+ import { freshSessionMiddleware, getSession, getSessionFromCtx, isStateful, listSessions, requestOnlySessionMiddleware, revokeOtherSessions, revokeSession, revokeSessions, sensitiveSessionMiddleware, sessionMiddleware } from "./routes/session.mjs";
9
9
  import { accountInfo, getAccessToken, linkSocialAccount, listUserAccounts, refreshToken, unlinkAccount } from "./routes/account.mjs";
10
10
  import { callbackOAuth } from "./routes/callback.mjs";
11
11
  import { createEmailVerificationToken, sendVerificationEmail, sendVerificationEmailFn, verifyEmail } from "./routes/email-verification.mjs";
@@ -24,7 +24,7 @@ import { APIError } from "@better-auth/core/error";
24
24
  import { ATTR_CONTEXT, ATTR_HOOK_TYPE, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_HTTP_ROUTE, withSpan } from "@better-auth/core/instrumentation";
25
25
  import { normalizePathname } from "@better-auth/core/utils/url";
26
26
  import { createRouter } from "better-call";
27
- import { createAuthEndpoint, createAuthMiddleware, optionsMiddleware } from "@better-auth/core/api";
27
+ import { NO_STORE_HEADERS, createAuthEndpoint, createAuthMiddleware, optionsMiddleware } from "@better-auth/core/api";
28
28
  //#region src/api/index.ts
29
29
  function checkEndpointConflicts(options, logger) {
30
30
  const endpointRegistry = /* @__PURE__ */ new Map();
@@ -178,7 +178,6 @@ const router = (ctx, options) => {
178
178
  return currentRequest;
179
179
  },
180
180
  async onResponse(res, req) {
181
- await onResponseRateLimit(req, ctx);
182
181
  for (const plugin of ctx.options.plugins || []) if (plugin.onResponse) {
183
182
  const response = await withSpan(`onResponse ${plugin.id}`, {
184
183
  [ATTR_HOOK_TYPE]: "onResponse",
@@ -214,4 +213,4 @@ const router = (ctx, options) => {
214
213
  });
215
214
  };
216
215
  //#endregion
217
- export { APIError, accountInfo, addOAuthServerContext, callbackOAuth, changeEmail, changePassword, checkEndpointConflicts, createAuthEndpoint, createAuthMiddleware, createEmailVerificationToken, deleteUser, deleteUserCallback, dispatchAuthEndpoint, error, formCsrfMiddleware, freshSessionMiddleware, getAccessToken, getEndpoints, getIp, getOAuthState, getSession, getSessionFromCtx, getShouldSkipSessionRefresh, isAPIError, linkSocialAccount, listSessions, listUserAccounts, ok, optionsMiddleware, originCheck, originCheckMiddleware, refreshToken, requestOnlySessionMiddleware, requestPasswordReset, requestPasswordResetCallback, requireOrgRole, requireResourceOwnership, resetPassword, revokeOtherSessions, revokeSession, revokeSessions, router, sendVerificationEmail, sendVerificationEmailFn, sensitiveSessionMiddleware, sessionMiddleware, setPassword, setShouldSkipSessionRefresh, signInEmail, signInSocial, signOut, signUpEmail, unlinkAccount, updateSession, updateUser, verifyEmail, verifyPassword };
216
+ export { APIError, NO_STORE_HEADERS, accountInfo, addOAuthServerContext, callbackOAuth, changeEmail, changePassword, checkEndpointConflicts, createAuthEndpoint, createAuthMiddleware, createEmailVerificationToken, deleteUser, deleteUserCallback, dispatchAuthEndpoint, error, formCsrfMiddleware, freshSessionMiddleware, getAccessToken, getEndpoints, getIp, getOAuthState, getSession, getSessionFromCtx, getShouldSkipSessionRefresh, isAPIError, isStateful, linkSocialAccount, listSessions, listUserAccounts, ok, optionsMiddleware, originCheck, originCheckMiddleware, refreshToken, requestOnlySessionMiddleware, requestPasswordReset, requestPasswordResetCallback, requireOrgRole, requireResourceOwnership, resetPassword, revokeOtherSessions, revokeSession, revokeSessions, router, sendVerificationEmail, sendVerificationEmailFn, sensitiveSessionMiddleware, sessionMiddleware, setPassword, setShouldSkipSessionRefresh, signInEmail, signInSocial, signOut, signUpEmail, unlinkAccount, updateSession, updateUser, verifyEmail, verifyPassword };
@@ -23,7 +23,10 @@ function shouldSkipOriginCheck(ctx) {
23
23
  if (Array.isArray(skipOriginCheck) && ctx.request) try {
24
24
  const basePath = new URL(ctx.context.baseURL).pathname;
25
25
  const currentPath = normalizePathname(ctx.request.url, basePath);
26
- return skipOriginCheck.some((skipPath) => currentPath.startsWith(skipPath));
26
+ return skipOriginCheck.some((skipPath) => {
27
+ const normalizedSkipPath = skipPath.replace(/\/+$/, "");
28
+ return currentPath === normalizedSkipPath || currentPath.startsWith(`${normalizedSkipPath}/`);
29
+ });
27
30
  } catch {}
28
31
  return false;
29
32
  }
@@ -47,6 +50,7 @@ const originCheckMiddleware = createAuthMiddleware(async (ctx) => {
47
50
  const newUserCallbackURL = body?.newUserCallbackURL;
48
51
  const validateURL = (url, label) => {
49
52
  if (!url) return;
53
+ if (typeof url !== "string") throw APIError.fromStatus("BAD_REQUEST", { message: `Invalid ${label}: expected a string` });
50
54
  if (!ctx.context.isTrustedOrigin(url, { allowRelativePaths: label !== "origin" })) {
51
55
  ctx.context.logger.error(`Invalid ${label}: ${url}`);
52
56
  ctx.context.logger.info(`If it's a valid URL, please add ${url} to trustedOrigins in your auth config\n`, `Current list of trustedOrigins: ${ctx.context.trustedOrigins}`);
@@ -1,14 +1,66 @@
1
1
  import { wildcardMatch } from "../../utils/wildcard.mjs";
2
2
  import { getIp } from "../../utils/get-request-ip.mjs";
3
- import { safeJSONParse } from "@better-auth/core/utils/json";
3
+ import { BetterAuthError } from "@better-auth/core/error";
4
4
  import { normalizePathname } from "@better-auth/core/utils/url";
5
5
  import { createRateLimitKey } from "@better-auth/core/utils/ip";
6
6
  //#region src/api/rate-limiter/index.ts
7
7
  const memory = /* @__PURE__ */ new Map();
8
- function shouldRateLimit(max, window, rateLimitData) {
8
+ const MEMORY_STORE_MAX_ENTRIES = 1e5;
9
+ function pruneMemoryStore() {
9
10
  const now = Date.now();
10
- const windowInMs = window * 1e3;
11
- return now - rateLimitData.lastRequest < windowInMs && rateLimitData.count >= max;
11
+ for (const [key, entry] of memory) if (now >= entry.expiresAt) memory.delete(key);
12
+ if (memory.size <= MEMORY_STORE_MAX_ENTRIES) return;
13
+ const overflow = memory.size - MEMORY_STORE_MAX_ENTRIES;
14
+ let removed = 0;
15
+ for (const key of memory.keys()) {
16
+ memory.delete(key);
17
+ if (++removed >= overflow) break;
18
+ }
19
+ }
20
+ /**
21
+ * Decide an atomic rate-limit step against an in-memory `RateLimit` snapshot
22
+ * for the rolling `window` (seconds) and `max`. Shared by the memory backend
23
+ * (read-decide-write is atomic under single-threaded JS) and as the fallback
24
+ * for storages lacking an atomic primitive.
25
+ */
26
+ function decideConsume(data, rule, now) {
27
+ const windowInMs = rule.window * 1e3;
28
+ if (!data) return {
29
+ next: {
30
+ key: "",
31
+ count: 1,
32
+ lastRequest: now
33
+ },
34
+ update: false,
35
+ allowed: true,
36
+ retryAfter: null
37
+ };
38
+ if (now - data.lastRequest >= windowInMs) return {
39
+ next: {
40
+ ...data,
41
+ count: 1,
42
+ lastRequest: now
43
+ },
44
+ update: true,
45
+ allowed: true,
46
+ retryAfter: null
47
+ };
48
+ if (data.count >= rule.max) return {
49
+ next: data,
50
+ update: true,
51
+ allowed: false,
52
+ retryAfter: getRetryAfter(data.lastRequest, rule.window)
53
+ };
54
+ return {
55
+ next: {
56
+ ...data,
57
+ count: data.count + 1,
58
+ lastRequest: now
59
+ },
60
+ update: true,
61
+ allowed: true,
62
+ retryAfter: null
63
+ };
12
64
  }
13
65
  function rateLimitResponse(retryAfter) {
14
66
  return new Response(JSON.stringify({ message: "Too many requests. Please try again later." }), {
@@ -25,94 +77,173 @@ function getRetryAfter(lastRequest, window) {
25
77
  function createDatabaseStorageWrapper(ctx) {
26
78
  const model = "rateLimit";
27
79
  const db = ctx.adapter;
28
- return {
29
- get: async (key) => {
30
- const data = (await db.findMany({
80
+ let longestObservedWindow = Math.max(...getConfiguredRateLimitWindows(ctx));
81
+ const readRow = async (key) => {
82
+ const data = (await db.findMany({
83
+ model,
84
+ where: [{
85
+ field: "key",
86
+ value: key
87
+ }]
88
+ }))[0];
89
+ if (typeof data?.lastRequest === "bigint") data.lastRequest = Number(data.lastRequest);
90
+ return data;
91
+ };
92
+ const consume = async (key, rule) => {
93
+ if (rule.window > longestObservedWindow) longestObservedWindow = rule.window;
94
+ const windowInMs = rule.window * 1e3;
95
+ const data = await readRow(key);
96
+ const now = Date.now();
97
+ if (!data) try {
98
+ await db.create({
99
+ model,
100
+ data: {
101
+ key,
102
+ count: 1,
103
+ lastRequest: now
104
+ }
105
+ });
106
+ return {
107
+ allowed: true,
108
+ retryAfter: null
109
+ };
110
+ } catch (error) {
111
+ if (!await readRow(key)) throw error;
112
+ return consume(key, rule);
113
+ }
114
+ if (now - data.lastRequest >= windowInMs) {
115
+ if (await db.incrementOne({
31
116
  model,
32
117
  where: [{
33
118
  field: "key",
34
119
  value: key
35
- }]
36
- }))[0];
37
- if (typeof data?.lastRequest === "bigint") data.lastRequest = Number(data.lastRequest);
38
- return data;
39
- },
40
- set: async (key, value, _update) => {
41
- try {
42
- if (_update) await db.updateMany({
43
- model,
44
- where: [{
45
- field: "key",
46
- value: key
47
- }],
48
- update: {
49
- count: value.count,
50
- lastRequest: value.lastRequest
51
- }
52
- });
53
- else await db.create({
54
- model,
55
- data: {
56
- key,
57
- count: value.count,
58
- lastRequest: value.lastRequest
59
- }
60
- });
61
- } catch (e) {
62
- ctx.logger.error("Error setting rate limit", e);
120
+ }, {
121
+ field: "lastRequest",
122
+ operator: "lte",
123
+ value: data.lastRequest
124
+ }],
125
+ increment: {},
126
+ set: {
127
+ count: 1,
128
+ lastRequest: now
129
+ }
130
+ })) {
131
+ deleteExpiredRows(now);
132
+ return {
133
+ allowed: true,
134
+ retryAfter: null
135
+ };
63
136
  }
137
+ return consume(key, rule);
64
138
  }
139
+ const windowStart = now - windowInMs;
140
+ if (await db.incrementOne({
141
+ model,
142
+ where: [
143
+ {
144
+ field: "key",
145
+ value: key
146
+ },
147
+ {
148
+ field: "lastRequest",
149
+ operator: "gt",
150
+ value: windowStart
151
+ },
152
+ {
153
+ field: "count",
154
+ operator: "lt",
155
+ value: rule.max
156
+ }
157
+ ],
158
+ increment: { count: 1 },
159
+ set: { lastRequest: now }
160
+ })) return {
161
+ allowed: true,
162
+ retryAfter: null
163
+ };
164
+ const fresh = await readRow(key);
165
+ if (!fresh) return consume(key, rule);
166
+ if (now - fresh.lastRequest >= windowInMs) return consume(key, rule);
167
+ return {
168
+ allowed: false,
169
+ retryAfter: getRetryAfter(fresh.lastRequest, rule.window)
170
+ };
171
+ };
172
+ const deleteExpiredRows = (now) => {
173
+ const cutoff = now - longestObservedWindow * 1e3;
174
+ ctx.runInBackground(db.deleteMany({
175
+ model,
176
+ where: [{
177
+ field: "lastRequest",
178
+ operator: "lt",
179
+ value: cutoff
180
+ }]
181
+ }).then(() => void 0).catch((e) => ctx.logger.error("Error pruning rate limit rows", e)));
65
182
  };
183
+ return { consume };
184
+ }
185
+ function getConfiguredRateLimitWindows(ctx) {
186
+ const windows = [ctx.rateLimit.window, ...getDefaultSpecialRules().map((rule) => rule.window)];
187
+ for (const plugin of ctx.options.plugins || []) if (plugin.rateLimit) windows.push(...plugin.rateLimit.map((rule) => rule.window));
188
+ if (ctx.rateLimit.customRules) {
189
+ for (const customRule of Object.values(ctx.rateLimit.customRules)) if (customRule && typeof customRule !== "function") windows.push(customRule.window);
190
+ }
191
+ const validWindows = windows.filter((window) => Number.isFinite(window) && window > 0);
192
+ return validWindows.length > 0 ? validWindows : [ctx.rateLimit.window];
66
193
  }
67
194
  function getRateLimitStorage(ctx, rateLimitSettings) {
68
195
  if (ctx.options.rateLimit?.customStorage) return ctx.options.rateLimit.customStorage;
69
196
  const storage = ctx.rateLimit.storage;
70
- if (storage === "secondary-storage") return {
71
- get: async (key) => {
72
- const data = await ctx.options.secondaryStorage?.get(key);
73
- return data ? safeJSONParse(data) : null;
74
- },
75
- set: async (key, value, _update) => {
76
- const ttl = rateLimitSettings?.window ?? ctx.options.rateLimit?.window ?? 10;
77
- await ctx.options.secondaryStorage?.set?.(key, JSON.stringify(value), ttl);
78
- }
79
- };
80
- else if (storage === "memory") return {
81
- async get(key) {
197
+ if (storage === "secondary-storage") {
198
+ const ttlFor = (window) => window ?? ctx.options.rateLimit?.window ?? 10;
199
+ const increment = ctx.options.secondaryStorage?.increment;
200
+ if (!increment) throw new BetterAuthError("Secondary-storage rate limiting requires SecondaryStorage.increment.");
201
+ return { consume: async (key, rule) => {
202
+ if (await increment(key, ttlFor(rule.window)) <= rule.max) return {
203
+ allowed: true,
204
+ retryAfter: null
205
+ };
206
+ return {
207
+ allowed: false,
208
+ retryAfter: rule.window
209
+ };
210
+ } };
211
+ } else if (storage === "memory") {
212
+ const ttlFor = (window) => window ?? ctx.options.rateLimit?.window ?? 10;
213
+ return { async consume(key, rule) {
214
+ pruneMemoryStore();
215
+ const now = Date.now();
82
216
  const entry = memory.get(key);
83
- if (!entry) return null;
84
- if (Date.now() >= entry.expiresAt) {
85
- memory.delete(key);
86
- return null;
87
- }
88
- return entry.data;
89
- },
90
- async set(key, value, _update) {
91
- const ttl = rateLimitSettings?.window ?? ctx.options.rateLimit?.window ?? 10;
92
- const expiresAt = Date.now() + ttl * 1e3;
93
- memory.set(key, {
94
- data: value,
95
- expiresAt
217
+ const decision = decideConsume(entry && now < entry.expiresAt ? entry.data : void 0, rule, now);
218
+ if (decision.allowed) memory.set(key, {
219
+ data: {
220
+ ...decision.next,
221
+ key
222
+ },
223
+ expiresAt: now + ttlFor(rule.window) * 1e3
96
224
  });
97
- }
98
- };
225
+ return {
226
+ allowed: decision.allowed,
227
+ retryAfter: decision.retryAfter
228
+ };
229
+ } };
230
+ }
99
231
  return createDatabaseStorageWrapper(ctx);
100
232
  }
101
233
  let ipWarningLogged = false;
234
+ const NO_TRUSTED_IP_KEY = "no-trusted-ip";
102
235
  async function resolveRateLimitConfig(req, ctx) {
103
236
  const basePath = new URL(ctx.baseURL).pathname;
104
237
  const path = normalizePathname(req.url, basePath);
105
238
  let currentWindow = ctx.rateLimit.window;
106
239
  let currentMax = ctx.rateLimit.max;
107
240
  const ip = getIp(req, ctx.options);
108
- if (!ip) {
109
- if (!ipWarningLogged) {
110
- ctx.logger.warn("Rate limiting skipped: could not determine client IP address. Ensure your runtime forwards a trusted client IP header and configure `advanced.ipAddress.ipAddressHeaders` if needed.");
111
- ipWarningLogged = true;
112
- }
113
- return null;
241
+ if (!ip && ctx.options.advanced?.ipAddress?.disableIpTracking) return null;
242
+ if (!ip && !ipWarningLogged) {
243
+ ctx.logger.warn("Rate limiting could not determine a client IP and is falling back to a single shared per-path bucket. Ensure your runtime forwards a trusted client IP header and configure `advanced.ipAddress.ipAddressHeaders` if needed.");
244
+ ipWarningLogged = true;
114
245
  }
115
- const key = createRateLimitKey(ip, path);
246
+ const key = createRateLimitKey(ip ?? NO_TRUSTED_IP_KEY, path);
116
247
  const specialRule = getDefaultSpecialRules().find((rule) => rule.pathMatcher(path));
117
248
  if (specialRule) {
118
249
  currentWindow = specialRule.window;
@@ -150,37 +281,24 @@ async function resolveRateLimitConfig(req, ctx) {
150
281
  currentMax
151
282
  };
152
283
  }
284
+ /**
285
+ * Decides the rate limit for the request in a single atomic step. The whole
286
+ * check-and-increment happens here in the request phase; there is no separate
287
+ * response-phase write-back, so concurrent requests cannot all pass a stale
288
+ * read before any increment lands.
289
+ */
153
290
  async function onRequestRateLimit(req, ctx) {
154
291
  if (!ctx.rateLimit.enabled) return;
155
292
  const config = await resolveRateLimitConfig(req, ctx);
156
293
  if (!config) return;
157
294
  const { key, currentWindow, currentMax } = config;
158
- const data = await getRateLimitStorage(ctx, { window: currentWindow }).get(key);
159
- if (data && shouldRateLimit(currentMax, currentWindow, data)) return rateLimitResponse(getRetryAfter(data.lastRequest, currentWindow));
160
- }
161
- async function onResponseRateLimit(req, ctx) {
162
- if (!ctx.rateLimit.enabled) return;
163
- const config = await resolveRateLimitConfig(req, ctx);
164
- if (!config) return;
165
- const { key, currentWindow } = config;
166
295
  const storage = getRateLimitStorage(ctx, { window: currentWindow });
167
- const data = await storage.get(key);
168
- const now = Date.now();
169
- if (!data) await storage.set(key, {
170
- key,
171
- count: 1,
172
- lastRequest: now
173
- });
174
- else if (now - data.lastRequest > currentWindow * 1e3) await storage.set(key, {
175
- ...data,
176
- count: 1,
177
- lastRequest: now
178
- }, true);
179
- else await storage.set(key, {
180
- ...data,
181
- count: data.count + 1,
182
- lastRequest: now
183
- }, true);
296
+ const rule = {
297
+ window: currentWindow,
298
+ max: currentMax
299
+ };
300
+ const { allowed, retryAfter } = await storage.consume(key, rule);
301
+ if (!allowed) return rateLimitResponse(retryAfter ?? currentWindow);
184
302
  }
185
303
  function getDefaultSpecialRules() {
186
304
  return [{
@@ -198,4 +316,4 @@ function getDefaultSpecialRules() {
198
316
  }];
199
317
  }
200
318
  //#endregion
201
- export { onRequestRateLimit, onResponseRateLimit };
319
+ export { onRequestRateLimit };
@@ -1,3 +1,4 @@
1
+ import { shouldBindAccountCookieToSessionUser } from "../../context/store-capabilities.mjs";
1
2
  import { parseAccountOutput } from "../../db/schema.mjs";
2
3
  import { generateRandomString } from "../../crypto/random.mjs";
3
4
  import { getAccountCookie } from "../../cookies/session-store.mjs";
@@ -6,8 +7,8 @@ import { missingEmailLogMessage } from "../../oauth2/errors.mjs";
6
7
  import { decryptOAuthToken } from "../../oauth2/token-encryption.mjs";
7
8
  import { persistOAuthAccount } from "../../oauth2/persist-account.mjs";
8
9
  import { applyUpdateUserInfoOnLink } from "../../oauth2/resolve-account.mjs";
9
- import { generateState } from "../../oauth2/state.mjs";
10
- import { freshSessionMiddleware, getSessionFromCtx, sessionMiddleware } from "./session.mjs";
10
+ import { generateIdTokenNonce, generateState } from "../../oauth2/state.mjs";
11
+ import { freshSessionMiddleware, getSessionFromCtx, isStateful, sessionMiddleware } from "./session.mjs";
11
12
  import { APIError, BASE_ERROR_CODES } from "@better-auth/core/error";
12
13
  import { additionalAuthorizationParamsSchema, readGrantedScopes, supportsIdTokenSignIn, verifyProviderIdToken } from "@better-auth/core/oauth2";
13
14
  import { SocialProviderListEnum } from "@better-auth/core/social-providers";
@@ -126,7 +127,7 @@ const linkSocialAccount = createAuthEndpoint("/link-social", {
126
127
  }
127
128
  const { token, nonce } = c.body.idToken;
128
129
  if (!await verifyProviderIdToken(provider, token, nonce)) {
129
- c.context.logger.error("Invalid id token", { provider: c.body.provider });
130
+ c.context.logger.warn("Invalid id token", { provider: c.body.provider });
130
131
  throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.INVALID_TOKEN);
131
132
  }
132
133
  const linkingUserInfo = await provider.getUserInfo({
@@ -183,9 +184,11 @@ const linkSocialAccount = createAuthEndpoint("/link-social", {
183
184
  }
184
185
  const stateNonce = generateRandomString(32);
185
186
  const codeVerifier = generateRandomString(128);
187
+ const idTokenNonce = generateIdTokenNonce(provider);
186
188
  const { url, requestedScopes } = await provider.createAuthorizationURL({
187
189
  state: stateNonce,
188
190
  codeVerifier,
191
+ idTokenNonce,
189
192
  redirectURI: `${c.context.baseURL}${provider.callbackPath}`,
190
193
  scopes: c.body.scopes,
191
194
  loginHint: c.body.loginHint,
@@ -199,7 +202,8 @@ const linkSocialAccount = createAuthEndpoint("/link-social", {
199
202
  additionalData: c.body.additionalData,
200
203
  requestedScopes,
201
204
  state: stateNonce,
202
- codeVerifier
205
+ codeVerifier,
206
+ idTokenNonce
203
207
  });
204
208
  if (!c.body.disableRedirect) c.setHeader("Location", url.toString());
205
209
  return c.json({
@@ -250,7 +254,7 @@ const unlinkAccount = createAuthEndpoint("/unlink-account", {
250
254
  * so the cache is left in place for them.
251
255
  */
252
256
  async function resolveUserId(ctx, userId) {
253
- const session = await getSessionFromCtx(ctx, { disableCookieCache: !!ctx.context.options.database || !!ctx.context.options.secondaryStorage });
257
+ const session = await getSessionFromCtx(ctx, { disableCookieCache: isStateful(ctx) });
254
258
  if (!session && (ctx.request || ctx.headers)) throw ctx.error("UNAUTHORIZED");
255
259
  const resolvedUserId = session?.user?.id || userId;
256
260
  if (!resolvedUserId) throw APIError.from("BAD_REQUEST", {
@@ -259,6 +263,9 @@ async function resolveUserId(ctx, userId) {
259
263
  });
260
264
  return resolvedUserId;
261
265
  }
266
+ function matchesAccountSelection(ctx, account, { resolvedUserId, providerId, accountId }) {
267
+ return (!shouldBindAccountCookieToSessionUser(ctx.context.options) || account.userId === resolvedUserId) && (!providerId || providerId === account.providerId) && (!accountId || account.accountId === accountId);
268
+ }
262
269
  /**
263
270
  * Fetches a currently-valid access token for a user's provider account,
264
271
  * refreshing and persisting it when it is within five seconds of expiry.
@@ -274,7 +281,11 @@ async function getValidAccessToken(ctx, { resolvedUserId, providerId, accountId,
274
281
  let account = resolvedAccount;
275
282
  if (!account) {
276
283
  const accountData = await getAccountCookie(ctx);
277
- if (accountData && accountData.userId === resolvedUserId && providerId === accountData.providerId && (!accountId || accountData.accountId === accountId)) account = accountData;
284
+ if (accountData && matchesAccountSelection(ctx, accountData, {
285
+ resolvedUserId,
286
+ providerId,
287
+ accountId
288
+ })) account = accountData;
278
289
  else account = (await ctx.context.internalAdapter.findAccounts(resolvedUserId)).find((acc) => accountId ? acc.accountId === accountId && acc.providerId === providerId : acc.providerId === providerId);
279
290
  }
280
291
  if (!account) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.ACCOUNT_NOT_FOUND);
@@ -283,7 +294,7 @@ async function getValidAccessToken(ctx, { resolvedUserId, providerId, accountId,
283
294
  const accessTokenExpired = account.accessTokenExpiresAt && new Date(account.accessTokenExpiresAt).getTime() - Date.now() < 5e3;
284
295
  if (account.refreshToken && accessTokenExpired && provider.refreshAccessToken) {
285
296
  const refreshToken = await decryptOAuthToken(account.refreshToken, ctx.context);
286
- newTokens = await provider.refreshAccessToken(refreshToken);
297
+ newTokens = await provider.refreshAccessToken(refreshToken, ctx);
287
298
  await persistOAuthAccount(ctx, {
288
299
  userId: account.userId,
289
300
  providerId: account.providerId,
@@ -401,14 +412,18 @@ const refreshToken = createAuthEndpoint("/refresh-token", {
401
412
  });
402
413
  let account = void 0;
403
414
  const accountData = await getAccountCookie(ctx);
404
- if (!!accountData && accountData.userId === resolvedUserId && providerId === accountData.providerId && (!accountId || accountData.accountId === accountId)) account = accountData;
415
+ if (!!accountData && matchesAccountSelection(ctx, accountData, {
416
+ resolvedUserId,
417
+ providerId,
418
+ accountId
419
+ })) account = accountData;
405
420
  else account = (await ctx.context.internalAdapter.findAccounts(resolvedUserId)).find((acc) => accountId ? acc.accountId === accountId && acc.providerId === providerId : acc.providerId === providerId);
406
421
  if (!account) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.ACCOUNT_NOT_FOUND);
407
422
  const refreshToken = account.refreshToken ?? void 0;
408
423
  if (!refreshToken) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.REFRESH_TOKEN_NOT_FOUND);
409
424
  try {
410
425
  const decryptedRefreshToken = await decryptOAuthToken(refreshToken, ctx.context);
411
- const tokens = await provider.refreshAccessToken(decryptedRefreshToken);
426
+ const tokens = await provider.refreshAccessToken(decryptedRefreshToken, ctx);
412
427
  await persistOAuthAccount(ctx, {
413
428
  userId: account.userId,
414
429
  providerId: account.providerId,
@@ -475,7 +490,10 @@ const accountInfo = createAuthEndpoint("/account-info", {
475
490
  if (!providedAccountId) {
476
491
  if (ctx.context.options.account?.storeAccountCookie) {
477
492
  const accountData = await getAccountCookie(ctx);
478
- if (accountData) account = accountData;
493
+ if (accountData && matchesAccountSelection(ctx, accountData, {
494
+ resolvedUserId,
495
+ providerId: providedProviderId
496
+ })) account = accountData;
479
497
  }
480
498
  } else {
481
499
  const matchingAccounts = (await ctx.context.internalAdapter.findAccounts(resolvedUserId)).filter((acc) => acc.accountId === providedAccountId && (!providedProviderId || acc.providerId === providedProviderId));
@@ -485,7 +503,7 @@ const accountInfo = createAuthEndpoint("/account-info", {
485
503
  });
486
504
  account = matchingAccounts[0];
487
505
  }
488
- if (!account || account.userId !== resolvedUserId) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.ACCOUNT_NOT_FOUND);
506
+ if (!account || !matchesAccountSelection(ctx, account, { resolvedUserId })) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.ACCOUNT_NOT_FOUND);
489
507
  const provider = await getAwaitableValue(ctx.context.socialProviders, { value: account.providerId });
490
508
  if (!provider) throw APIError.from("BAD_REQUEST", {
491
509
  message: "Account is not associated with a configured social provider.",