@better-auth/core 1.5.0-beta.8 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) hide show
  1. package/README.md +17 -0
  2. package/dist/api/index.d.mts +144 -41
  3. package/dist/api/index.mjs +2 -1
  4. package/dist/api/index.mjs.map +1 -0
  5. package/dist/async_hooks/index.d.mts +2 -1
  6. package/dist/async_hooks/index.mjs +2 -1
  7. package/dist/async_hooks/index.mjs.map +1 -0
  8. package/dist/async_hooks/pure.index.d.mts +2 -1
  9. package/dist/async_hooks/pure.index.mjs +2 -1
  10. package/dist/async_hooks/pure.index.mjs.map +1 -0
  11. package/dist/context/endpoint-context.d.mts +2 -1
  12. package/dist/context/endpoint-context.mjs +4 -3
  13. package/dist/context/endpoint-context.mjs.map +1 -0
  14. package/dist/context/global.d.mts +2 -2
  15. package/dist/context/global.mjs +3 -2
  16. package/dist/context/global.mjs.map +1 -0
  17. package/dist/context/index.d.mts +2 -2
  18. package/dist/context/index.mjs +2 -2
  19. package/dist/context/request-state.d.mts +2 -1
  20. package/dist/context/request-state.mjs +4 -3
  21. package/dist/context/request-state.mjs.map +1 -0
  22. package/dist/context/transaction.d.mts +12 -3
  23. package/dist/context/transaction.mjs +55 -11
  24. package/dist/context/transaction.mjs.map +1 -0
  25. package/dist/db/adapter/factory.d.mts +6 -13
  26. package/dist/db/adapter/factory.mjs +44 -57
  27. package/dist/db/adapter/factory.mjs.map +1 -0
  28. package/dist/db/adapter/get-default-field-name.d.mts +2 -1
  29. package/dist/db/adapter/get-default-field-name.mjs +3 -2
  30. package/dist/db/adapter/get-default-field-name.mjs.map +1 -0
  31. package/dist/db/adapter/get-default-model-name.d.mts +2 -1
  32. package/dist/db/adapter/get-default-model-name.mjs +5 -4
  33. package/dist/db/adapter/get-default-model-name.mjs.map +1 -0
  34. package/dist/db/adapter/get-field-attributes.d.mts +3 -2
  35. package/dist/db/adapter/get-field-attributes.mjs +2 -1
  36. package/dist/db/adapter/get-field-attributes.mjs.map +1 -0
  37. package/dist/db/adapter/get-field-name.d.mts +2 -1
  38. package/dist/db/adapter/get-field-name.mjs +2 -1
  39. package/dist/db/adapter/get-field-name.mjs.map +1 -0
  40. package/dist/db/adapter/get-id-field.d.mts +3 -2
  41. package/dist/db/adapter/get-id-field.mjs +3 -2
  42. package/dist/db/adapter/get-id-field.mjs.map +1 -0
  43. package/dist/db/adapter/get-model-name.d.mts +2 -1
  44. package/dist/db/adapter/get-model-name.mjs +2 -1
  45. package/dist/db/adapter/get-model-name.mjs.map +1 -0
  46. package/dist/db/adapter/index.d.mts +10 -4
  47. package/dist/db/adapter/index.mjs +19 -2
  48. package/dist/db/adapter/index.mjs.map +1 -0
  49. package/dist/db/adapter/types.d.mts +3 -34
  50. package/dist/db/adapter/utils.d.mts +2 -1
  51. package/dist/db/adapter/utils.mjs +2 -1
  52. package/dist/db/adapter/utils.mjs.map +1 -0
  53. package/dist/db/get-tables.d.mts +2 -1
  54. package/dist/db/get-tables.mjs +46 -39
  55. package/dist/db/get-tables.mjs.map +1 -0
  56. package/dist/db/index.d.mts +7 -7
  57. package/dist/db/plugin.d.mts +2 -1
  58. package/dist/db/schema/account.d.mts +8 -4
  59. package/dist/db/schema/account.mjs +2 -1
  60. package/dist/db/schema/account.mjs.map +1 -0
  61. package/dist/db/schema/rate-limit.d.mts +8 -2
  62. package/dist/db/schema/rate-limit.mjs +2 -1
  63. package/dist/db/schema/rate-limit.mjs.map +1 -0
  64. package/dist/db/schema/session.d.mts +8 -4
  65. package/dist/db/schema/session.mjs +2 -1
  66. package/dist/db/schema/session.mjs.map +1 -0
  67. package/dist/db/schema/shared.d.mts +2 -1
  68. package/dist/db/schema/shared.mjs +2 -1
  69. package/dist/db/schema/shared.mjs.map +1 -0
  70. package/dist/db/schema/user.d.mts +8 -4
  71. package/dist/db/schema/user.mjs +2 -1
  72. package/dist/db/schema/user.mjs.map +1 -0
  73. package/dist/db/schema/verification.d.mts +8 -4
  74. package/dist/db/schema/verification.mjs +2 -1
  75. package/dist/db/schema/verification.mjs.map +1 -0
  76. package/dist/db/type.d.mts +28 -2
  77. package/dist/env/color-depth.d.mts +2 -1
  78. package/dist/env/color-depth.mjs +2 -1
  79. package/dist/env/color-depth.mjs.map +1 -0
  80. package/dist/env/env-impl.d.mts +3 -2
  81. package/dist/env/env-impl.mjs +9 -8
  82. package/dist/env/env-impl.mjs.map +1 -0
  83. package/dist/env/logger.d.mts +2 -1
  84. package/dist/env/logger.mjs +3 -2
  85. package/dist/env/logger.mjs.map +1 -0
  86. package/dist/error/codes.d.mts +64 -181
  87. package/dist/error/codes.mjs +6 -2
  88. package/dist/error/codes.mjs.map +1 -0
  89. package/dist/error/index.d.mts +2 -1
  90. package/dist/error/index.mjs +2 -1
  91. package/dist/error/index.mjs.map +1 -0
  92. package/dist/index.d.mts +5 -4
  93. package/dist/oauth2/client-credentials-token.d.mts +25 -3
  94. package/dist/oauth2/client-credentials-token.mjs +15 -2
  95. package/dist/oauth2/client-credentials-token.mjs.map +1 -0
  96. package/dist/oauth2/create-authorization-url.d.mts +5 -2
  97. package/dist/oauth2/create-authorization-url.mjs +3 -1
  98. package/dist/oauth2/create-authorization-url.mjs.map +1 -0
  99. package/dist/oauth2/index.d.mts +4 -4
  100. package/dist/oauth2/index.mjs +4 -4
  101. package/dist/oauth2/oauth-provider.d.mts +3 -2
  102. package/dist/oauth2/refresh-access-token.d.mts +24 -4
  103. package/dist/oauth2/refresh-access-token.mjs +20 -2
  104. package/dist/oauth2/refresh-access-token.mjs.map +1 -0
  105. package/dist/oauth2/utils.d.mts +2 -1
  106. package/dist/oauth2/utils.mjs +2 -1
  107. package/dist/oauth2/utils.mjs.map +1 -0
  108. package/dist/oauth2/validate-authorization-code.d.mts +37 -4
  109. package/dist/oauth2/validate-authorization-code.mjs +25 -13
  110. package/dist/oauth2/validate-authorization-code.mjs.map +1 -0
  111. package/dist/oauth2/verify.d.mts +7 -13
  112. package/dist/oauth2/verify.mjs +2 -1
  113. package/dist/oauth2/verify.mjs.map +1 -0
  114. package/dist/social-providers/apple.d.mts +2 -1
  115. package/dist/social-providers/apple.mjs +22 -21
  116. package/dist/social-providers/apple.mjs.map +1 -0
  117. package/dist/social-providers/atlassian.d.mts +2 -1
  118. package/dist/social-providers/atlassian.mjs +2 -1
  119. package/dist/social-providers/atlassian.mjs.map +1 -0
  120. package/dist/social-providers/cognito.d.mts +2 -1
  121. package/dist/social-providers/cognito.mjs +4 -3
  122. package/dist/social-providers/cognito.mjs.map +1 -0
  123. package/dist/social-providers/discord.d.mts +2 -1
  124. package/dist/social-providers/discord.mjs +2 -1
  125. package/dist/social-providers/discord.mjs.map +1 -0
  126. package/dist/social-providers/dropbox.d.mts +2 -1
  127. package/dist/social-providers/dropbox.mjs +3 -2
  128. package/dist/social-providers/dropbox.mjs.map +1 -0
  129. package/dist/social-providers/facebook.d.mts +2 -1
  130. package/dist/social-providers/facebook.mjs +13 -12
  131. package/dist/social-providers/facebook.mjs.map +1 -0
  132. package/dist/social-providers/figma.d.mts +2 -1
  133. package/dist/social-providers/figma.mjs +2 -1
  134. package/dist/social-providers/figma.mjs.map +1 -0
  135. package/dist/social-providers/github.d.mts +3 -2
  136. package/dist/social-providers/github.mjs +23 -6
  137. package/dist/social-providers/github.mjs.map +1 -0
  138. package/dist/social-providers/gitlab.d.mts +2 -1
  139. package/dist/social-providers/gitlab.mjs +3 -2
  140. package/dist/social-providers/gitlab.mjs.map +1 -0
  141. package/dist/social-providers/google.d.mts +2 -1
  142. package/dist/social-providers/google.mjs +18 -13
  143. package/dist/social-providers/google.mjs.map +1 -0
  144. package/dist/social-providers/huggingface.d.mts +2 -1
  145. package/dist/social-providers/huggingface.mjs +3 -2
  146. package/dist/social-providers/huggingface.mjs.map +1 -0
  147. package/dist/social-providers/index.d.mts +61 -8
  148. package/dist/social-providers/index.mjs +5 -2
  149. package/dist/social-providers/index.mjs.map +1 -0
  150. package/dist/social-providers/kakao.d.mts +3 -2
  151. package/dist/social-providers/kakao.mjs +3 -2
  152. package/dist/social-providers/kakao.mjs.map +1 -0
  153. package/dist/social-providers/kick.d.mts +2 -1
  154. package/dist/social-providers/kick.mjs +2 -1
  155. package/dist/social-providers/kick.mjs.map +1 -0
  156. package/dist/social-providers/line.d.mts +2 -1
  157. package/dist/social-providers/line.mjs +3 -2
  158. package/dist/social-providers/line.mjs.map +1 -0
  159. package/dist/social-providers/linear.d.mts +2 -1
  160. package/dist/social-providers/linear.mjs +2 -1
  161. package/dist/social-providers/linear.mjs.map +1 -0
  162. package/dist/social-providers/linkedin.d.mts +2 -1
  163. package/dist/social-providers/linkedin.mjs +2 -1
  164. package/dist/social-providers/linkedin.mjs.map +1 -0
  165. package/dist/social-providers/microsoft-entra-id.d.mts +4 -1
  166. package/dist/social-providers/microsoft-entra-id.mjs +36 -2
  167. package/dist/social-providers/microsoft-entra-id.mjs.map +1 -0
  168. package/dist/social-providers/naver.d.mts +11 -20
  169. package/dist/social-providers/naver.mjs +3 -2
  170. package/dist/social-providers/naver.mjs.map +1 -0
  171. package/dist/social-providers/notion.d.mts +2 -1
  172. package/dist/social-providers/notion.mjs +3 -2
  173. package/dist/social-providers/notion.mjs.map +1 -0
  174. package/dist/social-providers/paybin.d.mts +2 -1
  175. package/dist/social-providers/paybin.mjs +3 -2
  176. package/dist/social-providers/paybin.mjs.map +1 -0
  177. package/dist/social-providers/paypal.d.mts +2 -1
  178. package/dist/social-providers/paypal.mjs +2 -1
  179. package/dist/social-providers/paypal.mjs.map +1 -0
  180. package/dist/social-providers/polar.d.mts +2 -1
  181. package/dist/social-providers/polar.mjs +3 -2
  182. package/dist/social-providers/polar.mjs.map +1 -0
  183. package/dist/social-providers/railway.d.mts +68 -0
  184. package/dist/social-providers/railway.mjs +78 -0
  185. package/dist/social-providers/railway.mjs.map +1 -0
  186. package/dist/social-providers/reddit.d.mts +2 -1
  187. package/dist/social-providers/reddit.mjs +2 -1
  188. package/dist/social-providers/reddit.mjs.map +1 -0
  189. package/dist/social-providers/roblox.d.mts +2 -1
  190. package/dist/social-providers/roblox.mjs +2 -1
  191. package/dist/social-providers/roblox.mjs.map +1 -0
  192. package/dist/social-providers/salesforce.d.mts +2 -1
  193. package/dist/social-providers/salesforce.mjs +2 -1
  194. package/dist/social-providers/salesforce.mjs.map +1 -0
  195. package/dist/social-providers/slack.d.mts +2 -1
  196. package/dist/social-providers/slack.mjs +2 -1
  197. package/dist/social-providers/slack.mjs.map +1 -0
  198. package/dist/social-providers/spotify.d.mts +2 -1
  199. package/dist/social-providers/spotify.mjs +2 -1
  200. package/dist/social-providers/spotify.mjs.map +1 -0
  201. package/dist/social-providers/tiktok.d.mts +3 -3
  202. package/dist/social-providers/tiktok.mjs +3 -2
  203. package/dist/social-providers/tiktok.mjs.map +1 -0
  204. package/dist/social-providers/twitch.d.mts +2 -1
  205. package/dist/social-providers/twitch.mjs +2 -1
  206. package/dist/social-providers/twitch.mjs.map +1 -0
  207. package/dist/social-providers/twitter.d.mts +14 -25
  208. package/dist/social-providers/twitter.mjs +2 -1
  209. package/dist/social-providers/twitter.mjs.map +1 -0
  210. package/dist/social-providers/vercel.d.mts +2 -1
  211. package/dist/social-providers/vercel.mjs +3 -2
  212. package/dist/social-providers/vercel.mjs.map +1 -0
  213. package/dist/social-providers/vk.d.mts +2 -1
  214. package/dist/social-providers/vk.mjs +2 -1
  215. package/dist/social-providers/vk.mjs.map +1 -0
  216. package/dist/social-providers/zoom.d.mts +3 -10
  217. package/dist/social-providers/zoom.mjs +2 -1
  218. package/dist/social-providers/zoom.mjs.map +1 -0
  219. package/dist/types/context.d.mts +54 -21
  220. package/dist/types/cookie.d.mts +2 -1
  221. package/dist/types/helper.d.mts +4 -1
  222. package/dist/types/index.d.mts +4 -3
  223. package/dist/types/init-options.d.mts +235 -144
  224. package/dist/types/plugin-client.d.mts +4 -1
  225. package/dist/types/plugin.d.mts +12 -11
  226. package/dist/types/secret.d.mts +12 -0
  227. package/dist/utils/db.d.mts +12 -0
  228. package/dist/utils/db.mjs +17 -0
  229. package/dist/utils/db.mjs.map +1 -0
  230. package/dist/utils/deprecate.d.mts +2 -2
  231. package/dist/utils/deprecate.mjs +2 -1
  232. package/dist/utils/deprecate.mjs.map +1 -0
  233. package/dist/utils/error-codes.d.mts +8 -6
  234. package/dist/utils/error-codes.mjs +3 -2
  235. package/dist/utils/error-codes.mjs.map +1 -0
  236. package/dist/utils/id.d.mts +2 -1
  237. package/dist/utils/id.mjs +2 -1
  238. package/dist/utils/id.mjs.map +1 -0
  239. package/dist/utils/ip.d.mts +55 -0
  240. package/dist/utils/ip.mjs +119 -0
  241. package/dist/utils/ip.mjs.map +1 -0
  242. package/dist/utils/json.d.mts +2 -1
  243. package/dist/utils/json.mjs +2 -1
  244. package/dist/utils/json.mjs.map +1 -0
  245. package/dist/utils/string.d.mts +2 -1
  246. package/dist/utils/string.mjs +2 -1
  247. package/dist/utils/string.mjs.map +1 -0
  248. package/dist/utils/url.d.mts +2 -1
  249. package/dist/utils/url.mjs +2 -1
  250. package/dist/utils/url.mjs.map +1 -0
  251. package/package.json +35 -13
  252. package/src/context/index.ts +1 -0
  253. package/src/context/transaction.ts +72 -9
  254. package/src/db/adapter/factory.ts +41 -73
  255. package/src/db/adapter/get-id-field.ts +1 -3
  256. package/src/db/adapter/index.ts +20 -15
  257. package/src/db/adapter/types.ts +2 -41
  258. package/src/db/get-tables.ts +48 -37
  259. package/src/db/index.ts +30 -5
  260. package/src/db/schema/account.ts +16 -3
  261. package/src/db/schema/rate-limit.ts +16 -1
  262. package/src/db/schema/session.ts +15 -3
  263. package/src/db/schema/user.ts +15 -3
  264. package/src/db/schema/verification.ts +16 -3
  265. package/src/db/test/get-tables.test.ts +33 -0
  266. package/src/db/type.ts +154 -1
  267. package/src/env/env-impl.ts +2 -2
  268. package/src/env/logger.ts +1 -1
  269. package/src/error/codes.ts +17 -0
  270. package/src/oauth2/client-credentials-token.ts +26 -2
  271. package/src/oauth2/create-authorization-url.ts +3 -1
  272. package/src/oauth2/index.ts +3 -0
  273. package/src/oauth2/oauth-provider.ts +1 -1
  274. package/src/oauth2/refresh-access-token.test.ts +90 -0
  275. package/src/oauth2/refresh-access-token.ts +37 -4
  276. package/src/oauth2/validate-authorization-code.ts +55 -29
  277. package/src/oauth2/validate-token.test.ts +229 -0
  278. package/src/social-providers/apple.ts +29 -29
  279. package/src/social-providers/cognito.ts +6 -5
  280. package/src/social-providers/dropbox.ts +1 -1
  281. package/src/social-providers/facebook.ts +3 -3
  282. package/src/social-providers/github.ts +26 -4
  283. package/src/social-providers/gitlab.ts +1 -1
  284. package/src/social-providers/google.ts +18 -14
  285. package/src/social-providers/huggingface.ts +1 -1
  286. package/src/social-providers/index.ts +9 -5
  287. package/src/social-providers/kakao.ts +1 -1
  288. package/src/social-providers/line.ts +1 -1
  289. package/src/social-providers/microsoft-entra-id.ts +84 -1
  290. package/src/social-providers/naver.ts +1 -1
  291. package/src/social-providers/notion.ts +1 -1
  292. package/src/social-providers/paybin.ts +1 -5
  293. package/src/social-providers/polar.ts +1 -1
  294. package/src/social-providers/railway.ts +100 -0
  295. package/src/social-providers/tiktok.ts +2 -1
  296. package/src/social-providers/vercel.ts +1 -1
  297. package/src/social-providers/zoom.ts +0 -8
  298. package/src/types/context.ts +79 -15
  299. package/src/types/helper.ts +9 -0
  300. package/src/types/index.ts +14 -2
  301. package/src/types/init-options.ts +298 -171
  302. package/src/types/plugin-client.ts +1 -0
  303. package/src/types/plugin.ts +11 -6
  304. package/src/types/secret.ts +8 -0
  305. package/src/utils/db.ts +20 -0
  306. package/src/utils/deprecate.test.ts +0 -1
  307. package/src/utils/error-codes.ts +12 -9
  308. package/src/utils/ip.test.ts +255 -0
  309. package/src/utils/ip.ts +211 -0
  310. package/.turbo/turbo-build.log +0 -180
  311. package/tsconfig.json +0 -7
  312. package/tsdown.config.ts +0 -32
  313. package/vitest.config.ts +0 -3
