better-auth 1.3.0-beta.5 → 1.3.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 (231) hide show
  1. package/dist/adapters/drizzle-adapter/index.d.cts +2 -2
  2. package/dist/adapters/drizzle-adapter/index.d.mts +2 -2
  3. package/dist/adapters/drizzle-adapter/index.d.ts +2 -2
  4. package/dist/adapters/index.d.cts +3 -3
  5. package/dist/adapters/index.d.mts +3 -3
  6. package/dist/adapters/index.d.ts +3 -3
  7. package/dist/adapters/kysely-adapter/index.d.cts +2 -2
  8. package/dist/adapters/kysely-adapter/index.d.mts +2 -2
  9. package/dist/adapters/kysely-adapter/index.d.ts +2 -2
  10. package/dist/adapters/memory-adapter/index.d.cts +2 -2
  11. package/dist/adapters/memory-adapter/index.d.mts +2 -2
  12. package/dist/adapters/memory-adapter/index.d.ts +2 -2
  13. package/dist/adapters/mongodb-adapter/index.d.cts +2 -2
  14. package/dist/adapters/mongodb-adapter/index.d.mts +2 -2
  15. package/dist/adapters/mongodb-adapter/index.d.ts +2 -2
  16. package/dist/adapters/prisma-adapter/index.d.cts +2 -2
  17. package/dist/adapters/prisma-adapter/index.d.mts +2 -2
  18. package/dist/adapters/prisma-adapter/index.d.ts +2 -2
  19. package/dist/adapters/test.d.cts +2 -2
  20. package/dist/adapters/test.d.mts +2 -2
  21. package/dist/adapters/test.d.ts +2 -2
  22. package/dist/api/index.cjs +1 -1
  23. package/dist/api/index.d.cts +2 -2
  24. package/dist/api/index.d.mts +2 -2
  25. package/dist/api/index.d.ts +2 -2
  26. package/dist/api/index.mjs +2 -2
  27. package/dist/chunks/index.cjs +905 -0
  28. package/dist/chunks/index.mjs +895 -0
  29. package/dist/client/index.d.cts +5 -9
  30. package/dist/client/index.d.mts +5 -9
  31. package/dist/client/index.d.ts +5 -9
  32. package/dist/client/plugins/index.d.cts +4 -4
  33. package/dist/client/plugins/index.d.mts +4 -4
  34. package/dist/client/plugins/index.d.ts +4 -4
  35. package/dist/client/react/index.d.cts +9 -9
  36. package/dist/client/react/index.d.mts +9 -9
  37. package/dist/client/react/index.d.ts +9 -9
  38. package/dist/client/solid/index.d.cts +9 -9
  39. package/dist/client/solid/index.d.mts +9 -9
  40. package/dist/client/solid/index.d.ts +9 -9
  41. package/dist/client/svelte/index.d.cts +3 -3
  42. package/dist/client/svelte/index.d.mts +3 -3
  43. package/dist/client/svelte/index.d.ts +3 -3
  44. package/dist/client/vue/index.d.cts +3 -3
  45. package/dist/client/vue/index.d.mts +3 -3
  46. package/dist/client/vue/index.d.ts +3 -3
  47. package/dist/cookies/index.d.cts +2 -2
  48. package/dist/cookies/index.d.mts +2 -2
  49. package/dist/cookies/index.d.ts +2 -2
  50. package/dist/db/index.d.cts +3 -3
  51. package/dist/db/index.d.mts +3 -3
  52. package/dist/db/index.d.ts +3 -3
  53. package/dist/index.cjs +2 -2
  54. package/dist/index.d.cts +4 -4
  55. package/dist/index.d.mts +4 -4
  56. package/dist/index.d.ts +4 -4
  57. package/dist/index.mjs +2 -2
  58. package/dist/integrations/next-js.cjs +2 -2
  59. package/dist/integrations/next-js.d.cts +2 -2
  60. package/dist/integrations/next-js.d.mts +2 -2
  61. package/dist/integrations/next-js.d.ts +2 -2
  62. package/dist/integrations/next-js.mjs +2 -2
  63. package/dist/integrations/node.d.cts +2 -2
  64. package/dist/integrations/node.d.mts +2 -2
  65. package/dist/integrations/node.d.ts +2 -2
  66. package/dist/integrations/react-start.cjs +3 -3
  67. package/dist/integrations/react-start.d.cts +2 -2
  68. package/dist/integrations/react-start.d.mts +2 -2
  69. package/dist/integrations/react-start.d.ts +2 -2
  70. package/dist/integrations/react-start.mjs +3 -3
  71. package/dist/integrations/svelte-kit.cjs +1 -1
  72. package/dist/integrations/svelte-kit.d.cts +2 -2
  73. package/dist/integrations/svelte-kit.d.mts +2 -2
  74. package/dist/integrations/svelte-kit.d.ts +2 -2
  75. package/dist/integrations/svelte-kit.mjs +1 -1
  76. package/dist/oauth2/index.cjs +1 -1
  77. package/dist/oauth2/index.d.cts +4 -4
  78. package/dist/oauth2/index.d.mts +4 -4
  79. package/dist/oauth2/index.d.ts +4 -4
  80. package/dist/oauth2/index.mjs +1 -1
  81. package/dist/plugins/admin/index.cjs +2 -2
  82. package/dist/plugins/admin/index.d.cts +6 -5
  83. package/dist/plugins/admin/index.d.mts +6 -5
  84. package/dist/plugins/admin/index.d.ts +6 -5
  85. package/dist/plugins/admin/index.mjs +2 -2
  86. package/dist/plugins/anonymous/index.cjs +1 -1
  87. package/dist/plugins/anonymous/index.d.cts +2 -2
  88. package/dist/plugins/anonymous/index.d.mts +2 -2
  89. package/dist/plugins/anonymous/index.d.ts +2 -2
  90. package/dist/plugins/anonymous/index.mjs +1 -1
  91. package/dist/plugins/bearer/index.cjs +1 -1
  92. package/dist/plugins/bearer/index.d.cts +2 -2
  93. package/dist/plugins/bearer/index.d.mts +2 -2
  94. package/dist/plugins/bearer/index.d.ts +2 -2
  95. package/dist/plugins/bearer/index.mjs +1 -1
  96. package/dist/plugins/captcha/index.d.cts +2 -2
  97. package/dist/plugins/captcha/index.d.mts +2 -2
  98. package/dist/plugins/captcha/index.d.ts +2 -2
  99. package/dist/plugins/custom-session/index.cjs +1 -1
  100. package/dist/plugins/custom-session/index.d.cts +2 -2
  101. package/dist/plugins/custom-session/index.d.mts +2 -2
  102. package/dist/plugins/custom-session/index.d.ts +2 -2
  103. package/dist/plugins/custom-session/index.mjs +1 -1
  104. package/dist/plugins/email-otp/index.cjs +213 -101
  105. package/dist/plugins/email-otp/index.d.cts +101 -72
  106. package/dist/plugins/email-otp/index.d.mts +101 -72
  107. package/dist/plugins/email-otp/index.d.ts +101 -72
  108. package/dist/plugins/email-otp/index.mjs +213 -101
  109. package/dist/plugins/generic-oauth/index.cjs +1 -1
  110. package/dist/plugins/generic-oauth/index.d.cts +2 -2
  111. package/dist/plugins/generic-oauth/index.d.mts +2 -2
  112. package/dist/plugins/generic-oauth/index.d.ts +2 -2
  113. package/dist/plugins/generic-oauth/index.mjs +1 -1
  114. package/dist/plugins/haveibeenpwned/index.cjs +1 -1
  115. package/dist/plugins/haveibeenpwned/index.d.cts +2 -2
  116. package/dist/plugins/haveibeenpwned/index.d.mts +2 -2
  117. package/dist/plugins/haveibeenpwned/index.d.ts +2 -2
  118. package/dist/plugins/haveibeenpwned/index.mjs +1 -1
  119. package/dist/plugins/index.cjs +23 -1895
  120. package/dist/plugins/index.d.cts +4 -4
  121. package/dist/plugins/index.d.mts +4 -4
  122. package/dist/plugins/index.d.ts +4 -4
  123. package/dist/plugins/index.mjs +22 -1894
  124. package/dist/plugins/jwt/index.cjs +1 -1
  125. package/dist/plugins/jwt/index.d.cts +2 -2
  126. package/dist/plugins/jwt/index.d.mts +2 -2
  127. package/dist/plugins/jwt/index.d.ts +2 -2
  128. package/dist/plugins/jwt/index.mjs +1 -1
  129. package/dist/plugins/magic-link/index.cjs +39 -12
  130. package/dist/plugins/magic-link/index.d.cts +12 -2
  131. package/dist/plugins/magic-link/index.d.mts +12 -2
  132. package/dist/plugins/magic-link/index.d.ts +12 -2
  133. package/dist/plugins/magic-link/index.mjs +39 -12
  134. package/dist/plugins/multi-session/index.cjs +1 -1
  135. package/dist/plugins/multi-session/index.d.cts +2 -2
  136. package/dist/plugins/multi-session/index.d.mts +2 -2
  137. package/dist/plugins/multi-session/index.d.ts +2 -2
  138. package/dist/plugins/multi-session/index.mjs +1 -1
  139. package/dist/plugins/oauth-proxy/index.cjs +1 -1
  140. package/dist/plugins/oauth-proxy/index.d.cts +2 -2
  141. package/dist/plugins/oauth-proxy/index.d.mts +2 -2
  142. package/dist/plugins/oauth-proxy/index.d.ts +2 -2
  143. package/dist/plugins/oauth-proxy/index.mjs +1 -1
  144. package/dist/plugins/oidc-provider/index.cjs +2 -2
  145. package/dist/plugins/oidc-provider/index.d.cts +7 -7
  146. package/dist/plugins/oidc-provider/index.d.mts +7 -7
  147. package/dist/plugins/oidc-provider/index.d.ts +7 -7
  148. package/dist/plugins/oidc-provider/index.mjs +2 -2
  149. package/dist/plugins/one-tap/index.cjs +1 -1
  150. package/dist/plugins/one-tap/index.mjs +1 -1
  151. package/dist/plugins/one-time-token/index.cjs +8 -77
  152. package/dist/plugins/one-time-token/index.d.cts +14 -4
  153. package/dist/plugins/one-time-token/index.d.mts +14 -4
  154. package/dist/plugins/one-time-token/index.d.ts +14 -4
  155. package/dist/plugins/one-time-token/index.mjs +6 -79
  156. package/dist/plugins/open-api/index.cjs +1 -1
  157. package/dist/plugins/open-api/index.d.cts +2 -2
  158. package/dist/plugins/open-api/index.d.mts +2 -2
  159. package/dist/plugins/open-api/index.d.ts +2 -2
  160. package/dist/plugins/open-api/index.mjs +1 -1
  161. package/dist/plugins/organization/index.cjs +2 -2
  162. package/dist/plugins/organization/index.d.cts +3 -2
  163. package/dist/plugins/organization/index.d.mts +3 -2
  164. package/dist/plugins/organization/index.d.ts +3 -2
  165. package/dist/plugins/organization/index.mjs +2 -2
  166. package/dist/plugins/passkey/index.cjs +1 -1
  167. package/dist/plugins/passkey/index.d.cts +2 -2
  168. package/dist/plugins/passkey/index.d.mts +2 -2
  169. package/dist/plugins/passkey/index.d.ts +2 -2
  170. package/dist/plugins/passkey/index.mjs +1 -1
  171. package/dist/plugins/phone-number/index.cjs +1 -1
  172. package/dist/plugins/phone-number/index.d.cts +2 -2
  173. package/dist/plugins/phone-number/index.d.mts +2 -2
  174. package/dist/plugins/phone-number/index.d.ts +2 -2
  175. package/dist/plugins/phone-number/index.mjs +1 -1
  176. package/dist/plugins/sso/index.cjs +1 -1
  177. package/dist/plugins/sso/index.d.cts +5 -5
  178. package/dist/plugins/sso/index.d.mts +5 -5
  179. package/dist/plugins/sso/index.d.ts +5 -5
  180. package/dist/plugins/sso/index.mjs +1 -1
  181. package/dist/plugins/two-factor/index.cjs +103 -18
  182. package/dist/plugins/two-factor/index.d.cts +23 -7
  183. package/dist/plugins/two-factor/index.d.mts +23 -7
  184. package/dist/plugins/two-factor/index.d.ts +23 -7
  185. package/dist/plugins/two-factor/index.mjs +103 -18
  186. package/dist/plugins/username/index.cjs +4 -2
  187. package/dist/plugins/username/index.d.cts +2 -2
  188. package/dist/plugins/username/index.d.mts +2 -2
  189. package/dist/plugins/username/index.d.ts +2 -2
  190. package/dist/plugins/username/index.mjs +4 -2
  191. package/dist/shared/{better-auth.CqTBLifU.d.cts → better-auth.1M3xAdJC.d.cts} +45 -38
  192. package/dist/shared/{better-auth.RTMLk2Ya.cjs → better-auth.B2zZl7qP.cjs} +1 -1
  193. package/dist/shared/{better-auth.C0cDbHJn.d.mts → better-auth.BJa1oqpN.d.cts} +1 -1
  194. package/dist/shared/{better-auth.GYpUAWrY.d.mts → better-auth.BYIMqSU0.d.mts} +2 -2
  195. package/dist/shared/{better-auth.BGfHbXlu.d.ts → better-auth.Bc-1Su7g.d.ts} +45 -38
  196. package/dist/shared/{better-auth.B7Dt9CoJ.cjs → better-auth.BjBe8STm.cjs} +11 -2
  197. package/dist/shared/{better-auth.ClyLnOjY.mjs → better-auth.BtyWISFt.mjs} +152 -75
  198. package/dist/shared/{better-auth.GAghsvQp.d.cts → better-auth.C1otFVHS.d.mts} +1 -1
  199. package/dist/shared/better-auth.C6VyAxGz.mjs +2001 -0
  200. package/dist/shared/{better-auth.CP_AmXSW.d.mts → better-auth.CJ2ZGyoL.d.mts} +7 -3
  201. package/dist/shared/{better-auth.CZ3qe2fL.d.ts → better-auth.CJb2R19P.d.ts} +2 -2
  202. package/dist/shared/{better-auth.CRISE-Is.mjs → better-auth.CQPOI-_E.mjs} +1 -1
  203. package/dist/shared/{better-auth.CJDmUUCz.d.cts → better-auth.CpSq0H3M.d.cts} +2 -2
  204. package/dist/shared/{better-auth.DBODKok7.mjs → better-auth.D7Si_1a9.mjs} +11 -2
  205. package/dist/shared/{better-auth.DFU4LGhu.d.ts → better-auth.D9z1x8va.d.ts} +99 -2
  206. package/dist/shared/{better-auth.B8vM3gli.d.mts → better-auth.DWRzwPcP.d.mts} +45 -38
  207. package/dist/shared/better-auth.DZBS14g0.cjs +2007 -0
  208. package/dist/shared/{better-auth.B9cT0y97.d.cts → better-auth.DcwXW4BB.d.cts} +7 -3
  209. package/dist/shared/{better-auth.69-aSQxn.d.ts → better-auth.Dde0tveQ.d.ts} +1 -1
  210. package/dist/shared/{better-auth.CBQcGOAy.mjs → better-auth.Dh9fsfY2.mjs} +3 -2
  211. package/dist/shared/{better-auth.Ds-w2spb.cjs → better-auth.HT3cSIq4.cjs} +152 -74
  212. package/dist/shared/{better-auth.D0zUlh1z.cjs → better-auth.I7OjQ-oc.cjs} +3 -2
  213. package/dist/shared/{better-auth.BnAeoMet.d.cts → better-auth.VwFr4owi.d.cts} +99 -2
  214. package/dist/shared/{better-auth.BK4bljal.cjs → better-auth.Y_QHVJcB.cjs} +1 -1
  215. package/dist/shared/{better-auth.BzWvuaI6.d.ts → better-auth.bHQlVztX.d.ts} +7 -3
  216. package/dist/shared/{better-auth.CpQAMo-G.d.mts → better-auth.kvIPfj9F.d.mts} +99 -2
  217. package/dist/shared/{better-auth.ZAqiQx_W.mjs → better-auth.tST9Caqi.mjs} +1 -1
  218. package/dist/social-providers/index.cjs +2 -1
  219. package/dist/social-providers/index.d.cts +1 -1
  220. package/dist/social-providers/index.d.mts +1 -1
  221. package/dist/social-providers/index.d.ts +1 -1
  222. package/dist/social-providers/index.mjs +1 -1
  223. package/dist/test-utils/index.cjs +3 -3
  224. package/dist/test-utils/index.d.cts +76 -76
  225. package/dist/test-utils/index.d.mts +76 -76
  226. package/dist/test-utils/index.d.ts +76 -76
  227. package/dist/test-utils/index.mjs +3 -3
  228. package/dist/types/index.d.cts +3 -3
  229. package/dist/types/index.d.mts +3 -3
  230. package/dist/types/index.d.ts +3 -3
  231. package/package.json +2 -2
