@better-auth/core 1.5.0-beta.2 → 1.5.0-beta.20

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 (331) hide show
  1. package/LICENSE.md +15 -12
  2. package/README.md +17 -0
  3. package/dist/api/index.d.mts +280 -2
  4. package/dist/api/index.mjs +4 -2
  5. package/dist/api/index.mjs.map +1 -0
  6. package/dist/async_hooks/index.d.mts +2 -1
  7. package/dist/async_hooks/index.mjs +2 -1
  8. package/dist/async_hooks/index.mjs.map +1 -0
  9. package/dist/async_hooks/pure.index.d.mts +2 -1
  10. package/dist/async_hooks/pure.index.mjs +2 -1
  11. package/dist/async_hooks/pure.index.mjs.map +1 -0
  12. package/dist/context/endpoint-context.d.mts +20 -0
  13. package/dist/context/endpoint-context.mjs +32 -0
  14. package/dist/context/endpoint-context.mjs.map +1 -0
  15. package/dist/context/global.d.mts +7 -0
  16. package/dist/context/global.mjs +38 -0
  17. package/dist/context/global.mjs.map +1 -0
  18. package/dist/context/index.d.mts +5 -53
  19. package/dist/context/index.mjs +5 -2
  20. package/dist/context/request-state.d.mts +28 -0
  21. package/dist/context/request-state.mjs +50 -0
  22. package/dist/context/request-state.mjs.map +1 -0
  23. package/dist/context/transaction.d.mts +25 -0
  24. package/dist/context/transaction.mjs +96 -0
  25. package/dist/context/transaction.mjs.map +1 -0
  26. package/dist/db/adapter/factory.d.mts +20 -0
  27. package/dist/db/adapter/factory.mjs +725 -0
  28. package/dist/db/adapter/factory.mjs.map +1 -0
  29. package/dist/db/adapter/get-default-field-name.d.mts +19 -0
  30. package/dist/db/adapter/get-default-field-name.mjs +39 -0
  31. package/dist/db/adapter/get-default-field-name.mjs.map +1 -0
  32. package/dist/db/adapter/get-default-model-name.d.mts +13 -0
  33. package/dist/db/adapter/get-default-model-name.mjs +33 -0
  34. package/dist/db/adapter/get-default-model-name.mjs.map +1 -0
  35. package/dist/db/adapter/get-field-attributes.d.mts +30 -0
  36. package/dist/db/adapter/get-field-attributes.mjs +40 -0
  37. package/dist/db/adapter/get-field-attributes.mjs.map +1 -0
  38. package/dist/db/adapter/get-field-name.d.mts +19 -0
  39. package/dist/db/adapter/get-field-name.mjs +34 -0
  40. package/dist/db/adapter/get-field-name.mjs.map +1 -0
  41. package/dist/db/adapter/get-id-field.d.mts +40 -0
  42. package/dist/db/adapter/get-id-field.mjs +68 -0
  43. package/dist/db/adapter/get-id-field.mjs.map +1 -0
  44. package/dist/db/adapter/get-model-name.d.mts +13 -0
  45. package/dist/db/adapter/get-model-name.mjs +24 -0
  46. package/dist/db/adapter/get-model-name.mjs.map +1 -0
  47. package/dist/db/adapter/index.d.mts +520 -2
  48. package/dist/db/adapter/index.mjs +27 -972
  49. package/dist/db/adapter/index.mjs.map +1 -0
  50. package/dist/db/adapter/types.d.mts +108 -0
  51. package/dist/db/adapter/utils.d.mts +8 -0
  52. package/dist/db/adapter/utils.mjs +39 -0
  53. package/dist/db/adapter/utils.mjs.map +1 -0
  54. package/dist/db/get-tables.d.mts +9 -0
  55. package/dist/{get-tables-CMc_Emww.mjs → db/get-tables.mjs} +52 -39
  56. package/dist/db/get-tables.mjs.map +1 -0
  57. package/dist/db/index.d.mts +10 -2
  58. package/dist/db/index.mjs +7 -60
  59. package/dist/db/plugin.d.mts +13 -0
  60. package/dist/db/schema/account.d.mts +30 -0
  61. package/dist/db/schema/account.mjs +20 -0
  62. package/dist/db/schema/account.mjs.map +1 -0
  63. package/dist/db/schema/rate-limit.d.mts +20 -0
  64. package/dist/db/schema/rate-limit.mjs +12 -0
  65. package/dist/db/schema/rate-limit.mjs.map +1 -0
  66. package/dist/db/schema/session.d.mts +25 -0
  67. package/dist/db/schema/session.mjs +15 -0
  68. package/dist/db/schema/session.mjs.map +1 -0
  69. package/dist/db/schema/shared.d.mts +11 -0
  70. package/dist/db/schema/shared.mjs +12 -0
  71. package/dist/db/schema/shared.mjs.map +1 -0
  72. package/dist/db/schema/user.d.mts +24 -0
  73. package/dist/db/schema/user.mjs +14 -0
  74. package/dist/db/schema/user.mjs.map +1 -0
  75. package/dist/db/schema/verification.d.mts +23 -0
  76. package/dist/db/schema/verification.mjs +13 -0
  77. package/dist/db/schema/verification.mjs.map +1 -0
  78. package/dist/db/type.d.mts +169 -0
  79. package/dist/env/color-depth.d.mts +5 -0
  80. package/dist/env/color-depth.mjs +89 -0
  81. package/dist/env/color-depth.mjs.map +1 -0
  82. package/dist/env/env-impl.d.mts +33 -0
  83. package/dist/env/env-impl.mjs +83 -0
  84. package/dist/env/env-impl.mjs.map +1 -0
  85. package/dist/env/index.d.mts +4 -2
  86. package/dist/env/index.mjs +3 -1
  87. package/dist/{index-BRBu0-5h.d.mts → env/logger.d.mts} +2 -35
  88. package/dist/env/logger.mjs +82 -0
  89. package/dist/env/logger.mjs.map +1 -0
  90. package/dist/error/codes.d.mts +69 -0
  91. package/dist/{error-C7mY-p0f.mjs → error/codes.mjs} +7 -30
  92. package/dist/error/codes.mjs.map +1 -0
  93. package/dist/error/index.d.mts +6 -187
  94. package/dist/error/index.mjs +29 -4
  95. package/dist/error/index.mjs.map +1 -0
  96. package/dist/index.d.mts +8 -2
  97. package/dist/oauth2/client-credentials-token.d.mts +58 -0
  98. package/dist/oauth2/client-credentials-token.mjs +67 -0
  99. package/dist/oauth2/client-credentials-token.mjs.map +1 -0
  100. package/dist/oauth2/create-authorization-url.d.mts +48 -0
  101. package/dist/oauth2/create-authorization-url.mjs +44 -0
  102. package/dist/oauth2/create-authorization-url.mjs.map +1 -0
  103. package/dist/oauth2/index.d.mts +8 -2
  104. package/dist/oauth2/index.mjs +7 -3
  105. package/dist/oauth2/oauth-provider.d.mts +195 -0
  106. package/dist/oauth2/refresh-access-token.d.mts +56 -0
  107. package/dist/oauth2/refresh-access-token.mjs +76 -0
  108. package/dist/oauth2/refresh-access-token.mjs.map +1 -0
  109. package/dist/oauth2/utils.d.mts +8 -0
  110. package/dist/oauth2/utils.mjs +28 -0
  111. package/dist/oauth2/utils.mjs.map +1 -0
  112. package/dist/oauth2/validate-authorization-code.d.mts +88 -0
  113. package/dist/oauth2/validate-authorization-code.mjs +83 -0
  114. package/dist/oauth2/validate-authorization-code.mjs.map +1 -0
  115. package/dist/oauth2/verify.d.mts +43 -0
  116. package/dist/oauth2/verify.mjs +96 -0
  117. package/dist/oauth2/verify.mjs.map +1 -0
  118. package/dist/social-providers/apple.d.mts +120 -0
  119. package/dist/social-providers/apple.mjs +105 -0
  120. package/dist/social-providers/apple.mjs.map +1 -0
  121. package/dist/social-providers/atlassian.d.mts +73 -0
  122. package/dist/social-providers/atlassian.mjs +84 -0
  123. package/dist/social-providers/atlassian.mjs.map +1 -0
  124. package/dist/social-providers/cognito.d.mts +88 -0
  125. package/dist/social-providers/cognito.mjs +166 -0
  126. package/dist/social-providers/cognito.mjs.map +1 -0
  127. package/dist/social-providers/discord.d.mts +127 -0
  128. package/dist/social-providers/discord.mjs +65 -0
  129. package/dist/social-providers/discord.mjs.map +1 -0
  130. package/dist/social-providers/dropbox.d.mts +72 -0
  131. package/dist/social-providers/dropbox.mjs +76 -0
  132. package/dist/social-providers/dropbox.mjs.map +1 -0
  133. package/dist/social-providers/facebook.d.mts +82 -0
  134. package/dist/social-providers/facebook.mjs +121 -0
  135. package/dist/social-providers/facebook.mjs.map +1 -0
  136. package/dist/social-providers/figma.d.mts +64 -0
  137. package/dist/social-providers/figma.mjs +87 -0
  138. package/dist/social-providers/figma.mjs.map +1 -0
  139. package/dist/social-providers/github.d.mts +105 -0
  140. package/dist/social-providers/github.mjs +97 -0
  141. package/dist/social-providers/github.mjs.map +1 -0
  142. package/dist/social-providers/gitlab.d.mts +126 -0
  143. package/dist/social-providers/gitlab.mjs +83 -0
  144. package/dist/social-providers/gitlab.mjs.map +1 -0
  145. package/dist/social-providers/google.d.mts +100 -0
  146. package/dist/social-providers/google.mjs +113 -0
  147. package/dist/social-providers/google.mjs.map +1 -0
  148. package/dist/social-providers/huggingface.d.mts +86 -0
  149. package/dist/social-providers/huggingface.mjs +76 -0
  150. package/dist/social-providers/huggingface.mjs.map +1 -0
  151. package/dist/social-providers/index.d.mts +1777 -2
  152. package/dist/social-providers/index.mjs +37 -2570
  153. package/dist/social-providers/index.mjs.map +1 -0
  154. package/dist/social-providers/kakao.d.mts +164 -0
  155. package/dist/social-providers/kakao.mjs +73 -0
  156. package/dist/social-providers/kakao.mjs.map +1 -0
  157. package/dist/social-providers/kick.d.mts +76 -0
  158. package/dist/social-providers/kick.mjs +72 -0
  159. package/dist/social-providers/kick.mjs.map +1 -0
  160. package/dist/social-providers/line.d.mts +108 -0
  161. package/dist/social-providers/line.mjs +114 -0
  162. package/dist/social-providers/line.mjs.map +1 -0
  163. package/dist/social-providers/linear.d.mts +71 -0
  164. package/dist/social-providers/linear.mjs +89 -0
  165. package/dist/social-providers/linear.mjs.map +1 -0
  166. package/dist/social-providers/linkedin.d.mts +70 -0
  167. package/dist/social-providers/linkedin.mjs +77 -0
  168. package/dist/social-providers/linkedin.mjs.map +1 -0
  169. package/dist/social-providers/microsoft-entra-id.d.mts +177 -0
  170. package/dist/social-providers/microsoft-entra-id.mjs +140 -0
  171. package/dist/social-providers/microsoft-entra-id.mjs.map +1 -0
  172. package/dist/social-providers/naver.d.mts +95 -0
  173. package/dist/social-providers/naver.mjs +68 -0
  174. package/dist/social-providers/naver.mjs.map +1 -0
  175. package/dist/social-providers/notion.d.mts +67 -0
  176. package/dist/social-providers/notion.mjs +76 -0
  177. package/dist/social-providers/notion.mjs.map +1 -0
  178. package/dist/social-providers/paybin.d.mts +74 -0
  179. package/dist/social-providers/paybin.mjs +86 -0
  180. package/dist/social-providers/paybin.mjs.map +1 -0
  181. package/dist/social-providers/paypal.d.mts +132 -0
  182. package/dist/social-providers/paypal.mjs +145 -0
  183. package/dist/social-providers/paypal.mjs.map +1 -0
  184. package/dist/social-providers/polar.d.mts +77 -0
  185. package/dist/social-providers/polar.mjs +74 -0
  186. package/dist/social-providers/polar.mjs.map +1 -0
  187. package/dist/social-providers/railway.d.mts +68 -0
  188. package/dist/social-providers/railway.mjs +78 -0
  189. package/dist/social-providers/railway.mjs.map +1 -0
  190. package/dist/social-providers/reddit.d.mts +65 -0
  191. package/dist/social-providers/reddit.mjs +84 -0
  192. package/dist/social-providers/reddit.mjs.map +1 -0
  193. package/dist/social-providers/roblox.d.mts +73 -0
  194. package/dist/social-providers/roblox.mjs +60 -0
  195. package/dist/social-providers/roblox.mjs.map +1 -0
  196. package/dist/social-providers/salesforce.d.mts +82 -0
  197. package/dist/social-providers/salesforce.mjs +92 -0
  198. package/dist/social-providers/salesforce.mjs.map +1 -0
  199. package/dist/social-providers/slack.d.mts +86 -0
  200. package/dist/social-providers/slack.mjs +69 -0
  201. package/dist/social-providers/slack.mjs.map +1 -0
  202. package/dist/social-providers/spotify.d.mts +66 -0
  203. package/dist/social-providers/spotify.mjs +72 -0
  204. package/dist/social-providers/spotify.mjs.map +1 -0
  205. package/dist/social-providers/tiktok.d.mts +171 -0
  206. package/dist/social-providers/tiktok.mjs +63 -0
  207. package/dist/social-providers/tiktok.mjs.map +1 -0
  208. package/dist/social-providers/twitch.d.mts +82 -0
  209. package/dist/social-providers/twitch.mjs +79 -0
  210. package/dist/social-providers/twitch.mjs.map +1 -0
  211. package/dist/social-providers/twitter.d.mts +129 -0
  212. package/dist/social-providers/twitter.mjs +88 -0
  213. package/dist/social-providers/twitter.mjs.map +1 -0
  214. package/dist/social-providers/vercel.d.mts +65 -0
  215. package/dist/social-providers/vercel.mjs +62 -0
  216. package/dist/social-providers/vercel.mjs.map +1 -0
  217. package/dist/social-providers/vk.d.mts +73 -0
  218. package/dist/social-providers/vk.mjs +84 -0
  219. package/dist/social-providers/vk.mjs.map +1 -0
  220. package/dist/social-providers/zoom.d.mts +166 -0
  221. package/dist/social-providers/zoom.mjs +73 -0
  222. package/dist/social-providers/zoom.mjs.map +1 -0
  223. package/dist/types/context.d.mts +274 -0
  224. package/dist/types/cookie.d.mts +16 -0
  225. package/dist/types/helper.d.mts +11 -0
  226. package/dist/types/index.d.mts +8 -0
  227. package/dist/types/init-options.d.mts +1298 -0
  228. package/dist/types/plugin-client.d.mts +113 -0
  229. package/dist/types/plugin.d.mts +125 -0
  230. package/dist/utils/db.d.mts +12 -0
  231. package/dist/utils/db.mjs +17 -0
  232. package/dist/utils/db.mjs.map +1 -0
  233. package/dist/utils/deprecate.d.mts +10 -0
  234. package/dist/utils/deprecate.mjs +18 -0
  235. package/dist/utils/deprecate.mjs.map +1 -0
  236. package/dist/utils/{index.d.mts → error-codes.d.mts} +9 -16
  237. package/dist/utils/error-codes.mjs +12 -0
  238. package/dist/utils/error-codes.mjs.map +1 -0
  239. package/dist/utils/id.d.mts +5 -0
  240. package/dist/utils/id.mjs +10 -0
  241. package/dist/utils/id.mjs.map +1 -0
  242. package/dist/utils/ip.d.mts +55 -0
  243. package/dist/utils/ip.mjs +119 -0
  244. package/dist/utils/ip.mjs.map +1 -0
  245. package/dist/utils/json.d.mts +5 -0
  246. package/dist/utils/json.mjs +26 -0
  247. package/dist/utils/json.mjs.map +1 -0
  248. package/dist/utils/string.d.mts +5 -0
  249. package/dist/utils/string.mjs +8 -0
  250. package/dist/utils/string.mjs.map +1 -0
  251. package/dist/utils/url.d.mts +21 -0
  252. package/dist/utils/url.mjs +33 -0
  253. package/dist/utils/url.mjs.map +1 -0
  254. package/package.json +36 -18
  255. package/src/context/endpoint-context.ts +7 -6
  256. package/src/context/global.ts +57 -0
  257. package/src/context/index.ts +2 -0
  258. package/src/context/request-state.ts +7 -6
  259. package/src/context/transaction.ts +77 -14
  260. package/src/db/adapter/factory.ts +54 -86
  261. package/src/db/adapter/get-default-model-name.ts +1 -1
  262. package/src/db/adapter/get-id-field.ts +4 -6
  263. package/src/db/adapter/index.ts +20 -15
  264. package/src/db/adapter/types.ts +2 -41
  265. package/src/db/get-tables.ts +54 -37
  266. package/src/db/index.ts +30 -5
  267. package/src/db/schema/account.ts +16 -3
  268. package/src/db/schema/rate-limit.ts +16 -1
  269. package/src/db/schema/session.ts +15 -3
  270. package/src/db/schema/user.ts +15 -3
  271. package/src/db/schema/verification.ts +16 -3
  272. package/src/db/test/get-tables.test.ts +33 -0
  273. package/src/db/type.ts +154 -1
  274. package/src/env/env-impl.ts +2 -2
  275. package/src/env/logger.ts +1 -1
  276. package/src/error/codes.ts +18 -1
  277. package/src/error/index.ts +2 -3
  278. package/src/oauth2/client-credentials-token.ts +26 -2
  279. package/src/oauth2/create-authorization-url.ts +4 -2
  280. package/src/oauth2/index.ts +3 -0
  281. package/src/oauth2/oauth-provider.ts +7 -1
  282. package/src/oauth2/refresh-access-token.test.ts +90 -0
  283. package/src/oauth2/refresh-access-token.ts +37 -4
  284. package/src/oauth2/validate-authorization-code.ts +55 -29
  285. package/src/oauth2/validate-token.test.ts +229 -0
  286. package/src/social-providers/apple.ts +38 -29
  287. package/src/social-providers/cognito.ts +6 -5
  288. package/src/social-providers/dropbox.ts +1 -1
  289. package/src/social-providers/facebook.ts +3 -3
  290. package/src/social-providers/figma.ts +5 -3
  291. package/src/social-providers/github.ts +26 -4
  292. package/src/social-providers/gitlab.ts +2 -2
  293. package/src/social-providers/google.ts +18 -14
  294. package/src/social-providers/huggingface.ts +1 -1
  295. package/src/social-providers/index.ts +9 -5
  296. package/src/social-providers/kakao.ts +1 -1
  297. package/src/social-providers/line.ts +1 -1
  298. package/src/social-providers/microsoft-entra-id.ts +84 -1
  299. package/src/social-providers/naver.ts +1 -1
  300. package/src/social-providers/notion.ts +1 -1
  301. package/src/social-providers/paybin.ts +1 -5
  302. package/src/social-providers/polar.ts +1 -1
  303. package/src/social-providers/railway.ts +100 -0
  304. package/src/social-providers/tiktok.ts +2 -1
  305. package/src/social-providers/vercel.ts +1 -1
  306. package/src/social-providers/zoom.ts +0 -8
  307. package/src/types/context.ts +241 -132
  308. package/src/types/cookie.ts +6 -4
  309. package/src/types/helper.ts +9 -0
  310. package/src/types/index.ts +19 -2
  311. package/src/types/init-options.ts +301 -186
  312. package/src/types/plugin-client.ts +1 -0
  313. package/src/types/plugin.ts +11 -6
  314. package/src/utils/db.ts +20 -0
  315. package/src/utils/deprecate.test.ts +71 -0
  316. package/src/utils/deprecate.ts +21 -0
  317. package/src/utils/error-codes.ts +12 -9
  318. package/src/utils/ip.test.ts +255 -0
  319. package/src/utils/ip.ts +211 -0
  320. package/src/utils/url.ts +43 -0
  321. package/.turbo/turbo-build.log +0 -43
  322. package/dist/context-DblZrIwO.mjs +0 -114
  323. package/dist/env-DbssmzoK.mjs +0 -245
  324. package/dist/index-BpRqx5_q.d.mts +0 -7833
  325. package/dist/oauth2-BjWM15hm.mjs +0 -326
  326. package/dist/utils/index.mjs +0 -4
  327. package/dist/utils-s65Fz0OM.mjs +0 -47
  328. package/src/utils/index.ts +0 -4
  329. package/tsconfig.json +0 -7
  330. package/tsdown.config.ts +0 -22
  331. package/vitest.config.ts +0 -3