@@ -80,4 +80,37 @@ describe("getAuthTables", () => {
80
80
  expect(newField.fieldName).toBe("new_field");
81
81
  expect(newField.type).toBe("string");
82
82
  });
83
+
84
+ it("should exclude verification table when secondaryStorage is configured", () => {
85
+ const tables = getAuthTables({
86
+ secondaryStorage: {
87
+ get: async () => null,
88
+ set: async () => {},
89
+ delete: async () => {},
90
+ },
91
+ });
92
+
93
+ expect(tables.verification).toBeUndefined();
94
+ });
95
+
96
+ it("should include verification table when storeInDatabase is true", () => {
97
+ const tables = getAuthTables({
98
+ secondaryStorage: {
99
+ get: async () => null,
100
+ set: async () => {},
101
+ delete: async () => {},
102
+ },
103
+ verification: {
104
+ storeInDatabase: true,
105
+ },
106
+ });
107
+
108
+ expect(tables.verification).toBeDefined();
109
+ });
110
+
111
+ it("should include verification table when no secondaryStorage", () => {
112
+ const tables = getAuthTables({});
113
+
114
+ expect(tables.verification).toBeDefined();
115
+ });
83
116
  });
package/src/db/type.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  import type { StandardSchemaV1 } from "@standard-schema/spec";
2
- import type { Awaitable, LiteralString } from "../types";
2
+ import type {
3
+ Awaitable,
4
+ BetterAuthOptions,
5
+ LiteralString,
6
+ UnionToIntersection,
7
+ } from "../types";
3
8
 