@@ -2,26 +2,27 @@
2
2
 
3
3
  const zod = require('zod');
4
4
  const betterCall = require('better-call');
5
- const socialProviders_index = require('../../shared/better-auth.Ds-w2spb.cjs');
5
+ const socialProviders_index = require('../../shared/better-auth.HT3cSIq4.cjs');
6
6
  const cookies_index = require('../../cookies/index.cjs');
7
7
  require('../../shared/better-auth.DcWKCjjf.cjs');
8
8
  require('../../shared/better-auth.DiSjtgs9.cjs');
9
9
  require('../../shared/better-auth.CXhVNgXP.cjs');
10
10
  require('defu');
11
- require('@better-auth/utils/hash');
11
+ const crypto_index = require('../../crypto/index.cjs');
12
+ const date = require('../../shared/better-auth.C1hdVENX.cjs');
13
+ const pluginHelper = require('../../shared/better-auth.DNqtHmvg.cjs');
14
+ const hash = require('@better-auth/utils/hash');
15
+ const base64 = require('@better-auth/utils/base64');
16
+ const random = require('../../shared/better-auth.CYeOI8C-.cjs');
17
+ require('@better-fetch/fetch');
18
+ require('jose');
12
19
  require('@noble/ciphers/chacha');
13
20
  require('@noble/ciphers/utils');