@@ -20,105 +20,168 @@ import type {
20
20
  Verification,
21
21
  } from "../db";
22
22
  import type { DBAdapterDebugLogOption, DBAdapterInstance } from "../db/adapter";
23
+ import type { BaseAccount } from "../db/schema/account";
24
+ import type { BaseRateLimit } from "../db/schema/rate-limit";
25
+ import type { BaseSession } from "../db/schema/session";
26
+ import type { BaseUser } from "../db/schema/user";
27
+ import type { BaseVerification } from "../db/schema/verification";
23
28
  import type { Logger } from "../env";
24
29
  import type { SocialProviderList, SocialProviders } from "../social-providers";
25
30
  import type { AuthContext, GenericEndpointContext } from "./context";
26
- import type { Awaitable, LiteralUnion } from "./helper";
31
+ import type { Awaitable, LiteralString, LiteralUnion } from "./helper";
27
32
  import type { BetterAuthPlugin } from "./plugin";
28
33
 
29
34
  type KyselyDatabaseType = "postgres" | "mysql" | "sqlite" | "mssql";
30
- type OmitId<T extends { id: unknown }> = Omit<T, "id">;
31
35
  type Optional<T> = {
32
36
  [P in keyof T]?: T[P] | undefined;
33
37
  };
34
38
 