4
9
  export type BaseModelNames = "user" | "account" | "session" | "verification";
5
10
 
@@ -8,6 +13,154 @@ export type ModelNames<T extends string = LiteralString> =
8
13
  | T
9
14
  | "rate-limit";
10
15
 
16
+ export type InferDBValueType<T extends DBFieldType> = T extends "string"
17
+ ? string
18
+ : T extends "number"
19
+ ? number
20
+ : T extends "boolean"
21
+ ? boolean
22
+ : T extends "date"
23
+ ? Date
24
+ : T extends "json"
25
+ ? Record<string, any>
26
+ : T extends `${infer U}[]`
27
+ ? U extends "string"
28
+ ? string[]
29
+ : number[]
30
+ : T extends Array<any>
31
+ ? T[number]
32
+ : never;
33
+
34
+ export type InferDBFieldOutput<T extends DBFieldAttribute> =
35
+ T["returned"] extends false
36
+ ? never
37
+ : T["required"] extends false
38
+ ? InferDBValueType<T["type"]> | undefined | null
39
+ : InferDBValueType<T["type"]>;
40
+
41
+ export type InferDBFieldInput<T extends DBFieldAttribute> = InferDBValueType<
42
+ T["type"]
43
+ >;
44
+
45
+ export type InferDBFieldsInput<Field> =
46
+ Field extends Record<infer Key, DBFieldAttribute>
47
+ ? {
48
+ [key in Key as Field[key]["required"] extends false
49
+ ? never
50
+ : Field[key]["defaultValue"] extends string | number | boolean | Date
51
+ ? never
52
+ : Field[key]["input"] extends false
53
+ ? never
54
+ : key]: InferDBFieldInput<Field[key]>;
55
+ } & {
56
+ [key in Key as Field[key]["input"] extends false ? never : key]?:
57
+ | InferDBFieldInput<Field[key]>
58
+ | undefined
59
+ | null;
60
+ }
61
+ : {};
62
+
63
+ export type InferDBFieldsOutput<
64
+ Fields extends Record<string, DBFieldAttribute>,
65
+ > =
66
+ Fields extends Record<infer Key, DBFieldAttribute>
67
+ ? {
68
+ [key in Key as Fields[key]["returned"] extends false
69
+ ? never
70
+ : Fields[key]["required"] extends false
71
+ ? Fields[key]["defaultValue"] extends
72
+ | boolean
73
+ | string
74
+ | number
75
+ | Date
76
+ ? key
77
+ : never
78
+ : key]: InferDBFieldOutput<Fields[key]>;
79
+ } & {
80
+ [key in Key as Fields[key]["returned"] extends false
81
+ ? never
82
+ : Fields[key]["required"] extends false
83
+ ? Fields[key]["defaultValue"] extends
84
+ | boolean
85
+ | string
86
+ | number
87
+ | Date
88
+ ? never
89
+ : key
90
+ : never]?: InferDBFieldOutput<Fields[key]> | null;
91
+ }
92
+ : never;
93
+
94
+ export type InferDBFieldsFromOptionsInput<
95
+ DBOptions extends
96
+ | BetterAuthOptions["session"]
97
+ | BetterAuthOptions["user"]
98
+ | BetterAuthOptions["verification"]
99
+ | BetterAuthOptions["account"]
100
+ | BetterAuthOptions["rateLimit"],
101
+ > = DBOptions extends {
102
+ additionalFields: Record<string, DBFieldAttribute>;
103
+ }
104
+ ? InferDBFieldsInput<DBOptions["additionalFields"]>
105
+ : {};
106
+
107
+ export type InferDBFieldsFromOptions<
108
+ DBOptions extends
109
+ | BetterAuthOptions["session"]
110
+ | BetterAuthOptions["user"]
111
+ | BetterAuthOptions["verification"]
112
+ | BetterAuthOptions["account"]
113
+ | BetterAuthOptions["rateLimit"],
114
+ > = DBOptions extends {
115
+ additionalFields: Record<string, DBFieldAttribute>;
116
+ }
117
+ ? InferDBFieldsOutput<DBOptions["additionalFields"]>
118
+ : {};
119
+
120
+ export type InferDBFieldsFromPluginsInput<
121
+ ModelName extends string,
122
+ Plugins extends unknown[] | undefined,
123
+ > = Plugins extends []
124
+ ? {}
125
+ : Plugins extends [infer P, ...infer Rest]
126
+ ? P extends {
127
+ schema: {
128
+ [key in ModelName]: {
129
+ fields: infer Fields;
130
+ };
131
+ };
132
+ }
133
+ ? Fields extends Record<string, DBFieldAttribute>
134
+ ? UnionToIntersection<
135
+ InferDBFieldsInput<Fields> &
136
+ InferDBFieldsFromPluginsInput<ModelName, Rest>
137
+ >
138
+ : InferDBFieldsFromPluginsInput<ModelName, Rest>
139
+ : InferDBFieldsFromPluginsInput<ModelName, Rest>
140
+ : {};
141
+
142
+ export type InferDBFieldsFromPlugins<
143
+ ModelName extends string,
144
+ Plugins extends unknown[] | undefined,
145
+ > = Plugins extends []
146
+ ? {}
147
+ : Plugins extends [infer P, ...infer Rest]
148
+ ? P extends {
149
+ schema: {
150
+ [key in ModelName]: {
151
+ fields: infer Fields;
152
+ };
153
+ };
154
+ }
155
+ ? Fields extends Record<string, DBFieldAttribute>
156
+ ? UnionToIntersection<
157
+ InferDBFieldsOutput<Fields> &
158
+ InferDBFieldsFromPlugins<ModelName, Rest>
159
+ >
160
+ : InferDBFieldsFromPlugins<ModelName, Rest>
161
+ : InferDBFieldsFromPlugins<ModelName, Rest>
162
+ : {};
163
+
11
164
  export type DBFieldType =