14
21
  require('@noble/ciphers/webcrypto');
15
- require('@better-auth/utils/base64');
16
- require('jose');
17
22
  require('@noble/hashes/scrypt');
18
23
  require('@better-auth/utils');
19
24
  require('@better-auth/utils/hex');
20
25
  require('@noble/hashes/utils');
21
- const random = require('../../shared/better-auth.CYeOI8C-.cjs');
22
- const date = require('../../shared/better-auth.C1hdVENX.cjs');
23
- const pluginHelper = require('../../shared/better-auth.DNqtHmvg.cjs');
24
- require('@better-fetch/fetch');
25
26
  require('../../shared/better-auth.C-R0J0n1.cjs');
26
27
  require('../../shared/better-auth.ANpbi45u.cjs');
27
28
  require('../../shared/better-auth.D3mtHEZg.cjs');
@@ -30,12 +31,31 @@ require('@better-auth/utils/binary');
30
31
  require('../../shared/better-auth.BMYo0QR-.cjs');
31
32
  require('jose/errors');
32
33
  require('@better-auth/utils/random');
34
+ require('../../shared/better-auth.YUF6P-PB.cjs');
35
+
36
+ const defaultKeyHasher = async (otp) => {
37
+ const hash$1 = await hash.createHash("SHA-256").digest(
38
+ new TextEncoder().encode(otp)
39
+ );
40
+ const hashed = base64.base64Url.encode(new Uint8Array(hash$1), {
41
+ padding: false
42
+ });
43
+ return hashed;
44
+ };
45
+ function splitAtLastColon(input) {
46
+ const idx = input.lastIndexOf(":");
47
+ if (idx === -1) {
48
+ return [input, ""];
49
+ }
50
+ return [input.slice(0, idx), input.slice(idx + 1)];
51
+ }
33
52
 