39
+ export type StoreIdentifierOption =
40
+ | "plain"
41
+ | "hashed"
42
+ | { hash: (identifier: string) => Promise<string> };
43
+
35
44
  export type GenerateIdFn = (options: {
36
45
  model: ModelNames;
37
46
  size?: number | undefined;
38
47
  }) => string | false;
39
48
 
40
- export type BetterAuthRateLimitOptions = {
49
+ /**
50
+ * Configuration for dynamic base URL resolution.
51
+ * Allows Better Auth to work with multiple domains (e.g., Vercel preview deployments).
52
+ */
53
+ export type DynamicBaseURLConfig = {
41
54
  /**
42
- * By default, rate limiting is only
43
- * enabled on production.
55
+ * List of allowed hostnames. Supports wildcard patterns.
56
+ *
57
+ * The derived host from the request will be validated against this list.
58
+ * Uses the same wildcard matching as `trustedOrigins`.
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * allowedHosts: [
63
+ * "myapp.com", // Exact match
64
+ * "*.vercel.app", // Any Vercel preview
65
+ * "preview-*.myapp.com" // Pattern match
66
+ * ]
67
+ * ```
44
68
  */
45
- enabled?: boolean | undefined;
69
+ allowedHosts: string[];
70
+
46
71
  /**
47
- * Default window to use for rate limiting. The value
48
- * should be in seconds.
72
+ * Fallback URL to use if the derived host doesn't match any allowed host.
73
+ * If not set, Better Auth will throw an error when the host doesn't match.
49
74
  *
50
- * @default 10 seconds
75
+ * @example "https://myapp.com"
51
76
  */
52
- window?: number | undefined;
77
+ fallback?: string | undefined;
78
+
53
79
  /**
54
- * The default maximum number of requests allowed within the window.
80
+ * Protocol to use when constructing the URL.
81
+ * - `"https"`: Always use HTTPS (recommended for production)
82
+ * - `"http"`: Always use HTTP (for local development)
83
+ * - `"auto"`: Derive from `x-forwarded-proto` header or default to HTTPS
55
84
  *
56
- * @default 100 requests
85
+ * @default "auto"
57
86
  */
58
- max?: number | undefined;
87
+ protocol?: "http" | "https" | "auto" | undefined;
88
+ };
89
+
90
+ /**
91
+ * Base URL configuration.
92
+ * Can be a static string or a dynamic config for multi-domain deployments.
93
+ */
94
+ export type BaseURLConfig = string | DynamicBaseURLConfig;
95
+
96
+ export interface BetterAuthRateLimitStorage {
97
+ get: (key: string) => Promise<RateLimit | null | undefined>;
98
+ set: (
99
+ key: string,
100
+ value: RateLimit,
101
+ update?: boolean | undefined,
102
+ ) => Promise<void>;
103
+ }
104
+
105
+ export type BetterAuthRateLimitRule = {
59
106
  /**
60
- * Custom rate limit rules to apply to
61
- * specific paths.
107
+ * Default window to use for rate limiting. The value
108
+ * should be in seconds.
109
+ *
110
+ * @default 10 seconds
62
111
  */
63
- customRules?:
64
- | {
65
- [key: string]:
66
- | {
67
- /**
68
- * The window to use for the custom rule.
69
- */
70
- window: number;
71
- /**
72
- * The maximum number of requests allowed within the window.
73
- */
74
- max: number;
75
- }
76
- | false
77
- | ((request: Request) =>
78
- | { window: number; max: number }
79
- | false
80
- | Promise<
81
- | {
82
- window: number;
83
- max: number;
84
- }
85
- | false
86
- >);
87
- }
88
- | undefined;
112
+ window: number;
89
113
  /**
90
- * Storage configuration
91
- *
92
- * By default, rate limiting is stored in memory. If you passed a
93
- * secondary storage, rate limiting will be stored in the secondary
94
- * storage.
114
+ * The default maximum number of requests allowed within the window.
95
115
  *
96
- * @default "memory"
116
+ * @default 100 requests
97
117
  */
98
- storage?: ("memory" | "database" | "secondary-storage") | undefined;
118
+ max: number;
119
+ };
120
+
121
+ export type BetterAuthDBOptions<
122
+ ModelName extends string,
123
+ Keys extends string = string,
124
+ > = {
99
125
  /**
100
- * If database is used as storage, the name of the table to
101
- * use for rate limiting.
102
- *
103
- * @default "rateLimit"
126
+ * The name of the model. Defaults to the model name.
104
127
  */
105
- modelName?: string | undefined;
128
+ modelName?: ModelName | LiteralString;
106
129
  /**
107
- * Custom field names for the rate limit table
130
+ * Map fields to database columns
108
131
  */
109
- fields?: Partial<Record<keyof RateLimit, string>> | undefined;
132
+ fields?: Partial<Record<Exclude<Keys, "id">, string>>;
110
133
  /**
111
- * custom storage configuration.
112
- *
113
- * NOTE: If custom storage is used storage
114
- * is ignored
134
+ * Additional fields for the model
115
135
  */
116
- customStorage?: {
117
- get: (key: string) => Promise<RateLimit | undefined>;
118
- set: (key: string, value: RateLimit) => Promise<void>;
136
+ additionalFields?: {
137
+ [Key in Exclude<string, Keys | "id">]: DBFieldAttribute;
119
138
  };
120
139
  };
121
140
 
141
+ export type BetterAuthRateLimitOptions = Optional<BetterAuthRateLimitRule> &
142
+ Omit<
143
+ BetterAuthDBOptions<"rateLimit", keyof BaseRateLimit>,
144
+ "additionalFields"
145
+ > & {
146
+ /**
147
+ * By default, rate limiting is only
148
+ * enabled on production.
149
+ */
150
+ enabled?: boolean | undefined;
151
+ /**
152
+ * Custom rate limit rules to apply to
153
+ * specific paths.
154
+ */
155
+ customRules?:
156
+ | {
157
+ [key: string]:
158
+ | BetterAuthRateLimitRule
159
+ | false
160
+ | ((
161
+ request: Request,
162
+ currentRule: BetterAuthRateLimitRule,
163
+ ) => Awaitable<false | BetterAuthRateLimitRule>);
164
+ }
165
+ | undefined;
166
+ /**
167
+ * Storage configuration
168
+ *
169
+ * By default, rate limiting is stored in memory. If you passed a
170
+ * secondary storage, rate limiting will be stored in the secondary
171
+ * storage.
172
+ *
173
+ * @default "memory"
174
+ */
175
+ storage?: ("memory" | "database" | "secondary-storage") | undefined;
176
+ /**
177
+ * custom storage configuration.
178
+ *
179
+ * NOTE: If custom storage is used storage
180
+ * is ignored
181
+ */
182
+ customStorage?: BetterAuthRateLimitStorage;
183
+ };
184
+
122
185
  export type BetterAuthAdvancedOptions = {
123
186
  /**
124
187
  * Ip address configuration
@@ -142,6 +205,13 @@ export type BetterAuthAdvancedOptions = {
142
205
  * ⚠︎ This is a security risk and it may expose your application to abuse
143
206
  */
144
207
  disableIpTracking?: boolean;
208
+ /**
209
+ * IPv6 subnet prefix length for rate limiting.
210
+ * IPv6 addresses will be normalized to this subnet.
211
+ *
212
+ * @default 64
213
+ */
214
+ ipv6Subnet?: 128 | 64 | 48 | 32;
145
215
  }
146
216
  | undefined;
147
217
  /**
@@ -151,17 +221,32 @@ export type BetterAuthAdvancedOptions = {
151
221
  */
152
222
  useSecureCookies?: boolean | undefined;
153
223
  /**
154
- * Disable trusted origins check
224
+ * Disable all CSRF protection.
225
+ *
226
+ * When enabled, this disables:
227
+ * - Origin header validation when cookies are present
228
+ * - Fetch Metadata checks (Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest)
229
+ * - Cross-site navigation blocking for first-login scenarios
155
230
  *
156
231
  * ⚠︎ This is a security risk and it may expose your application to
157
232
  * CSRF attacks
233
+ *
234
+ * @default false
158
235
  */
159
236
  disableCSRFCheck?: boolean | undefined;
160
237
  /**
161
- * Disable origin check
238
+ * Disable URL validation against trustedOrigins.
239
+ *
240
+ * When enabled, this disables validation of:
241
+ * - callbackURL
242
+ * - redirectTo
243
+ * - errorCallbackURL
244
+ * - newUserCallbackURL
245
+ *
246
+ * ⚠︎ This may allow open redirects and could lead to security
247
+ * vulnerabilities.
162
248
  *
163
- * ⚠︎ This may allow requests from any origin to be processed by
164
- * Better Auth. And could lead to security vulnerabilities.
249
+ * @default false
165
250
  */
166
251
  disableOriginCheck?: boolean | undefined;
167
252
  /**
@@ -228,17 +313,6 @@ export type BetterAuthAdvancedOptions = {
228
313
  * @default 100
229
314
  */
230
315
  defaultFindManyLimit?: number;
231
- /**
232
- * If your database auto increments number ids, set this to `true`.
233
- *
234
- * Note: If enabled, we will not handle ID generation (including if you use `generateId`), and it would be expected that your database will provide the ID automatically.
235
- *
236
- * @default false
237
- *
238
- * @deprecated Please use `generateId` instead. This will be removed in future
239
- * releases.
240
- */
241
- useNumberId?: boolean;
242
316
  /**
243
317
  * Custom generateId function.
244
318
  *
@@ -294,8 +368,17 @@ export type BetterAuthAdvancedOptions = {
294
368
  * }
295
369
  */
296
370
  backgroundTasks?: {
297
- handler: (promise: Promise<void>) => void;
371
+ handler: (promise: Promise<unknown>) => void;
298
372
  };
373
+ /**
374
+ * Skip trailing slashes in API routes.
375
+ *
376
+ * When enabled, requests with trailing slashes (e.g., `/api/auth/session/`)
377
+ * will be handled the same as requests without (e.g., `/api/auth/session`).
378
+ *
379
+ * @default false
380
+ */
381
+ skipTrailingSlashes?: boolean;
299
382
  };
300
383
 
301
384
  export type BetterAuthOptions = {
@@ -310,12 +393,27 @@ export type BetterAuthOptions = {
310
393
  /**
311
394
  * Base URL for the Better Auth. This is typically the
312
395
  * root URL where your application server is hosted.
313
- * If not explicitly set,
314
- * the system will check the following environment variable:
315
396
  *
316
- * process.env.BETTER_AUTH_URL
397
+ * Can be configured as:
398
+ * - A static string: `"https://myapp.com"`
399
+ * - A dynamic config with allowed hosts for multi-domain deployments
400
+ *
401
+ * If not explicitly set, the system will check environment variables:
402
+ * `BETTER_AUTH_URL`, `NEXT_PUBLIC_BETTER_AUTH_URL`, etc.
403
+ *
404
+ * @example
405
+ * ```ts
406
+ * // Static URL
407
+ * baseURL: "https://myapp.com"
408
+ *
409
+ * // Dynamic with allowed hosts (for Vercel, multi-domain, etc.)
410
+ * baseURL: {
411
+ * allowedHosts: ["myapp.com", "*.vercel.app", "preview-*.myapp.com"],
412
+ * fallback: "https://myapp.com"
413
+ * }
414
+ * ```
317
415
  */
318
- baseURL?: string | undefined;
416
+ baseURL?: BaseURLConfig | undefined;
319
417
  /**
320
418
  * Base path for the Better Auth. This is typically
321
419
  * the path where the
@@ -451,10 +549,13 @@ export type BetterAuthOptions = {
451
549
  request?: Request,
452
550
  ) => Promise<void>;
453
551
  /**
454
- * Send a verification email automatically
455
- * after sign up
552
+ * Send a verification email automatically after sign up.
456
553
  *
457
- * @default false
554
+ * - `true`: Always send verification email on sign up
555
+ * - `false`: Never send verification email on sign up
556
+ * - `undefined`: Follows `requireEmailVerification` behavior
557
+ *
558
+ * @default undefined
458
559
  */
459
560
  sendOnSignUp?: boolean;
460
561
  /**
@@ -475,11 +576,14 @@ export type BetterAuthOptions = {
475
576
  */
476
577
  expiresIn?: number;
477
578
  /**
478
- * A function that is called when a user verifies their email
579
+ * A function that is called before a user verifies their email
479
580
  * @param user the user that verified their email
480
581
  * @param request the request object
481
582
  */
482
- onEmailVerification?: (user: User, request?: Request) => Promise<void>;
583
+ beforeEmailVerification?: (
584
+ user: User,
585
+ request?: Request,
586
+ ) => Promise<void>;
483
587
  /**
484
588
  * A function that is called when a user's email is updated to verified
485
589
  * @param user the user that verified their email
@@ -585,6 +689,20 @@ export type BetterAuthOptions = {
585
689
  * @default false
586
690
  */
587
691
  revokeSessionsOnPasswordReset?: boolean;
692
+ /**
693
+ * A callback function that is triggered when a user tries to sign up
694
+ * with an email that already exists. Useful for notifying the existing user
695
+ * that someone attempted to register with their email.
696
+ *
697
+ * This is only called when `requireEmailVerification: true` or `autoSignIn: false`.
698
+ */
699
+ onExistingUserSignUp?: (
700
+ /**
701
+ * @param user the existing user from the database
702
+ */
703
+ data: { user: User },
704
+ request?: Request,
705
+ ) => Promise<void>;
588
706
  }
589
707
  | undefined;
590
708
  /**
@@ -599,28 +717,7 @@ export type BetterAuthOptions = {
599
717
  * User configuration
600
718
  */
601
719
  user?:
602
- | {
603
- /**
604
- * The model name for the user. Defaults to "user".
605
- */
606
- modelName?: string;
607
- /**
608
- * Map fields
609
- *
610
- * @example
611
- * ```ts
612
- * {
613
- * userId: "user_id"
614
- * }
615
- * ```
616
- */
617
- fields?: Partial<Record<keyof OmitId<User>, string>>;
618
- /**
619
- * Additional fields for the user
620
- */
621
- additionalFields?: {
622
- [key: string]: DBFieldAttribute;
623
- };
720
+ | (BetterAuthDBOptions<"user", keyof BaseUser> & {
624
721
  /**
625
722
  * Changing email configuration
626
723
  */
@@ -630,21 +727,6 @@ export type BetterAuthOptions = {
630
727
  * @default false
631
728
  */
632
729
  enabled: boolean;
633
- /**
634
- * Send a verification email when the user changes their email.
635
- * @param data the data object
636
- * @param request the request object
637
- * @deprecated Use `sendChangeEmailConfirmation` instead
638
- */
639
- sendChangeEmailVerification?: (
640
- data: {
641
- user: User;
642
- newEmail: string;
643
- url: string;
644
- token: string;
645
- },
646
- request?: Request,
647
- ) => Promise<void>;
648
730
  /**
649
731
  * Send a confirmation email to the old email address when the user changes their email.
650
732
  * @param data the data object
@@ -707,26 +789,10 @@ export type BetterAuthOptions = {
707
789
  */
708
790
  deleteTokenExpiresIn?: number;
709
791
  };
710
- }
792
+ })
711
793
  | undefined;
712
794
  session?:
713
- | {
714
- /**
715
- * The model name for the session.
716
- *
717
- * @default "session"
718
- */
719
- modelName?: string;
720
- /**
721
- * Map fields
722
- *
723
- * @example
724
- * ```ts
725
- * {
726
- * userId: "user_id"
727
- * }
728
- */
729
- fields?: Partial<Record<keyof OmitId<Session>, string>>;
795
+ | (BetterAuthDBOptions<"session", keyof BaseSession> & {
730
796
  /**
731
797
  * Expiration time for the session token. The value
732
798
  * should be in seconds.
@@ -748,11 +814,13 @@ export type BetterAuthOptions = {
748
814
  */
749
815
  disableSessionRefresh?: boolean;
750
816
  /**
751
- * Additional fields for the session
817
+ * Defer session refresh writes to POST requests.
818
+ * When enabled, GET is read-only and POST performs refresh.
819
+ * Useful for read-replica database setups.
820
+ *
821
+ * @default false
752
822
  */
753
- additionalFields?: {
754
- [key: string]: DBFieldAttribute;
755
- };
823
+ deferSessionRefresh?: boolean;
756
824
  /**
757
825
  * By default if secondary storage is provided
758
826
  * the session is stored in the secondary storage.
@@ -862,24 +930,10 @@ export type BetterAuthOptions = {
862
930
  * @default 1 day (60 * 60 * 24)
863
931
  */
864
932
  freshAge?: number;
865
- }
933
+ })
866
934
  | undefined;
867
935
  account?:
868
- | {
869
- /**
870
- * The model name for the account. Defaults to "account".
871
- */
872
- modelName?: string;
873
- /**
874
- * Map fields
875
- */
876
- fields?: Partial<Record<keyof OmitId<Account>, string>>;
877
- /**
878
- * Additional fields for the account
879
- */
880
- additionalFields?: {
881
- [key: string]: DBFieldAttribute;
882
- };
936
+ | (BetterAuthDBOptions<"account", keyof BaseAccount> & {
883
937
  /**
884
938
  * When enabled (true), the user account data (accessToken, idToken, refreshToken, etc.)
885
939
  * will be updated on sign in with the latest data from the provider.
@@ -898,11 +952,54 @@ export type BetterAuthOptions = {
898
952
  */
899
953
  enabled?: boolean;
900
954
  /**
901
- * List of trusted providers
955
+ * Disable implicit account linking on sign-in.
956
+ *
957
+ * When enabled, accounts will not be automatically linked
958
+ * during OAuth sign-in, even if the email is verified or
959
+ * the provider is trusted. Users must explicitly link
960
+ * accounts using `linkSocial()` while authenticated.
961
+ *
962
+ * @default false
963
+ */
964
+ disableImplicitLinking?: boolean;
965
+ /**
966
+ * List of trusted providers. Can be a static array or a function
967
+ * that returns providers dynamically. The function is called
968
+ * during context init (with `request` undefined) and again
969
+ * on each request (with the incoming Request). It must be
970
+ * resilient to `request` being undefined.
971
+ *
972
+ * @example
973
+ * ```ts
974
+ * trustedProviders: ["google", "github"]
975
+ * ```
976
+ *
977
+ * @example
978
+ * ```ts
979
+ * trustedProviders: async (request) => {
980
+ * if (!request) return [];
981
+ * const providers = await getTrustedProvidersForTenant(request);
982
+ * return providers;
983
+ * }
984
+ * ```
902
985
  */
903
- trustedProviders?: Array<
904
- LiteralUnion<SocialProviderList[number] | "email-password", string>
905
- >;
986
+ trustedProviders?:
987
+ | Array<
988
+ LiteralUnion<
989
+ SocialProviderList[number] | "email-password",
990
+ string
991
+ >
992
+ >
993
+ | ((
994
+ request?: Request | undefined,
995
+ ) => Awaitable<
996
+ Array<
997
+ LiteralUnion<
998
+ SocialProviderList[number] | "email-password",
999
+ string
1000
+ >
1001
+ >
1002
+ >);
906
1003
  /**
907
1004
  * If enabled (true), this will allow users to manually linking accounts with different email addresses than the main user.
908
1005
  *
@@ -964,33 +1061,34 @@ export type BetterAuthOptions = {
964
1061
  * @note This is automatically set to true if you haven't passed a database
965
1062
  */
966
1063
  storeAccountCookie?: boolean;
967
- }
1064
+ })
968
1065
  | undefined;
969
- /**
970
- * Verification configuration
971
- */
972
1066
  verification?:
973
- | {
1067
+ | (BetterAuthDBOptions<"verification", keyof BaseVerification> & {
974
1068
  /**
975
- * Change the modelName of the verification table
976
- */
977
- modelName?: string;
978
- /**
979
- * Map verification fields
1069
+ * disable cleaning up expired values when a verification value is
1070
+ * fetched
980
1071
  */
981
- fields?: Partial<Record<keyof OmitId<Verification>, string>>;
1072
+ disableCleanup?: boolean;
982
1073
  /**
983
- * Additional fields for the verification
1074
+ * How to store verification identifiers (tokens, OTPs, etc.)
1075
+ *
1076
+ * @example "hashed"
1077
+ *
1078
+ * @default "plain"
984
1079
  */
985
- additionalFields?: {
986
- [key: string]: DBFieldAttribute;
987
- };
1080
+ storeIdentifier?:
1081
+ | StoreIdentifierOption
1082
+ | {
1083
+ default: StoreIdentifierOption;
1084
+ overrides?: Record<string, StoreIdentifierOption>;
1085
+ };
988
1086
  /**
989
- * disable cleaning up expired values when a verification value is
990
- * fetched
1087
+ * Store verification data in database even when secondary storage is configured.
1088
+ * @default false
991
1089
  */
992
- disableCleanup?: boolean;
993
- }
1090
+ storeInDatabase?: boolean;
1091
+ })
994
1092
  | undefined;
995
1093
  /**
996
1094
  * List of trusted origins.
@@ -1002,9 +1100,26 @@ export type BetterAuthOptions = {
1002
1100
  *
1003
1101
  * Trusted origins will be dynamically
1004
1102
  * calculated based on the request.
1103
+ *
1104
+ * @example
1105
+ * ```ts
1106
+ * trustedOrigins: async (request) => {
1107
+ * return [
1108
+ * "https://better-auth.com",
1109
+ * "https://*.better-auth.com",
1110
+ * request.headers.get("x-custom-origin")
1111
+ * ];
1112
+ * }
1113
+ * ```
1114
+ * @returns An array of trusted origins.
1005
1115
  */
1006
1116
  trustedOrigins?:
1007
- | (string[] | ((request?: Request | undefined) => Awaitable<string[]>))
1117
+ | (
1118
+ | string[]
1119
+ | ((
1120
+ request?: Request | undefined,
1121
+ ) => Awaitable<(string | undefined | null)[]>)
1122
+ )
1008
1123
  | undefined;
1009
1124
  /**
1010
1125
  * Rate limiting configuration
@@ -17,6 +17,7 @@ export interface ClientStore {
17
17
  export type ClientAtomListener = {
18
18
  matcher: (path: string) => boolean;
19
19
  signal: "$sessionSignal" | Omit<string, "$sessionSignal">;
20
+ callback?: (path: string) => void;
20
21
  };
21
22
 
22
23
  /**