12
165
  | "string"
13
166
  | "number"
@@ -115,10 +115,10 @@ export const ENV = Object.freeze({
115
115
  get PACKAGE_VERSION() {
116
116
  return getEnvVar("PACKAGE_VERSION", "0.0.0");
117
117
  },
118
- get BETTER_AUTH_TELEMETRY_ENDPOINT() {
118
+ get BETTER_AUTH_TELEMETRY_ENDPOINT(): string | undefined {
119
119
  return getEnvVar(
120
120
  "BETTER_AUTH_TELEMETRY_ENDPOINT",
121
- "https://telemetry.better-auth.com/v1/track",
121
+ import.meta.env.BETTER_AUTH_TELEMETRY_ENDPOINT,
122
122
  );
123
123
  },
124
124
  });
package/src/env/logger.ts CHANGED
@@ -94,7 +94,7 @@ export type InternalLogger = {
94
94
 
95
95
  export const createLogger = (options?: Logger | undefined): InternalLogger => {
96
96
  const enabled = options?.disabled !== true;
97
- const logLevel = options?.level ?? "error";
97
+ const logLevel = options?.level ?? "warn";
98
98
 
99
99
  const isDisableColorsSpecified = options?.disableColors !== undefined;
100
100
  const colorsEnabled = isDisableColorsSpecified
@@ -1,5 +1,18 @@
1
1
  import { defineErrorCodes } from "../utils/error-codes";
2
2
 
3
+ declare module "@better-auth/core" {
4
+ interface BetterAuthPluginRegistry<AuthOptions, Options> {
5
+ /**
6
+ * This plugin does not exist, do not use it in runtime.
7
+ */
8
+ "$internal:base": {
9
+ creator: () => {
10
+ $ERROR_CODES: typeof BASE_ERROR_CODES;
11
+ };
12
+ };
13
+ }
14
+ }
15
+
3
16
  export const BASE_ERROR_CODES = defineErrorCodes({
4
17
  USER_NOT_FOUND: "User not found",
5
18
  FAILED_TO_CREATE_USER: "Failed to create user",
@@ -49,6 +62,10 @@ export const BASE_ERROR_CODES = defineErrorCodes({
49
62
  ASYNC_VALIDATION_NOT_SUPPORTED: "Async validation is not supported",
50
63
  VALIDATION_ERROR: "Validation Error",
51
64
  MISSING_FIELD: "Field is required",
65
+ METHOD_NOT_ALLOWED_DEFER_SESSION_REQUIRED:
66
+ "POST method requires deferSessionRefresh to be enabled in session config",
67
+ BODY_MUST_BE_AN_OBJECT: "Body must be an object",
68
+ PASSWORD_ALREADY_SET: "User already has a password set",
52
69
  });
53
70
 
54
71
  export type APIErrorCode = keyof typeof BASE_ERROR_CODES;
@@ -1,7 +1,31 @@
1
1
  import { base64Url } from "@better-auth/utils/base64";
2
2
  import { betterFetch } from "@better-fetch/fetch";
3
+ import type { AwaitableFunction } from "../types";
3
4
  import type { OAuth2Tokens, ProviderOptions } from "./oauth-provider";
4
5
 
6
+ export async function clientCredentialsTokenRequest({
7
+ options,
8
+ scope,
9
+ authentication,
10
+ resource,
11
+ }: {
12
+ options: AwaitableFunction<ProviderOptions & { clientSecret: string }>;
13
+ scope?: string | undefined;
14
+ authentication?: ("basic" | "post") | undefined;
15
+ resource?: (string | string[]) | undefined;
16
+ }) {
17
+ options = typeof options === "function" ? await options() : options;
18
+ return createClientCredentialsTokenRequest({
19
+ options,
20
+ scope,
21
+ authentication,
22
+ resource,
23
+ });
24
+ }
25
+
26
+ /**
27
+ * @deprecated use async'd clientCredentialsTokenRequest instead
28
+ */
5
29
  export function createClientCredentialsTokenRequest({
6
30
  options,
7
31
  scope,
@@ -59,13 +83,13 @@ export async function clientCredentialsToken({
59
83
  authentication,
60
84
  resource,
61
85
  }: {
62
- options: ProviderOptions & { clientSecret: string };
86
+ options: AwaitableFunction<ProviderOptions & { clientSecret: string }>;
63
87
  tokenEndpoint: string;
64
88
  scope: string;
65
89
  authentication?: ("basic" | "post") | undefined;
66
90
  resource?: (string | string[]) | undefined;
67
91
  }): Promise<OAuth2Tokens> {
68
- const { body, headers } = createClientCredentialsTokenRequest({
92
+ const { body, headers } = await clientCredentialsTokenRequest({
69
93
  options,
70
94
  scope,
71
95
  authentication,
@@ -1,3 +1,4 @@
1
+ import type { AwaitableFunction } from "../types";
1
2
  import type { ProviderOptions } from "./index";
2
3
  import { generateCodeChallenge } from "./utils";
3
4
 
@@ -22,7 +23,7 @@ export async function createAuthorizationURL({
22
23
  scopeJoiner,
23
24
  }: {
24
25
  id: string;
25
- options: ProviderOptions;
26
+ options: AwaitableFunction<ProviderOptions>;
26
27
  redirectURI: string;
27
28
  authorizationEndpoint: string;
28
29
  state: string;
@@ -40,6 +41,7 @@ export async function createAuthorizationURL({
40
41
  additionalParams?: Record<string, string> | undefined;
41
42
  scopeJoiner?: string | undefined;
42
43
  }) {
44
+ options = typeof options === "function" ? await options() : options;
43
45
  const url = new URL(options.authorizationEndpoint || authorizationEndpoint);
44
46
  url.searchParams.set("response_type", responseType || "code");
45
47
  const primaryClientId = Array.isArray(options.clientId)
@@ -1,5 +1,6 @@
1
1
  export {
2
2
  clientCredentialsToken,
3
+ clientCredentialsTokenRequest,
3
4
  createClientCredentialsTokenRequest,
4
5
  } from "./client-credentials-token";
5
6
  export { createAuthorizationURL } from "./create-authorization-url";
@@ -12,9 +13,11 @@ export type {
12
13
  export {
13
14
  createRefreshAccessTokenRequest,
14
15
  refreshAccessToken,
16
+ refreshAccessTokenRequest,
15
17
  } from "./refresh-access-token";
16
18
  export { generateCodeChallenge, getOAuth2Tokens } from "./utils";
17
19
  export {
20
+ authorizationCodeRequest,
18
21
  createAuthorizationCodeRequest,
19
22
  validateAuthorizationCode,
20
23
  validateToken,
@@ -42,7 +42,7 @@ export interface OAuthProvider<
42
42
  redirectURI: string;
43
43
  codeVerifier?: string | undefined;
44
44
  deviceId?: string | undefined;
45
- }) => Promise<OAuth2Tokens>;
45
+ }) => Promise<OAuth2Tokens | null>;
46
46
  getUserInfo: (
47
47
  token: OAuth2Tokens & {
48
48
  /**
@@ -0,0 +1,90 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+
3
+ vi.mock("@better-fetch/fetch", () => ({
4
+ betterFetch: vi.fn(),
5
+ }));
6
+
7
+ import { betterFetch } from "@better-fetch/fetch";
8
+ import { refreshAccessToken } from "./refresh-access-token";
9
+
10
+ const mockedBetterFetch = vi.mocked(betterFetch);
11
+
12
+ describe("refreshAccessToken", () => {
13
+ it("should set accessTokenExpiresAt when expires_in is returned", async () => {
14
+ const now = Date.now();
15
+ mockedBetterFetch.mockResolvedValueOnce({
16
+ data: {
17
+ access_token: "new-access-token",
18
+ refresh_token: "new-refresh-token",
19
+ expires_in: 3600,
20
+ token_type: "Bearer",
21
+ },
22
+ error: null,
23
+ });
24
+
25
+ const tokens = await refreshAccessToken({
26
+ refreshToken: "old-refresh-token",
27
+ options: { clientId: "test-client", clientSecret: "test-secret" },
28
+ tokenEndpoint: "https://example.com/token",
29
+ });
30
+
31
+ expect(tokens.accessToken).toBe("new-access-token");
32
+ expect(tokens.refreshToken).toBe("new-refresh-token");
33
+ expect(tokens.accessTokenExpiresAt).toBeInstanceOf(Date);
34
+ expect(tokens.accessTokenExpiresAt!.getTime()).toBeGreaterThanOrEqual(
35
+ now + 3600 * 1000 - 1000,
36
+ );
37
+ expect(tokens.refreshTokenExpiresAt).toBeUndefined();
38
+ });
39
+
40
+ /**
41
+ * @see https://github.com/better-auth/better-auth/issues/7682
42
+ */
43
+ it("should set refreshTokenExpiresAt when refresh_token_expires_in is returned", async () => {
44
+ const now = Date.now();
45
+ mockedBetterFetch.mockResolvedValueOnce({
46
+ data: {
47
+ access_token: "new-access-token",
48
+ refresh_token: "new-refresh-token",
49
+ expires_in: 3600,
50
+ refresh_token_expires_in: 86400,
51
+ token_type: "Bearer",
52
+ },
53
+ error: null,
54
+ });
55
+
56
+ const tokens = await refreshAccessToken({
57
+ refreshToken: "old-refresh-token",
58
+ options: { clientId: "test-client", clientSecret: "test-secret" },
59
+ tokenEndpoint: "https://example.com/token",
60
+ });
61
+
62
+ expect(tokens.accessToken).toBe("new-access-token");
63
+ expect(tokens.refreshToken).toBe("new-refresh-token");
64
+ expect(tokens.accessTokenExpiresAt).toBeInstanceOf(Date);
65
+ expect(tokens.refreshTokenExpiresAt).toBeInstanceOf(Date);
66
+ expect(tokens.refreshTokenExpiresAt!.getTime()).toBeGreaterThanOrEqual(
67
+ now + 86400 * 1000 - 1000,
68
+ );
69
+ });
70
+
71
+ it("should not set refreshTokenExpiresAt when refresh_token_expires_in is not returned", async () => {
72
+ mockedBetterFetch.mockResolvedValueOnce({
73
+ data: {
74
+ access_token: "new-access-token",
75
+ refresh_token: "new-refresh-token",
76
+ expires_in: 3600,
77
+ token_type: "Bearer",
78
+ },
79
+ error: null,
80
+ });
81
+
82
+ const tokens = await refreshAccessToken({
83
+ refreshToken: "old-refresh-token",
84
+ options: { clientId: "test-client", clientSecret: "test-secret" },
85
+ tokenEndpoint: "https://example.com/token",
86
+ });
87
+
88
+ expect(tokens.refreshTokenExpiresAt).toBeUndefined();
89
+ });
90
+ });
@@ -1,7 +1,34 @@
1
1
  import { base64 } from "@better-auth/utils/base64";
2
2
  import { betterFetch } from "@better-fetch/fetch";
3
+ import type { AwaitableFunction } from "../types";
3
4
  import type { OAuth2Tokens, ProviderOptions } from "./oauth-provider";
4
5
 
6
+ export async function refreshAccessTokenRequest({
7
+ refreshToken,
8
+ options,
9
+ authentication,
10
+ extraParams,
11
+ resource,
12
+ }: {
13
+ refreshToken: string;
14
+ options: AwaitableFunction<Partial<ProviderOptions>>;
15
+ authentication?: ("basic" | "post") | undefined;
16
+ extraParams?: Record<string, string> | undefined;
17
+ resource?: (string | string[]) | undefined;
18
+ }) {
19
+ options = typeof options === "function" ? await options() : options;
20
+ return createRefreshAccessTokenRequest({
21
+ refreshToken,
22
+ options,
23
+ authentication,
24
+ extraParams,
25
+ resource,
26
+ });
27
+ }
28
+
29
+ /**
30
+ * @deprecated use async'd refreshAccessTokenRequest instead
31
+ */
5
32
  export function createRefreshAccessTokenRequest({
6
33
  refreshToken,
7
34
  options,
@@ -10,7 +37,7 @@ export function createRefreshAccessTokenRequest({
10
37
  resource,
11
38
  }: {
12
39
  refreshToken: string;
13
- options: Partial<ProviderOptions>;
40
+ options: ProviderOptions;
14
41
  authentication?: ("basic" | "post") | undefined;
15
42
  extraParams?: Record<string, string> | undefined;
16
43
  resource?: (string | string[]) | undefined;
@@ -80,10 +107,8 @@ export async function refreshAccessToken({
80
107
  tokenEndpoint: string;
81
108
  authentication?: ("basic" | "post") | undefined;
82
109
  extraParams?: Record<string, string> | undefined;
83
- /** @deprecated always "refresh_token" */
84
- grantType?: string | undefined;
85
110
  }): Promise<OAuth2Tokens> {
86
- const { body, headers } = createRefreshAccessTokenRequest({
111
+ const { body, headers } = await createRefreshAccessTokenRequest({
87
112
  refreshToken,
88
113
  options,
89
114
  authentication,
@@ -94,6 +119,7 @@ export async function refreshAccessToken({
94
119
  access_token: string;
95
120
  refresh_token?: string | undefined;
96
121
  expires_in?: number | undefined;
122
+ refresh_token_expires_in?: number | undefined;
97
123
  token_type?: string | undefined;
98
124
  scope?: string | undefined;
99
125
  id_token?: string | undefined;
@@ -120,5 +146,12 @@ export async function refreshAccessToken({
120
146
  );
121
147
  }
122
148
 
149
+ if (data.refresh_token_expires_in) {
150
+ const now = new Date();
151
+ tokens.refreshTokenExpiresAt = new Date(
152
+ now.getTime() + data.refresh_token_expires_in * 1000,
153
+ );
154
+ }
155
+
123
156
  return tokens;
124
157
  }
@@ -1,9 +1,48 @@
1
1
  import { base64 } from "@better-auth/utils/base64";
2
2
  import { betterFetch } from "@better-fetch/fetch";
3
- import { jwtVerify } from "jose";
3
+ import { createRemoteJWKSet, jwtVerify } from "jose";
4
+ import type { AwaitableFunction } from "../types";
4
5
  import type { ProviderOptions } from "./index";
5
6
  import { getOAuth2Tokens } from "./index";
6
7
 
8
+ export async function authorizationCodeRequest({
9
+ code,
10
+ codeVerifier,
11
+ redirectURI,
12
+ options,
13
+ authentication,
14
+ deviceId,
15
+ headers,
16
+ additionalParams = {},
17
+ resource,
18
+ }: {
19
+ code: string;
20
+ redirectURI: string;
21
+ options: AwaitableFunction<Partial<ProviderOptions>>;
22
+ codeVerifier?: string | undefined;
23
+ deviceId?: string | undefined;
24
+ authentication?: ("basic" | "post") | undefined;
25
+ headers?: Record<string, string> | undefined;
26
+ additionalParams?: Record<string, string> | undefined;
27
+ resource?: (string | string[]) | undefined;
28
+ }) {
29
+ options = typeof options === "function" ? await options() : options;
30
+ return createAuthorizationCodeRequest({
31
+ code,
32
+ codeVerifier,
33
+ redirectURI,
34
+ options,
35
+ authentication,
36
+ deviceId,
37
+ headers,
38
+ additionalParams,
39
+ resource,
40
+ });
41
+ }
42
+
43
+ /**
44
+ * @deprecated use async'd authorizationCodeRequest instead
45
+ */
7
46
  export function createAuthorizationCodeRequest({
8
47
  code,
9
48
  codeVerifier,
@@ -31,6 +70,7 @@ export function createAuthorizationCodeRequest({
31
70
  accept: "application/json",
32
71
  ...headers,
33
72
  };
73
+
34
74
  body.set("grant_type", "authorization_code");
35
75
  body.set("code", code);
36
76
  codeVerifier && body.set("code_verifier", codeVerifier);
@@ -90,7 +130,7 @@ export async function validateAuthorizationCode({
90
130
  }: {
91
131
  code: string;
92
132
  redirectURI: string;
93
- options: Partial<ProviderOptions>;
133
+ options: AwaitableFunction<Partial<ProviderOptions>>;
94
134
  codeVerifier?: string | undefined;
95
135
  deviceId?: string | undefined;
96
136
  tokenEndpoint: string;
@@ -99,7 +139,7 @@ export async function validateAuthorizationCode({
99
139
  additionalParams?: Record<string, string> | undefined;
100
140
  resource?: (string | string[]) | undefined;
101
141
  }) {
102
- const { body, headers: requestHeaders } = createAuthorizationCodeRequest({
142
+ const { body, headers: requestHeaders } = await authorizationCodeRequest({
103
143
  code,
104
144
  codeVerifier,
105
145
  redirectURI,
@@ -116,7 +156,6 @@ export async function validateAuthorizationCode({
116
156
  body: body,
117
157
  headers: requestHeaders,
118
158
  });
119
-
120
159
  if (error) {
121
160
  throw error;
122
161
  }
@@ -124,31 +163,18 @@ export async function validateAuthorizationCode({
124
163
  return tokens;
125
164
  }
126
165
 
127
- export async function validateToken(token: string, jwksEndpoint: string) {
128
- const { data, error } = await betterFetch<{
129
- keys: {
130
- kid: string;
131
- kty: string;
132
- use: string;
133
- n: string;
134
- e: string;
135
- x5c: string[];
136
- }[];
137
- }>(jwksEndpoint, {
138
- method: "GET",
139
- headers: {
140
- accept: "application/json",
141
- },
166
+ export async function validateToken(
167
+ token: string,
168
+ jwksEndpoint: string,
169
+ options?: {
170
+ audience?: string | string[];
171
+ issuer?: string | string[];
172
+ },
173
+ ) {
174
+ const jwks = createRemoteJWKSet(new URL(jwksEndpoint));
175
+ const verified = await jwtVerify(token, jwks, {
176
+ audience: options?.audience,
177
+ issuer: options?.issuer,
142
178
  });
143
- if (error) {
144
- throw error;
145
- }
146
- const keys = data["keys"];
147
- const header = JSON.parse(atob(token.split(".")[0]!));
148
- const key = keys.find((key) => key.kid === header.kid);
149
- if (!key) {
150
- throw new Error("Key not found");
151
- }
152
- const verified = await jwtVerify(token, key);
153
179
  return verified;
154
180
  }