34
53
  const types = ["email-verification", "sign-in", "forget-password"];
35
54
  const emailOTP = (options) => {
36
55
  const opts = {
37
56
  expiresIn: 5 * 60,
38
57
  generateOTP: () => random.generateRandomString(options.otpLength ?? 6, "0-9"),
58
+ storeOTP: "plain",
39
59
  ...options
40
60
  };
41
61
  const ERROR_CODES = {
@@ -45,35 +65,71 @@ const emailOTP = (options) => {
45
65
  USER_NOT_FOUND: "User not found",
46
66
  TOO_MANY_ATTEMPTS: "Too many attempts"
47
67
  };
48
- return {
49
- id: "email-otp",
50
- endpoints: {
51
- sendVerificationOTP: socialProviders_index.createAuthEndpoint(
52
- "/email-otp/send-verification-otp",
53
- {
54
- method: "POST",
55
- body: zod.z.object({
56
- email: zod.z.string({
57
- description: "Email address to send the OTP"
58
- }),
59
- type: zod.z.enum(types, {
60
- description: "Type of the OTP"
61
- })
68
+ async function storeOTP(ctx, otp) {
69
+ if (opts.storeOTP === "encrypted") {
70
+ return await crypto_index.symmetricEncrypt({
71
+ key: ctx.context.secret,
72
+ data: otp
73
+ });
74
+ }
75
+ if (opts.storeOTP === "hashed") {
76
+ return await defaultKeyHasher(otp);
77
+ }
78
+ if (typeof opts.storeOTP === "object" && "hash" in opts.storeOTP) {
79
+ return await opts.storeOTP.hash(otp);
80
+ }
81
+ if (typeof opts.storeOTP === "object" && "encrypt" in opts.storeOTP) {
82
+ return await opts.storeOTP.encrypt(otp);
83
+ }
84
+ return otp;
85
+ }
86
+ async function verifyStoredOTP(ctx, storedOtp, otp) {
87
+ if (opts.storeOTP === "encrypted") {
88
+ return await crypto_index.symmetricDecrypt({
89
+ key: ctx.context.secret,
90
+ data: storedOtp
91
+ }) === otp;
92
+ }
93
+ if (opts.storeOTP === "hashed") {
94
+ const hashedOtp = await defaultKeyHasher(otp);
95
+ return hashedOtp === storedOtp;
96
+ }
97
+ if (typeof opts.storeOTP === "object" && "hash" in opts.storeOTP) {
98
+ const hashedOtp = await opts.storeOTP.hash(otp);
99
+ return hashedOtp === storedOtp;
100
+ }
101
+ if (typeof opts.storeOTP === "object" && "decrypt" in opts.storeOTP) {
102
+ const decryptedOtp = await opts.storeOTP.decrypt(storedOtp);
103
+ return decryptedOtp === otp;
104
+ }
105
+ return otp === storedOtp;
106
+ }
107
+ const endpoints = {
108
+ sendVerificationOTP: socialProviders_index.createAuthEndpoint(
109
+ "/email-otp/send-verification-otp",
110
+ {
111
+ method: "POST",
112
+ body: zod.z.object({
113
+ email: zod.z.string({
114
+ description: "Email address to send the OTP"
62
115
  }),
63
- metadata: {
64
- openapi: {
65
- description: "Send verification OTP",
66
- responses: {
67
- 200: {
68
- description: "Success",
69
- content: {
70
- "application/json": {
71
- schema: {
72
- type: "object",
73
- properties: {
74
- success: {
75
- type: "boolean"
76
- }
116
+ type: zod.z.enum(types, {
117
+ description: "Type of the OTP"
118
+ })
119
+ }),
120
+ metadata: {
121
+ openapi: {
122
+ description: "Send verification OTP",
123
+ responses: {
124
+ 200: {
125
+ description: "Success",
126
+ content: {
127
+ "application/json": {
128
+ schema: {
129
+ type: "object",
130
+ properties: {
131
+ success: {
132
+ type: "boolean"
77
133
  }
78
134
  }
79
135
  }
@@ -82,75 +138,101 @@ const emailOTP = (options) => {
82
138
  }
83
139
  }
84
140
  }
85
- },
86
- async (ctx) => {
87
- if (!options?.sendVerificationOTP) {
88
- ctx.context.logger.error(
89
- "send email verification is not implemented"
90
- );
141
+ }
142
+ },
143
+ async (ctx) => {
144
+ if (!options?.sendVerificationOTP) {
145
+ ctx.context.logger.error(
146
+ "send email verification is not implemented"
147
+ );
148
+ throw new betterCall.APIError("BAD_REQUEST", {
149
+ message: "send email verification is not implemented"
150
+ });
151
+ }
152
+ const email = ctx.body.email;
153
+ const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
154
+ if (!emailRegex.test(email)) {
155
+ throw ctx.error("BAD_REQUEST", {
156
+ message: ERROR_CODES.INVALID_EMAIL
157
+ });
158
+ }
159
+ if (opts.disableSignUp) {
160
+ const user = await ctx.context.internalAdapter.findUserByEmail(email);
161
+ if (!user) {
91
162
  throw new betterCall.APIError("BAD_REQUEST", {
92
- message: "send email verification is not implemented"
163
+ message: ERROR_CODES.USER_NOT_FOUND
93
164
  });
94
165
  }
95
- const email = ctx.body.email;
96
- const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
97
- if (!emailRegex.test(email)) {
98
- throw ctx.error("BAD_REQUEST", {
99
- message: ERROR_CODES.INVALID_EMAIL
166
+ } else if (ctx.body.type === "forget-password") {
167
+ const user = await ctx.context.internalAdapter.findUserByEmail(email);
168
+ if (!user) {
169
+ return ctx.json({
170
+ success: true
100
171
  });
101
172
  }
102
- if (opts.disableSignUp) {
103
- const user = await ctx.context.internalAdapter.findUserByEmail(email);
104
- if (!user) {
105
- throw new betterCall.APIError("BAD_REQUEST", {
106
- message: ERROR_CODES.USER_NOT_FOUND
107
- });
108
- }
109
- } else if (ctx.body.type === "forget-password") {
110
- const user = await ctx.context.internalAdapter.findUserByEmail(email);
111
- if (!user) {
112
- return ctx.json({
113
- success: true
114
- });
115
- }
116
- }
117
- const otp = opts.generateOTP(
118
- { email, type: ctx.body.type },
119
- ctx.request
173
+ }
174
+ let otp = opts.generateOTP({ email, type: ctx.body.type }, ctx.request);
175
+ let storedOTP = await storeOTP(ctx, otp);
176
+ await ctx.context.internalAdapter.createVerificationValue(
177
+ {
178
+ value: `${storedOTP}:0`,
179
+ identifier: `${ctx.body.type}-otp-${email}`,
180
+ expiresAt: date.getDate(opts.expiresIn, "sec")
181
+ },
182
+ ctx
183
+ ).catch(async (error) => {
184
+ await ctx.context.internalAdapter.deleteVerificationByIdentifier(
185
+ `${ctx.body.type}-otp-${email}`
120
186
  );
121
187
  await ctx.context.internalAdapter.createVerificationValue(
122
188
  {
123
- value: `${otp}:0`,
189
+ value: `${storedOTP}:0`,
124
190
  identifier: `${ctx.body.type}-otp-${email}`,
125
191
  expiresAt: date.getDate(opts.expiresIn, "sec")
126
192
  },
127
193
  ctx
128
- ).catch(async (error) => {
129
- await ctx.context.internalAdapter.deleteVerificationByIdentifier(
130
- `${ctx.body.type}-otp-${email}`
131
- );
132
- await ctx.context.internalAdapter.createVerificationValue(
133
- {
134
- value: `${otp}:0`,
135
- identifier: `${ctx.body.type}-otp-${email}`,
136
- expiresAt: date.getDate(opts.expiresIn, "sec")
137
- },
138
- ctx
139
- );
140
- });
141
- await options.sendVerificationOTP(
142
- {
143
- email,
144
- otp,
145
- type: ctx.body.type
146
- },
147
- ctx.request
148
194
  );
149
- return ctx.json({
150
- success: true
151
- });
195
+ });
196
+ await options.sendVerificationOTP(
197
+ {
198
+ email,
199
+ otp,
200
+ type: ctx.body.type
201
+ },
202
+ ctx.request
203
+ );
204
+ return ctx.json({
205
+ success: true
206
+ });
207
+ }
208
+ )
209
+ };
210
+ return {
211
+ id: "email-otp",
212
+ init(ctx) {
213
+ return {
214
+ options: {
215
+ emailVerification: {
216
+ ...opts.overrideDefaultEmailVerification ? {
217
+ async sendVerificationEmail(data, request) {
218
+ await endpoints.sendVerificationOTP({
219
+ //@ts-expect-error - we need to pass the context
220
+ context: ctx,
221
+ request,
222
+ body: {
223
+ email: data.user.email,
224
+ type: "email-verification"
225
+ },
226
+ ctx
227
+ });
228
+ }
229
+ } : {}
230
+ }
152
231
  }
153
- ),
232
+ };
233
+ },
234
+ endpoints: {
235
+ ...endpoints,
154
236
  createVerificationOTP: socialProviders_index.createAuthEndpoint(
155
237
  "/email-otp/create-verification-otp",
156
238
  {
@@ -188,9 +270,10 @@ const emailOTP = (options) => {
188
270
  { email, type: ctx.body.type },
189
271
  ctx.request
190
272
  );
273
+ let storedOTP = await storeOTP(ctx, otp);
191
274
  await ctx.context.internalAdapter.createVerificationValue(
192
275
  {
193
- value: `${otp}:0`,
276
+ value: `${storedOTP}:0`,
194
277
  identifier: `${ctx.body.type}-otp-${email}`,
195
278
  expiresAt: date.getDate(opts.expiresIn, "sec")
196
279
  },
@@ -246,8 +329,26 @@ const emailOTP = (options) => {
246
329
  otp: null
247
330
  });
248
331
  }
332
+ if (opts.storeOTP === "hashed" || typeof opts.storeOTP === "object" && "hash" in opts.storeOTP) {
333
+ throw new betterCall.APIError("BAD_REQUEST", {
334
+ message: "OTP is hashed, cannot return the plain text OTP"
335
+ });
336
+ }
337
+ let [storedOtp, _attempts] = splitAtLastColon(
338
+ verificationValue.value
339
+ );
340
+ let otp = storedOtp;
341
+ if (opts.storeOTP === "encrypted") {
342
+ otp = await crypto_index.symmetricDecrypt({
343
+ key: ctx.context.secret,
344
+ data: storedOtp
345
+ });
346
+ }
347
+ if (typeof opts.storeOTP === "object" && "decrypt" in opts.storeOTP) {
348
+ otp = await opts.storeOTP.decrypt(storedOtp);
349
+ }
249
350
  return ctx.json({
250
- otp: verificationValue.value
351
+ otp
251
352
  });
252
353
  }
253
354
  ),
@@ -318,7 +419,9 @@ const emailOTP = (options) => {
318
419
  message: ERROR_CODES.OTP_EXPIRED
319
420
  });
320
421
  }
321
- const [otpValue, attempts] = verificationValue.value.split(":");
422
+ const [otpValue, attempts] = splitAtLastColon(
423
+ verificationValue.value
424
+ );
322
425
  const allowedAttempts = options?.allowedAttempts || 3;
323
426
  if (attempts && parseInt(attempts) >= allowedAttempts) {
324
427
  await ctx.context.internalAdapter.deleteVerificationValue(
@@ -328,7 +431,8 @@ const emailOTP = (options) => {
328
431
  message: ERROR_CODES.TOO_MANY_ATTEMPTS
329
432
  });
330
433
  }
331
- if (ctx.body.otp !== otpValue) {
434
+ const verified = await verifyStoredOTP(ctx, otpValue, ctx.body.otp);
435
+ if (!verified) {
332
436
  await ctx.context.internalAdapter.updateVerificationValue(
333
437
  verificationValue.id,
334
438
  {
@@ -453,7 +557,9 @@ const emailOTP = (options) => {
453
557
  message: ERROR_CODES.OTP_EXPIRED
454
558
  });
455
559
  }
456
- const [otpValue, attempts] = verificationValue.value.split(":");
560
+ const [otpValue, attempts] = splitAtLastColon(
561
+ verificationValue.value
562
+ );
457
563
  const allowedAttempts = options?.allowedAttempts || 3;
458
564
  if (attempts && parseInt(attempts) >= allowedAttempts) {
459
565
  await ctx.context.internalAdapter.deleteVerificationValue(
@@ -463,7 +569,8 @@ const emailOTP = (options) => {
463
569
  message: ERROR_CODES.TOO_MANY_ATTEMPTS
464
570
  });
465
571
  }
466
- if (ctx.body.otp !== otpValue) {
572
+ const verified = await verifyStoredOTP(ctx, otpValue, ctx.body.otp);
573
+ if (!verified) {
467
574
  await ctx.context.internalAdapter.updateVerificationValue(
468
575
  verificationValue.id,
469
576
  {
@@ -589,9 +696,10 @@ const emailOTP = (options) => {
589
696
  { email, type: "forget-password" },
590
697
  ctx.request
591
698
  );
699
+ let storedOTP = await storeOTP(ctx, otp);
592
700
  await ctx.context.internalAdapter.createVerificationValue(
593
701
  {
594
- value: `${otp}:0`,
702
+ value: `${storedOTP}:0`,
595
703
  identifier: `forget-password-otp-${email}`,
596
704
  expiresAt: date.getDate(opts.expiresIn, "sec")
597
705
  },
@@ -677,7 +785,9 @@ const emailOTP = (options) => {
677
785
  message: ERROR_CODES.OTP_EXPIRED
678
786
  });
679
787
  }
680
- const [otpValue, attempts] = verificationValue.value.split(":");
788
+ const [otpValue, attempts] = splitAtLastColon(
789
+ verificationValue.value
790
+ );
681
791
  const allowedAttempts = options?.allowedAttempts || 3;
682
792
  if (attempts && parseInt(attempts) >= allowedAttempts) {
683
793
  await ctx.context.internalAdapter.deleteVerificationValue(
@@ -687,7 +797,8 @@ const emailOTP = (options) => {
687
797
  message: ERROR_CODES.TOO_MANY_ATTEMPTS
688
798
  });
689
799
  }
690
- if (ctx.body.otp !== otpValue) {
800
+ const verified = await verifyStoredOTP(ctx, otpValue, ctx.body.otp);
801
+ if (!verified) {
691
802
  await ctx.context.internalAdapter.updateVerificationValue(
692
803
  verificationValue.id,
693
804
  {
@@ -753,9 +864,10 @@ const emailOTP = (options) => {
753
864
  { email, type: ctx.body.type },
754
865
  ctx.request
755
866
  );
867
+ let storedOTP = await storeOTP(ctx, otp);
756
868
  await ctx.context.internalAdapter.createVerificationValue(
757
869
  {
758
- value: `${otp}:0`,
870
+ value: `${storedOTP}:0`,
759
871
  identifier: `email-verification-otp-${email}`,
760
872
  expiresAt: date.getDate(opts.expiresIn, "sec")
761
873
  },
@@ -1,8 +1,8 @@
1
1
  import * as better_call from 'better-call';
2
+ import { p as AuthContext, U as User, H as HookEndpointContext } from '../../shared/better-auth.1M3xAdJC.cjs';
2
3
  import { z } from 'zod';
3
- import { H as HookEndpointContext } from '../../shared/better-auth.CqTBLifU.cjs';
4
4
  import '../../shared/better-auth.9XhOL8gb.cjs';
5
- import '../../shared/better-auth.BnAeoMet.cjs';
5
+ import '../../shared/better-auth.VwFr4owi.cjs';
6
6
  import 'kysely';
7
7
  import 'better-sqlite3';
8
8
  import 'bun:sqlite';
@@ -53,81 +53,39 @@ interface EmailOTPOptions {
53
53
  * @default 3
54
54
  */
55
55
  allowedAttempts?: number;
56
+ /**
57
+ * Store the OTP in your database in a secure way
58
+ * Note: This will not affect the OTP sent to the user, it will only affect the OTP stored in your database
59
+ *
60
+ * @default "plain"
61
+ */
62
+ storeOTP?: "hashed" | "plain" | "encrypted" | {
63
+ hash: (otp: string) => Promise<string>;
64
+ } | {
65
+ encrypt: (otp: string) => Promise<string>;
66
+ decrypt: (otp: string) => Promise<string>;
67
+ };
68
+ /**
69
+ * Override the default email verification to use email otp instead
70
+ *
71
+ * @default false
72
+ */
73
+ overrideDefaultEmailVerification?: boolean;
56
74
  }
57
75
  declare const emailOTP: (options: EmailOTPOptions) => {
58
76
  id: "email-otp";
59
- endpoints: {
60
- sendVerificationOTP: {
61
- <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0: {
62
- body: {
63
- type: "sign-in" | "forget-password" | "email-verification";
64
- email: string;
65
- };
66
- } & {
67
- method?: "POST" | undefined;
68
- } & {
69
- query?: Record<string, any> | undefined;
70
- } & {
71
- params?: Record<string, any>;
72
- } & {
73
- request?: Request;
74
- } & {
75
- headers?: HeadersInit;
76
- } & {
77
- asResponse?: boolean;
78
- returnHeaders?: boolean;
79
- use?: better_call.Middleware[];
80
- path?: string;
81
- } & {
82
- asResponse?: AsResponse | undefined;
83
- returnHeaders?: ReturnHeaders | undefined;
84
- }): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
85
- headers: Headers;
86
- response: {
87
- success: boolean;
88
- };
89
- } : {
90
- success: boolean;
91
- }>;
92
- options: {
93
- method: "POST";
94
- body: z.ZodObject<{
95
- email: z.ZodString;
96
- type: z.ZodEnum<["email-verification", "sign-in", "forget-password"]>;
97
- }, "strip", z.ZodTypeAny, {
98
- type: "sign-in" | "forget-password" | "email-verification";
99
- email: string;
100
- }, {
101
- type: "sign-in" | "forget-password" | "email-verification";
102
- email: string;
103
- }>;
104
- metadata: {
105
- openapi: {
106
- description: string;
107
- responses: {
108
- 200: {
109
- description: string;
110
- content: {
111
- "application/json": {
112
- schema: {
113
- type: "object";
114
- properties: {
115
- success: {
116
- type: string;
117
- };
118
- };
119
- };
120
- };
121
- };
122
- };
123
- };
124
- };
125
- };
126
- } & {
127
- use: any[];
77
+ init(ctx: AuthContext): {
78
+ options: {
79
+ emailVerification: {
80
+ sendVerificationEmail?: ((data: {
81
+ user: User;
82
+ url: string;
83
+ token: string;
84
+ }, request: Request | undefined) => Promise<void>) | undefined;
128
85
  };
129
- path: "/email-otp/send-verification-otp";
130
86
  };
87
+ };
88
+ endpoints: {
131
89
  createVerificationOTP: {
132
90
  <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0: {
133
91
  body: {
@@ -633,6 +591,77 @@ declare const emailOTP: (options: EmailOTPOptions) => {
633
591
  };
634
592
  path: "/email-otp/reset-password";
635
593
  };
594
+ sendVerificationOTP: {
595
+ <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0: {
596
+ body: {
597
+ type: "sign-in" | "forget-password" | "email-verification";
598
+ email: string;
599
+ };
600
+ } & {
601
+ method?: "POST" | undefined;
602
+ } & {
603
+ query?: Record<string, any> | undefined;
604
+ } & {
605
+ params?: Record<string, any>;
606
+ } & {
607
+ request?: Request;
608
+ } & {
609
+ headers?: HeadersInit;
610
+ } & {
611
+ asResponse?: boolean;
612
+ returnHeaders?: boolean;
613
+ use?: better_call.Middleware[];
614
+ path?: string;
615
+ } & {
616
+ asResponse?: AsResponse | undefined;
617
+ returnHeaders?: ReturnHeaders | undefined;
618
+ }): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
619
+ headers: Headers;
620
+ response: {
621
+ success: boolean;
622
+ };
623
+ } : {
624
+ success: boolean;
625
+ }>;
626
+ options: {
627
+ method: "POST";
628
+ body: z.ZodObject<{
629
+ email: z.ZodString;
630
+ type: z.ZodEnum<["email-verification", "sign-in", "forget-password"]>;
631
+ }, "strip", z.ZodTypeAny, {
632
+ type: "sign-in" | "forget-password" | "email-verification";
633
+ email: string;
634
+ }, {
635
+ type: "sign-in" | "forget-password" | "email-verification";
636
+ email: string;
637
+ }>;
638
+ metadata: {
639
+ openapi: {
640
+ description: string;
641
+ responses: {
642
+ 200: {
643
+ description: string;
644
+ content: {
645
+ "application/json": {
646
+ schema: {
647
+ type: "object";
648
+ properties: {
649
+ success: {
650
+ type: string;
651
+ };
652
+ };
653
+ };
654
+ };
655
+ };
656
+ };
657
+ };
658
+ };
659
+ };
660
+ } & {
661
+ use: any[];
662
+ };
663
+ path: "/email-otp/send-verification-otp";
664
+ };
636
665
  };
637
666
  hooks: {
638
667
  after: {