better-auth 1.2.6-beta.7 → 1.2.7-beta.1

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 (273) hide show
  1. package/dist/adapters/drizzle-adapter/index.cjs +186 -249
  2. package/dist/adapters/drizzle-adapter/index.d.cts +11 -49
  3. package/dist/adapters/drizzle-adapter/index.d.mts +11 -49
  4. package/dist/adapters/drizzle-adapter/index.d.ts +11 -49
  5. package/dist/adapters/drizzle-adapter/index.mjs +186 -249
  6. package/dist/adapters/index.cjs +26 -0
  7. package/dist/adapters/index.d.cts +17 -0
  8. package/dist/adapters/index.d.mts +17 -0
  9. package/dist/adapters/index.d.ts +17 -0
  10. package/dist/adapters/index.mjs +20 -0
  11. package/dist/adapters/kysely-adapter/index.cjs +7 -7
  12. package/dist/adapters/kysely-adapter/index.d.cts +17 -49
  13. package/dist/adapters/kysely-adapter/index.d.mts +17 -49
  14. package/dist/adapters/kysely-adapter/index.d.ts +17 -49
  15. package/dist/adapters/kysely-adapter/index.mjs +8 -8
  16. package/dist/adapters/memory-adapter/index.cjs +7 -8
  17. package/dist/adapters/memory-adapter/index.d.cts +9 -49
  18. package/dist/adapters/memory-adapter/index.d.mts +9 -49
  19. package/dist/adapters/memory-adapter/index.d.ts +9 -49
  20. package/dist/adapters/memory-adapter/index.mjs +8 -9
  21. package/dist/adapters/mongodb-adapter/index.cjs +2 -2
  22. package/dist/adapters/mongodb-adapter/index.d.cts +4 -4
  23. package/dist/adapters/mongodb-adapter/index.d.mts +4 -4
  24. package/dist/adapters/mongodb-adapter/index.d.ts +4 -4
  25. package/dist/adapters/mongodb-adapter/index.mjs +3 -3
  26. package/dist/adapters/prisma-adapter/index.cjs +130 -203
  27. package/dist/adapters/prisma-adapter/index.d.cts +17 -49
  28. package/dist/adapters/prisma-adapter/index.d.mts +17 -49
  29. package/dist/adapters/prisma-adapter/index.d.ts +17 -49
  30. package/dist/adapters/prisma-adapter/index.mjs +131 -204
  31. package/dist/adapters/test.cjs +710 -377
  32. package/dist/adapters/test.d.cts +64 -5
  33. package/dist/adapters/test.d.mts +64 -5
  34. package/dist/adapters/test.d.ts +64 -5
  35. package/dist/adapters/test.mjs +712 -380
  36. package/dist/api/index.cjs +61 -25
  37. package/dist/api/index.d.cts +3 -3
  38. package/dist/api/index.d.mts +3 -3
  39. package/dist/api/index.d.ts +3 -3
  40. package/dist/api/index.mjs +63 -27
  41. package/dist/client/index.d.cts +3 -3
  42. package/dist/client/index.d.mts +3 -3
  43. package/dist/client/index.d.ts +3 -3
  44. package/dist/client/plugins/index.cjs +13 -15
  45. package/dist/client/plugins/index.d.cts +80 -19
  46. package/dist/client/plugins/index.d.mts +80 -19
  47. package/dist/client/plugins/index.d.ts +80 -19
  48. package/dist/client/plugins/index.mjs +13 -16
  49. package/dist/client/react/index.cjs +4 -4
  50. package/dist/client/react/index.d.cts +3 -3
  51. package/dist/client/react/index.d.mts +3 -3
  52. package/dist/client/react/index.d.ts +3 -3
  53. package/dist/client/solid/index.d.cts +3 -3
  54. package/dist/client/solid/index.d.mts +3 -3
  55. package/dist/client/solid/index.d.ts +3 -3
  56. package/dist/client/svelte/index.d.cts +3 -3
  57. package/dist/client/svelte/index.d.mts +3 -3
  58. package/dist/client/svelte/index.d.ts +3 -3
  59. package/dist/client/vue/index.d.cts +3 -3
  60. package/dist/client/vue/index.d.mts +3 -3
  61. package/dist/client/vue/index.d.ts +3 -3
  62. package/dist/cookies/index.cjs +13 -2
  63. package/dist/cookies/index.d.cts +3 -3
  64. package/dist/cookies/index.d.mts +3 -3
  65. package/dist/cookies/index.d.ts +3 -3
  66. package/dist/cookies/index.mjs +13 -2
  67. package/dist/db/index.cjs +6 -5
  68. package/dist/db/index.d.cts +4 -4
  69. package/dist/db/index.d.mts +4 -4
  70. package/dist/db/index.d.ts +4 -4
  71. package/dist/db/index.mjs +7 -6
  72. package/dist/index.cjs +11 -7
  73. package/dist/index.d.cts +4 -4
  74. package/dist/index.d.mts +4 -4
  75. package/dist/index.d.ts +4 -4
  76. package/dist/index.mjs +14 -10
  77. package/dist/integrations/next-js.cjs +4 -5
  78. package/dist/integrations/next-js.d.cts +3 -3
  79. package/dist/integrations/next-js.d.mts +3 -3
  80. package/dist/integrations/next-js.d.ts +3 -3
  81. package/dist/integrations/next-js.mjs +5 -6
  82. package/dist/integrations/node.d.cts +3 -3
  83. package/dist/integrations/node.d.mts +3 -3
  84. package/dist/integrations/node.d.ts +3 -3
  85. package/dist/integrations/react-start.cjs +5 -6
  86. package/dist/integrations/react-start.d.cts +3 -3
  87. package/dist/integrations/react-start.d.mts +3 -3
  88. package/dist/integrations/react-start.d.ts +3 -3
  89. package/dist/integrations/react-start.mjs +6 -7
  90. package/dist/integrations/svelte-kit.d.cts +3 -3
  91. package/dist/integrations/svelte-kit.d.mts +3 -3
  92. package/dist/integrations/svelte-kit.d.ts +3 -3
  93. package/dist/oauth2/index.d.cts +5 -5
  94. package/dist/oauth2/index.d.mts +5 -5
  95. package/dist/oauth2/index.d.ts +5 -5
  96. package/dist/plugins/access/index.d.cts +1 -1
  97. package/dist/plugins/access/index.d.mts +1 -1
  98. package/dist/plugins/access/index.d.ts +1 -1
  99. package/dist/plugins/admin/access/index.d.cts +1 -1
  100. package/dist/plugins/admin/access/index.d.mts +1 -1
  101. package/dist/plugins/admin/access/index.d.ts +1 -1
  102. package/dist/plugins/admin/index.cjs +4 -4
  103. package/dist/plugins/admin/index.d.cts +74 -14
  104. package/dist/plugins/admin/index.d.mts +74 -14
  105. package/dist/plugins/admin/index.d.ts +74 -14
  106. package/dist/plugins/admin/index.mjs +5 -5
  107. package/dist/plugins/anonymous/index.cjs +4 -5
  108. package/dist/plugins/anonymous/index.d.cts +3 -3
  109. package/dist/plugins/anonymous/index.d.mts +3 -3
  110. package/dist/plugins/anonymous/index.d.ts +3 -3
  111. package/dist/plugins/anonymous/index.mjs +5 -6
  112. package/dist/plugins/bearer/index.cjs +2 -2
  113. package/dist/plugins/bearer/index.d.cts +3 -3
  114. package/dist/plugins/bearer/index.d.mts +3 -3
  115. package/dist/plugins/bearer/index.d.ts +3 -3
  116. package/dist/plugins/bearer/index.mjs +3 -3
  117. package/dist/plugins/captcha/index.cjs +110 -45
  118. package/dist/plugins/captcha/index.d.cts +26 -6
  119. package/dist/plugins/captcha/index.d.mts +26 -6
  120. package/dist/plugins/captcha/index.d.ts +26 -6
  121. package/dist/plugins/captcha/index.mjs +110 -45
  122. package/dist/plugins/custom-session/index.cjs +24 -5
  123. package/dist/plugins/custom-session/index.d.cts +25 -6
  124. package/dist/plugins/custom-session/index.d.mts +25 -6
  125. package/dist/plugins/custom-session/index.d.ts +25 -6
  126. package/dist/plugins/custom-session/index.mjs +25 -6
  127. package/dist/plugins/email-otp/index.cjs +96 -30
  128. package/dist/plugins/email-otp/index.d.cts +33 -10
  129. package/dist/plugins/email-otp/index.d.mts +33 -10
  130. package/dist/plugins/email-otp/index.d.ts +33 -10
  131. package/dist/plugins/email-otp/index.mjs +97 -31
  132. package/dist/plugins/generic-oauth/index.cjs +81 -20
  133. package/dist/plugins/generic-oauth/index.d.cts +46 -3
  134. package/dist/plugins/generic-oauth/index.d.mts +46 -3
  135. package/dist/plugins/generic-oauth/index.d.ts +46 -3
  136. package/dist/plugins/generic-oauth/index.mjs +82 -21
  137. package/dist/plugins/haveibeenpwned/index.cjs +98 -0
  138. package/dist/plugins/haveibeenpwned/index.d.cts +36 -0
  139. package/dist/plugins/haveibeenpwned/index.d.mts +36 -0
  140. package/dist/plugins/haveibeenpwned/index.d.ts +36 -0
  141. package/dist/plugins/haveibeenpwned/index.mjs +96 -0
  142. package/dist/plugins/index.cjs +583 -19
  143. package/dist/plugins/index.d.cts +7 -5
  144. package/dist/plugins/index.d.mts +7 -5
  145. package/dist/plugins/index.d.ts +7 -5
  146. package/dist/plugins/index.mjs +583 -21
  147. package/dist/plugins/jwt/index.cjs +45 -21
  148. package/dist/plugins/jwt/index.d.cts +52 -6
  149. package/dist/plugins/jwt/index.d.mts +52 -6
  150. package/dist/plugins/jwt/index.d.ts +52 -6
  151. package/dist/plugins/jwt/index.mjs +46 -22
  152. package/dist/plugins/magic-link/index.cjs +3 -3
  153. package/dist/plugins/magic-link/index.mjs +4 -4
  154. package/dist/plugins/multi-session/index.cjs +3 -3
  155. package/dist/plugins/multi-session/index.d.cts +3 -3
  156. package/dist/plugins/multi-session/index.d.mts +3 -3
  157. package/dist/plugins/multi-session/index.d.ts +3 -3
  158. package/dist/plugins/multi-session/index.mjs +4 -4
  159. package/dist/plugins/oauth-proxy/index.cjs +4 -4
  160. package/dist/plugins/oauth-proxy/index.d.cts +3 -3
  161. package/dist/plugins/oauth-proxy/index.d.mts +3 -3
  162. package/dist/plugins/oauth-proxy/index.d.ts +3 -3
  163. package/dist/plugins/oauth-proxy/index.mjs +5 -5
  164. package/dist/plugins/oidc-provider/index.cjs +227 -8
  165. package/dist/plugins/oidc-provider/index.d.cts +215 -3
  166. package/dist/plugins/oidc-provider/index.d.mts +215 -3
  167. package/dist/plugins/oidc-provider/index.d.ts +215 -3
  168. package/dist/plugins/oidc-provider/index.mjs +228 -9
  169. package/dist/plugins/one-tap/index.cjs +5 -5
  170. package/dist/plugins/one-tap/index.mjs +6 -6
  171. package/dist/plugins/one-time-token/index.cjs +119 -0
  172. package/dist/plugins/one-time-token/index.d.cts +134 -0
  173. package/dist/plugins/one-time-token/index.d.mts +134 -0
  174. package/dist/plugins/one-time-token/index.d.ts +134 -0
  175. package/dist/plugins/one-time-token/index.mjs +117 -0
  176. package/dist/plugins/open-api/index.cjs +3 -3
  177. package/dist/plugins/open-api/index.d.cts +3 -3
  178. package/dist/plugins/open-api/index.d.mts +3 -3
  179. package/dist/plugins/open-api/index.d.ts +3 -3
  180. package/dist/plugins/open-api/index.mjs +4 -4
  181. package/dist/plugins/organization/access/index.d.cts +1 -1
  182. package/dist/plugins/organization/access/index.d.mts +1 -1
  183. package/dist/plugins/organization/access/index.d.ts +1 -1
  184. package/dist/plugins/organization/index.cjs +4 -4
  185. package/dist/plugins/organization/index.d.cts +708 -55
  186. package/dist/plugins/organization/index.d.mts +708 -55
  187. package/dist/plugins/organization/index.d.ts +708 -55
  188. package/dist/plugins/organization/index.mjs +5 -5
  189. package/dist/plugins/passkey/index.cjs +82 -8
  190. package/dist/plugins/passkey/index.d.cts +72 -3
  191. package/dist/plugins/passkey/index.d.mts +72 -3
  192. package/dist/plugins/passkey/index.d.ts +72 -3
  193. package/dist/plugins/passkey/index.mjs +83 -9
  194. package/dist/plugins/phone-number/index.cjs +194 -26
  195. package/dist/plugins/phone-number/index.d.cts +132 -8
  196. package/dist/plugins/phone-number/index.d.mts +132 -8
  197. package/dist/plugins/phone-number/index.d.ts +132 -8
  198. package/dist/plugins/phone-number/index.mjs +195 -27
  199. package/dist/plugins/sso/index.cjs +190 -7
  200. package/dist/plugins/sso/index.d.cts +181 -15
  201. package/dist/plugins/sso/index.d.mts +181 -15
  202. package/dist/plugins/sso/index.d.ts +181 -15
  203. package/dist/plugins/sso/index.mjs +191 -8
  204. package/dist/plugins/two-factor/index.cjs +443 -92
  205. package/dist/plugins/two-factor/index.d.cts +230 -396
  206. package/dist/plugins/two-factor/index.d.mts +230 -396
  207. package/dist/plugins/two-factor/index.d.ts +230 -396
  208. package/dist/plugins/two-factor/index.mjs +431 -80
  209. package/dist/plugins/username/index.cjs +34 -31
  210. package/dist/plugins/username/index.d.cts +15 -12
  211. package/dist/plugins/username/index.d.mts +15 -12
  212. package/dist/plugins/username/index.d.ts +15 -12
  213. package/dist/plugins/username/index.mjs +35 -32
  214. package/dist/shared/better-auth.1DR6suCQ.mjs +307 -0
  215. package/dist/shared/{better-auth.BSsp73pg.cjs → better-auth.B7cZ2juS.cjs} +15 -14
  216. package/dist/shared/{better-auth.bKwabe3I.d.mts → better-auth.B88xucNq.d.mts} +529 -39
  217. package/dist/shared/{better-auth.CApEjVDP.cjs → better-auth.BW8BpneG.cjs} +4 -1
  218. package/dist/shared/{better-auth.BiQsvaIP.d.cts → better-auth.BcU1Kjyq.d.cts} +2051 -518
  219. package/dist/shared/better-auth.BfG24BjZ.cjs +118 -0
  220. package/dist/shared/{better-auth.A3TjrU8G.mjs → better-auth.Bk5IMdhM.mjs} +32 -12
  221. package/dist/shared/{better-auth.D9VnBkRI.mjs → better-auth.Bm9HxIzE.mjs} +47 -24
  222. package/dist/shared/{better-auth.BRf6Iynu.d.ts → better-auth.Bwc-6kOr.d.ts} +1 -1
  223. package/dist/shared/{better-auth.D-oLmHIj.d.mts → better-auth.CA2hFK4N.d.ts} +2051 -518
  224. package/dist/shared/{better-auth.Dmhe30iW.d.mts → better-auth.CGukGrxT.d.cts} +1 -1
  225. package/dist/shared/{better-auth.CsSpq0zL.cjs → better-auth.CHUzBidy.cjs} +46 -23
  226. package/dist/shared/{better-auth.DWRligF8.d.cts → better-auth.CT9J6rD-.d.cts} +539 -7
  227. package/dist/shared/better-auth.CVCo5Z2T.cjs +310 -0
  228. package/dist/shared/{better-auth.D4jH-sJA.mjs → better-auth.CWwVo_61.mjs} +458 -118
  229. package/dist/shared/{better-auth.Bi8FQwDD.d.cts → better-auth.CYegVoq1.d.cts} +1 -1
  230. package/dist/shared/{better-auth.Bi8FQwDD.d.mts → better-auth.CYegVoq1.d.mts} +1 -1
  231. package/dist/shared/{better-auth.Bi8FQwDD.d.ts → better-auth.CYegVoq1.d.ts} +1 -1
  232. package/dist/shared/{better-auth.CepcSj5H.mjs → better-auth.Cc72UxUH.mjs} +1 -2
  233. package/dist/shared/{better-auth.BWp5dztg.d.ts → better-auth.CmN4mlPh.d.ts} +539 -7
  234. package/dist/shared/{better-auth.DH3YjMQH.mjs → better-auth.Cqykj82J.mjs} +1 -1
  235. package/dist/shared/{better-auth.wcdMj2cT.d.mts → better-auth.DIt2e3lu.d.mts} +539 -7
  236. package/dist/shared/{better-auth.BANAxdkL.d.ts → better-auth.DNTAFSt1.d.ts} +529 -39
  237. package/dist/shared/{better-auth.DU2QNVc_.d.ts → better-auth.DQ7OSJbI.d.mts} +2051 -518
  238. package/dist/shared/{better-auth.DLTzKoOS.cjs → better-auth.DSVbLSt7.cjs} +4 -1
  239. package/dist/shared/{better-auth.B2Fw1vhH.d.cts → better-auth.DTiSPWEk.d.cts} +529 -39
  240. package/dist/shared/better-auth.DURsStt9.mjs +116 -0
  241. package/dist/shared/{better-auth.BIjcZ_vt.cjs → better-auth.DYoLD99C.cjs} +31 -11
  242. package/dist/shared/{better-auth.CV1L7TPV.cjs → better-auth.D_ZIX1O8.cjs} +317 -47
  243. package/dist/shared/{better-auth.C5H9XEzZ.cjs → better-auth.DcWKCjjf.cjs} +1 -2
  244. package/dist/shared/{better-auth.BDYXUcLv.cjs → better-auth.Dg0siV5C.cjs} +457 -117
  245. package/dist/shared/better-auth.DjryM8pE.cjs +760 -0
  246. package/dist/shared/{better-auth.DPBQN9Fs.mjs → better-auth.Dn_Ms1Uf.mjs} +318 -48
  247. package/dist/shared/{better-auth.DiG4KL2x.mjs → better-auth.OuYYTHC7.mjs} +4 -1
  248. package/dist/shared/{better-auth.DtC8i3pf.d.cts → better-auth.S1jimRbX.d.mts} +1 -1
  249. package/dist/shared/better-auth.SPmq4a4z.d.mts +344 -0
  250. package/dist/shared/{better-auth.cOCrlspr.mjs → better-auth.bkwPl2G4.mjs} +4 -1
  251. package/dist/shared/better-auth.cp2rC2iM.d.ts +344 -0
  252. package/dist/shared/better-auth.eVy4DZvP.d.cts +344 -0
  253. package/dist/shared/{better-auth.BrOpzmqo.mjs → better-auth.iKoUsdFE.mjs} +15 -14
  254. package/dist/shared/better-auth.rSYJCd3o.mjs +758 -0
  255. package/dist/social-providers/index.cjs +75 -3
  256. package/dist/social-providers/index.d.cts +2 -2
  257. package/dist/social-providers/index.d.mts +2 -2
  258. package/dist/social-providers/index.d.ts +2 -2
  259. package/dist/social-providers/index.mjs +77 -6
  260. package/dist/types/index.d.cts +4 -4
  261. package/dist/types/index.d.mts +4 -4
  262. package/dist/types/index.d.ts +4 -4
  263. package/package.json +42 -5
  264. package/dist/chunks/server.cjs +0 -905
  265. package/dist/chunks/server.mjs +0 -895
  266. package/dist/shared/better-auth.BcoSd9tC.mjs +0 -10
  267. package/dist/shared/better-auth.BnRFp-t0.mjs +0 -405
  268. package/dist/shared/better-auth.C1-vpKly.cjs +0 -12
  269. package/dist/shared/better-auth.ClTSOgiD.mjs +0 -140
  270. package/dist/shared/better-auth.DC8JQbiE.mjs +0 -173
  271. package/dist/shared/better-auth.DWHWPllD.cjs +0 -175
  272. package/dist/shared/better-auth.DqLjzBlO.cjs +0 -408
  273. package/dist/shared/better-auth.m575EIBC.cjs +0 -144
@@ -1,20 +1,19 @@
1
1
  import { g as generateRandomString } from '../../shared/better-auth.B4Qoxdgc.mjs';
2
2
  import { z } from 'zod';
3
- import { a as createAuthEndpoint, s as sessionMiddleware, c as createAuthMiddleware, B as BASE_ERROR_CODES } from '../../shared/better-auth.D4jH-sJA.mjs';
3
+ import { g as getSessionFromCtx, a as createAuthEndpoint, s as sessionMiddleware, B as BASE_ERROR_CODES, c as createAuthMiddleware } from '../../shared/better-auth.CWwVo_61.mjs';
4
4
  import { APIError } from 'better-call';
5
5
  import { setSessionCookie, deleteSessionCookie } from '../../cookies/index.mjs';
6
- import { m as mergeSchema } from '../../shared/better-auth.CepcSj5H.mjs';
6
+ import { m as mergeSchema } from '../../shared/better-auth.Cc72UxUH.mjs';
7
7
  import '../../shared/better-auth.8zoxzg-F.mjs';
8
- import '../../shared/better-auth.DH3YjMQH.mjs';
8
+ import '../../shared/better-auth.Cqykj82J.mjs';
9
9
  import 'defu';
10
10
  import { symmetricEncrypt, symmetricDecrypt } from '../../crypto/index.mjs';
11
- import { v as verifyTwoFactorMiddleware, T as TRUST_DEVICE_COOKIE_NAME, a as TWO_FACTOR_COOKIE_NAME } from '../../shared/better-auth.ClTSOgiD.mjs';
12
- import { T as TWO_FACTOR_ERROR_CODES } from '../../shared/better-auth.BcoSd9tC.mjs';
11
+ import '@better-auth/utils/base64';
12
+ import { createHMAC } from '@better-auth/utils/hmac';
13
13
  import '@better-auth/utils/hash';
14
14
  import '@noble/ciphers/chacha';
15
15
  import '@noble/ciphers/utils';
16
16
  import '@noble/ciphers/webcrypto';
17
- import '@better-auth/utils/base64';
18
17
  import 'jose';
19
18
  import '@noble/hashes/scrypt';
20
19
  import '@better-auth/utils';
@@ -22,7 +21,6 @@ import '@better-auth/utils/hex';
22
21
  import '@noble/hashes/utils';
23
22
  import { createOTP } from '@better-auth/utils/otp';
24
23
  import { v as validatePassword } from '../../shared/better-auth.YwDQhoPc.mjs';
25
- import { createHMAC } from '@better-auth/utils/hmac';
26
24
  export { t as twoFactorClient } from '../../shared/better-auth.Ddw8bVyV.mjs';
27
25
  import '@better-auth/utils/random';
28
26
  import '../../social-providers/index.mjs';
@@ -31,14 +29,151 @@ import '../../shared/better-auth.DCVeP5-W.mjs';
31
29
  import '../../shared/better-auth.CW6D9eSx.mjs';
32
30
  import '../../shared/better-auth.DdzSJf-n.mjs';
33
31
  import '../../shared/better-auth.BdyOG_p4.mjs';
32
+ import '../../shared/better-auth.tB5eU6EY.mjs';
34
33
  import '../../shared/better-auth.BUPPRXfK.mjs';
35
34
  import '../../shared/better-auth.DDEbWX-S.mjs';
36
35
  import '../../shared/better-auth.VTXNLFMT.mjs';
37
36
  import 'jose/errors';
38
- import '../../shared/better-auth.tB5eU6EY.mjs';
39
37
  import '@better-auth/utils/binary';
40
38
  import '../../shared/better-auth.OT3XFeFk.mjs';
41
39
 
40
+ const TWO_FACTOR_ERROR_CODES = {
41
+ OTP_NOT_ENABLED: "OTP not enabled",
42
+ OTP_HAS_EXPIRED: "OTP has expired",
43
+ TOTP_NOT_ENABLED: "TOTP not enabled",
44
+ TWO_FACTOR_NOT_ENABLED: "Two factor isn't enabled",
45
+ BACKUP_CODES_NOT_ENABLED: "Backup codes aren't enabled",
46
+ INVALID_BACKUP_CODE: "Invalid backup code",
47
+ INVALID_CODE: "Invalid code",
48
+ TOO_MANY_ATTEMPTS_REQUEST_NEW_CODE: "Too many attempts. Please request a new code.",
49
+ INVALID_TWO_FACTOR_COOKIE: "Invalid two factor cookie"
50
+ };
51
+
52
+ const TWO_FACTOR_COOKIE_NAME = "two_factor";
53
+ const TRUST_DEVICE_COOKIE_NAME = "trust_device";
54
+
55
+ async function verifyTwoFactor(ctx) {
56
+ const session = await getSessionFromCtx(ctx);
57
+ if (!session) {
58
+ const cookieName = ctx.context.createAuthCookie(TWO_FACTOR_COOKIE_NAME);
59
+ const twoFactorCookie = await ctx.getSignedCookie(
60
+ cookieName.name,
61
+ ctx.context.secret
62
+ );
63
+ if (!twoFactorCookie) {
64
+ throw new APIError("UNAUTHORIZED", {
65
+ message: TWO_FACTOR_ERROR_CODES.INVALID_TWO_FACTOR_COOKIE
66
+ });
67
+ }
68
+ const verificationToken = await ctx.context.internalAdapter.findVerificationValue(twoFactorCookie);
69
+ if (!verificationToken) {
70
+ throw new APIError("UNAUTHORIZED", {
71
+ message: TWO_FACTOR_ERROR_CODES.INVALID_TWO_FACTOR_COOKIE
72
+ });
73
+ }
74
+ const user = await ctx.context.internalAdapter.findUserById(
75
+ verificationToken.value
76
+ );
77
+ if (!user) {
78
+ throw new APIError("UNAUTHORIZED", {
79
+ message: TWO_FACTOR_ERROR_CODES.INVALID_TWO_FACTOR_COOKIE
80
+ });
81
+ }
82
+ const dontRememberMe = await ctx.getSignedCookie(
83
+ ctx.context.authCookies.dontRememberToken.name,
84
+ ctx.context.secret
85
+ );
86
+ return {
87
+ valid: async (ctx2) => {
88
+ const session2 = await ctx2.context.internalAdapter.createSession(
89
+ verificationToken.value,
90
+ ctx2.headers,
91
+ !!dontRememberMe
92
+ );
93
+ if (!session2) {
94
+ throw new APIError("INTERNAL_SERVER_ERROR", {
95
+ message: "failed to create session"
96
+ });
97
+ }
98
+ await setSessionCookie(ctx2, {
99
+ session: session2,
100
+ user
101
+ });
102
+ if (ctx2.body.trustDevice) {
103
+ const trustDeviceCookie = ctx2.context.createAuthCookie(
104
+ TRUST_DEVICE_COOKIE_NAME,
105
+ {
106
+ maxAge: 30 * 24 * 60 * 60
107
+ // 30 days, it'll be refreshed on sign in requests
108
+ }
109
+ );
110
+ const token = await createHMAC("SHA-256", "base64urlnopad").sign(
111
+ ctx2.context.secret,
112
+ `${user.id}!${session2.token}`
113
+ );
114
+ await ctx2.setSignedCookie(
115
+ trustDeviceCookie.name,
116
+ `${token}!${session2.token}`,
117
+ ctx2.context.secret,
118
+ trustDeviceCookie.attributes
119
+ );
120
+ ctx2.setCookie(ctx2.context.authCookies.dontRememberToken.name, "", {
121
+ maxAge: 0
122
+ });
123
+ ctx2.setCookie(cookieName.name, "", {
124
+ maxAge: 0
125
+ });
126
+ }
127
+ return ctx2.json({
128
+ token: session2.token,
129
+ user: {
130
+ id: user.id,
131
+ email: user.email,
132
+ emailVerified: user.emailVerified,
133
+ name: user.name,
134
+ image: user.image,
135
+ createdAt: user.createdAt,
136
+ updatedAt: user.updatedAt
137
+ }
138
+ });
139
+ },
140
+ invalid: async (errorKey) => {
141
+ throw new APIError("UNAUTHORIZED", {
142
+ message: TWO_FACTOR_ERROR_CODES[errorKey]
143
+ });
144
+ },
145
+ session: {
146
+ session: null,
147
+ user
148
+ },
149
+ key: twoFactorCookie
150
+ };
151
+ }
152
+ return {
153
+ valid: async (ctx2) => {
154
+ return ctx2.json({
155
+ token: session.session.token,
156
+ user: {
157
+ id: session.user.id,
158
+ email: session.user.email,
159
+ emailVerified: session.user.emailVerified,
160
+ name: session.user.name,
161
+ image: session.user.image,
162
+ createdAt: session.user.createdAt,
163
+ updatedAt: session.user.updatedAt
164
+ }
165
+ });
166
+ },
167
+ invalid: async () => {
168
+ throw new APIError("UNAUTHORIZED", {
169
+ message: TWO_FACTOR_ERROR_CODES.INVALID_TWO_FACTOR_COOKIE
170
+ });
171
+ },
172
+ session,
173
+ key: `${session.user.id}!${session.session.id}`
174
+ };
175
+ }
176
+
42
177
  function generateBackupCodesFn(options) {
43
178
  return Array.from({ length: options?.amount ?? 10 }).fill(null).map(() => generateRandomString(options?.length ?? 10, "a-z", "0-9", "A-Z")).map((code) => `${code.slice(0, 5)}-${code.slice(5)}`);
44
179
  }
@@ -106,10 +241,112 @@ const backupCode2fa = (options) => {
106
241
  description: "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time."
107
242
  }).optional()
108
243
  }),
109
- use: [verifyTwoFactorMiddleware]
244
+ metadata: {
245
+ openapi: {
246
+ description: "Verify a backup code for two-factor authentication",
247
+ responses: {
248
+ "200": {
249
+ description: "Backup code verified successfully",
250
+ content: {
251
+ "application/json": {
252
+ schema: {
253
+ type: "object",
254
+ properties: {
255
+ user: {
256
+ type: "object",
257
+ properties: {
258
+ id: {
259
+ type: "string",
260
+ description: "Unique identifier of the user"
261
+ },
262
+ email: {
263
+ type: "string",
264
+ format: "email",
265
+ nullable: true,
266
+ description: "User's email address"
267
+ },
268
+ emailVerified: {
269
+ type: "boolean",
270
+ nullable: true,
271
+ description: "Whether the email is verified"
272
+ },
273
+ name: {
274
+ type: "string",
275
+ nullable: true,
276
+ description: "User's name"
277
+ },
278
+ image: {
279
+ type: "string",
280
+ format: "uri",
281
+ nullable: true,
282
+ description: "User's profile image URL"
283
+ },
284
+ twoFactorEnabled: {
285
+ type: "boolean",
286
+ description: "Whether two-factor authentication is enabled for the user"
287
+ },
288
+ createdAt: {
289
+ type: "string",
290
+ format: "date-time",
291
+ description: "Timestamp when the user was created"
292
+ },
293
+ updatedAt: {
294
+ type: "string",
295
+ format: "date-time",
296
+ description: "Timestamp when the user was last updated"
297
+ }
298
+ },
299
+ required: [
300
+ "id",
301
+ "twoFactorEnabled",
302
+ "createdAt",
303
+ "updatedAt"
304
+ ],
305
+ description: "The authenticated user object with two-factor details"
306
+ },
307
+ session: {
308
+ type: "object",
309
+ properties: {
310
+ token: {
311
+ type: "string",
312
+ description: "Session token"
313
+ },
314
+ userId: {
315
+ type: "string",
316
+ description: "ID of the user associated with the session"
317
+ },
318
+ createdAt: {
319
+ type: "string",
320
+ format: "date-time",
321
+ description: "Timestamp when the session was created"
322
+ },
323
+ expiresAt: {
324
+ type: "string",
325
+ format: "date-time",
326
+ description: "Timestamp when the session expires"
327
+ }
328
+ },
329
+ required: [
330
+ "token",
331
+ "userId",
332
+ "createdAt",
333
+ "expiresAt"
334
+ ],
335
+ description: "The current session object, included unless disableSession is true"
336
+ }
337
+ },
338
+ required: ["user", "session"]
339
+ }
340
+ }
341
+ }
342
+ }
343
+ }
344
+ }
345
+ }
110
346
  },
111
347
  async (ctx) => {
112
- const user = ctx.context.session.user;
348
+ const { session, valid } = await verifyTwoFactor(ctx);
349
+ const user = session.user;
113
350
  const twoFactor = await ctx.context.adapter.findOne({
114
351
  model: twoFactorTable,
115
352
  where: [
@@ -153,14 +390,19 @@ const backupCode2fa = (options) => {
153
390
  ]
154
391
  });
155
392
  if (!ctx.body.disableSession) {
156
- await setSessionCookie(ctx, {
157
- session: ctx.context.session.session,
158
- user
159
- });
393
+ return valid(ctx);
160
394
  }
161
395
  return ctx.json({
162
- user,
163
- session: ctx.context.session
396
+ token: session.session?.token,
397
+ user: {
398
+ id: session.user?.id,
399
+ email: session.user.email,
400
+ emailVerified: session.user.emailVerified,
401
+ name: session.user.name,
402
+ image: session.user.image,
403
+ createdAt: session.user.createdAt,
404
+ updatedAt: session.user.updatedAt
405
+ }
164
406
  });
165
407
  }
166
408
  ),
@@ -171,7 +413,37 @@ const backupCode2fa = (options) => {
171
413
  body: z.object({
172
414
  password: z.string()
173
415
  }),
174
- use: [sessionMiddleware]
416
+ use: [sessionMiddleware],
417
+ metadata: {
418
+ openapi: {
419
+ description: "Generate new backup codes for two-factor authentication",
420
+ responses: {
421
+ "200": {
422
+ description: "Backup codes generated successfully",
423
+ content: {
424
+ "application/json": {
425
+ schema: {
426
+ type: "object",
427
+ properties: {
428
+ status: {
429
+ type: "boolean",
430
+ description: "Indicates if the backup codes were generated successfully",
431
+ enum: [true]
432
+ },
433
+ backupCodes: {
434
+ type: "array",
435
+ items: { type: "string" },
436
+ description: "Array of generated backup codes in plain text"
437
+ }
438
+ },
439
+ required: ["status", "backupCodes"]
440
+ }
441
+ }
442
+ }
443
+ }
444
+ }
445
+ }
446
+ }
175
447
  },
176
448
  async (ctx) => {
177
449
  const user = ctx.context.session.user;
@@ -267,7 +539,6 @@ const otp2fa = (options) => {
267
539
  */
268
540
  trustDevice: z.boolean().optional()
269
541
  }).optional(),
270
- use: [verifyTwoFactorMiddleware],
271
542
  metadata: {
272
543
  openapi: {
273
544
  summary: "Send two factor OTP",
@@ -301,13 +572,13 @@ const otp2fa = (options) => {
301
572
  message: "otp isn't configured"
302
573
  });
303
574
  }
304
- const user = ctx.context.session.user;
575
+ const { session, key } = await verifyTwoFactor(ctx);
305
576
  const twoFactor = await ctx.context.adapter.findOne({
306
577
  model: twoFactorTable,
307
578
  where: [
308
579
  {
309
580
  field: "userId",
310
- value: user.id
581
+ value: session.user.id
311
582
  }
312
583
  ]
313
584
  });
@@ -318,11 +589,14 @@ const otp2fa = (options) => {
318
589
  }
319
590
  const code = generateRandomString(opts.digits, "0-9");
320
591
  await ctx.context.internalAdapter.createVerificationValue({
321
- value: code,
322
- identifier: `2fa-otp-${user.id}`,
592
+ value: `${code}!0`,
593
+ identifier: `2fa-otp-${key}`,
323
594
  expiresAt: new Date(Date.now() + opts.period)
324
595
  });
325
- await options.sendOTP({ user, otp: code }, ctx.request);
596
+ await options.sendOTP(
597
+ { user: session.user, otp: code },
598
+ ctx.request
599
+ );
326
600
  return ctx.json({ status: true });
327
601
  }
328
602
  );
@@ -341,23 +615,67 @@ const otp2fa = (options) => {
341
615
  */
342
616
  trustDevice: z.boolean().optional()
343
617
  }),
344
- use: [verifyTwoFactorMiddleware],
345
618
  metadata: {
346
619
  openapi: {
347
620
  summary: "Verify two factor OTP",
348
621
  description: "Verify two factor OTP",
349
622
  responses: {
350
- 200: {
351
- description: "Success",
623
+ "200": {
624
+ description: "Two-factor OTP verified successfully",
352
625
  content: {
353
626
  "application/json": {
354
627
  schema: {
355
628
  type: "object",
356
629
  properties: {
357
- status: {
358
- type: "boolean"
630
+ token: {
631
+ type: "string",
632
+ description: "Session token for the authenticated session"
633
+ },
634
+ user: {
635
+ type: "object",
636
+ properties: {
637
+ id: {
638
+ type: "string",
639
+ description: "Unique identifier of the user"
640
+ },
641
+ email: {
642
+ type: "string",
643
+ format: "email",
644
+ nullable: true,
645
+ description: "User's email address"
646
+ },
647
+ emailVerified: {
648
+ type: "boolean",
649
+ nullable: true,
650
+ description: "Whether the email is verified"
651
+ },
652
+ name: {
653
+ type: "string",
654
+ nullable: true,
655
+ description: "User's name"
656
+ },
657
+ image: {
658
+ type: "string",
659
+ format: "uri",
660
+ nullable: true,
661
+ description: "User's profile image URL"
662
+ },
663
+ createdAt: {
664
+ type: "string",
665
+ format: "date-time",
666
+ description: "Timestamp when the user was created"
667
+ },
668
+ updatedAt: {
669
+ type: "string",
670
+ format: "date-time",
671
+ description: "Timestamp when the user was last updated"
672
+ }
673
+ },
674
+ required: ["id", "createdAt", "updatedAt"],
675
+ description: "The authenticated user object"
359
676
  }
360
- }
677
+ },
678
+ required: ["token", "user"]
361
679
  }
362
680
  }
363
681
  }
@@ -367,13 +685,13 @@ const otp2fa = (options) => {
367
685
  }
368
686
  },
369
687
  async (ctx) => {
370
- const user = ctx.context.session.user;
688
+ const { session, key, valid, invalid } = await verifyTwoFactor(ctx);
371
689
  const twoFactor = await ctx.context.adapter.findOne({
372
690
  model: twoFactorTable,
373
691
  where: [
374
692
  {
375
693
  field: "userId",
376
- value: user.id
694
+ value: session.user.id
377
695
  }
378
696
  ]
379
697
  });
@@ -383,38 +701,74 @@ const otp2fa = (options) => {
383
701
  });
384
702
  }
385
703
  const toCheckOtp = await ctx.context.internalAdapter.findVerificationValue(
386
- `2fa-otp-${user.id}`
704
+ `2fa-otp-${key}`
387
705
  );
706
+ const [otp, counter] = toCheckOtp?.value?.split("!") ?? [];
388
707
  if (!toCheckOtp || toCheckOtp.expiresAt < /* @__PURE__ */ new Date()) {
708
+ await ctx.context.internalAdapter.deleteVerificationValue(
709
+ `2fa-otp-${key}`
710
+ );
389
711
  throw new APIError("BAD_REQUEST", {
390
712
  message: TWO_FACTOR_ERROR_CODES.OTP_HAS_EXPIRED
391
713
  });
392
714
  }
393
- if (toCheckOtp.value === ctx.body.code) {
394
- if (!user.twoFactorEnabled) {
715
+ const allowedAttempts = options?.allowedAttempts || 5;
716
+ if (parseInt(counter) >= allowedAttempts) {
717
+ await ctx.context.internalAdapter.deleteVerificationValue(
718
+ `2fa-otp-${key}`
719
+ );
720
+ throw new APIError("BAD_REQUEST", {
721
+ message: TWO_FACTOR_ERROR_CODES.TOO_MANY_ATTEMPTS_REQUEST_NEW_CODE
722
+ });
723
+ }
724
+ if (otp === ctx.body.code) {
725
+ if (!session.user.twoFactorEnabled) {
726
+ if (!session.session) {
727
+ throw new APIError("BAD_REQUEST", {
728
+ message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION
729
+ });
730
+ }
395
731
  const updatedUser = await ctx.context.internalAdapter.updateUser(
396
- user.id,
732
+ session.user.id,
397
733
  {
398
734
  twoFactorEnabled: true
399
735
  }
400
736
  );
401
737
  const newSession = await ctx.context.internalAdapter.createSession(
402
- user.id,
403
- ctx.request,
738
+ session.user.id,
739
+ ctx.headers,
404
740
  false,
405
- ctx.context.session.session
741
+ session.session
406
742
  );
407
743
  await ctx.context.internalAdapter.deleteSession(
408
- ctx.context.session.session.token
744
+ session.session.token
409
745
  );
410
746
  await setSessionCookie(ctx, {
411
747
  session: newSession,
412
748
  user: updatedUser
413
749
  });
750
+ return ctx.json({
751
+ token: newSession.token,
752
+ user: {
753
+ id: updatedUser.id,
754
+ email: updatedUser.email,
755
+ emailVerified: updatedUser.emailVerified,
756
+ name: updatedUser.name,
757
+ image: updatedUser.image,
758
+ createdAt: updatedUser.createdAt,
759
+ updatedAt: updatedUser.updatedAt
760
+ }
761
+ });
414
762
  }
415
- return ctx.context.valid(ctx);
763
+ return valid(ctx);
416
764
  } else {
417
- return ctx.context.invalid();
765
+ await ctx.context.internalAdapter.updateVerificationValue(
766
+ toCheckOtp.id,
767
+ {
768
+ value: `${otp}!${parseInt(counter) + 1}`
769
+ }
770
+ );
771
+ return invalid("INVALID_CODE");
418
772
  }
419
773
  }
420
774
  );
@@ -438,7 +792,11 @@ const totp2fa = (options) => {
438
792
  "/totp/generate",
439
793
  {
440
794
  method: "POST",
441
- use: [sessionMiddleware],
795
+ body: z.object({
796
+ secret: z.string({
797
+ description: "The secret to generate the TOTP code"
798
+ })
799
+ }),
442
800
  metadata: {
443
801
  openapi: {
444
802
  summary: "Generate TOTP code",
@@ -460,7 +818,8 @@ const totp2fa = (options) => {
460
818
  }
461
819
  }
462
820
  }
463
- }
821
+ },
822
+ SERVER_ONLY: true
464
823
  }
465
824
  },
466
825
  async (ctx) => {
@@ -472,22 +831,7 @@ const totp2fa = (options) => {
472
831
  message: "totp isn't configured"
473
832
  });
474
833
  }
475
- const user = ctx.context.session.user;
476
- const twoFactor = await ctx.context.adapter.findOne({
477
- model: twoFactorTable,
478
- where: [
479
- {
480
- field: "userId",
481
- value: user.id
482
- }
483
- ]
484
- });
485
- if (!twoFactor) {
486
- throw new APIError("BAD_REQUEST", {
487
- message: TWO_FACTOR_ERROR_CODES.TOTP_NOT_ENABLED
488
- });
489
- }
490
- const code = await createOTP(twoFactor.secret, {
834
+ const code = await createOTP(ctx.body.secret, {
491
835
  period: opts.period,
492
836
  digits: opts.digits
493
837
  }).totp();
@@ -583,7 +927,6 @@ const totp2fa = (options) => {
583
927
  description: "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time."
584
928
  }).optional()
585
929
  }),
586
- use: [verifyTwoFactorMiddleware],
587
930
  metadata: {
588
931
  openapi: {
589
932
  summary: "Verify two factor TOTP",
@@ -617,7 +960,8 @@ const totp2fa = (options) => {
617
960
  message: "totp isn't configured"
618
961
  });
619
962
  }
620
- const user = ctx.context.session.user;
963
+ const { session, valid, invalid } = await verifyTwoFactor(ctx);
964
+ const user = session.user;
621
965
  const twoFactor = await ctx.context.adapter.findOne({
622
966
  model: twoFactorTable,
623
967
  where: [
@@ -641,9 +985,14 @@ const totp2fa = (options) => {
641
985
  digits: opts.digits
642
986
  }).verify(ctx.body.code);
643
987
  if (!status) {
644
- return ctx.context.invalid();
988
+ return invalid("INVALID_CODE");
645
989
  }
646
990
  if (!user.twoFactorEnabled) {
991
+ if (!session.session) {
992
+ throw new APIError("BAD_REQUEST", {
993
+ message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION
994
+ });
995
+ }
647
996
  const updatedUser = await ctx.context.internalAdapter.updateUser(
648
997
  user.id,
649
998
  {
@@ -651,23 +1000,16 @@ const totp2fa = (options) => {
651
1000
  },
652
1001
  ctx
653
1002
  );
654
- const newSession = await ctx.context.internalAdapter.createSession(
655
- user.id,
656
- ctx.request,
657
- false,
658
- ctx.context.session.session
659
- ).catch((e) => {
1003
+ const newSession = await ctx.context.internalAdapter.createSession(user.id, ctx.headers, false, session.session).catch((e) => {
660
1004
  throw e;
661
1005
  });
662
- await ctx.context.internalAdapter.deleteSession(
663
- ctx.context.session.session.token
664
- );
1006
+ await ctx.context.internalAdapter.deleteSession(session.session.token);
665
1007
  await setSessionCookie(ctx, {
666
1008
  session: newSession,
667
1009
  user: updatedUser
668
1010
  });
669
1011
  }
670
- return ctx.context.valid(ctx);
1012
+ return valid(ctx);
671
1013
  }
672
1014
  );
673
1015
  return {
@@ -736,7 +1078,10 @@ const twoFactor = (options) => {
736
1078
  body: z.object({
737
1079
  password: z.string({
738
1080
  description: "User password"
739
- })
1081
+ }),
1082
+ issuer: z.string({
1083
+ description: "Custom issuer for the TOTP URI"
1084
+ }).optional()
740
1085
  }),
741
1086
  use: [sessionMiddleware],
742
1087
  metadata: {
@@ -773,7 +1118,7 @@ const twoFactor = (options) => {
773
1118
  },
774
1119
  async (ctx) => {
775
1120
  const user = ctx.context.session.user;
776
- const { password } = ctx.body;
1121
+ const { password, issuer } = ctx.body;
777
1122
  const isPasswordValid = await validatePassword(ctx, {
778
1123
  password,
779
1124
  userId: user.id
@@ -802,7 +1147,7 @@ const twoFactor = (options) => {
802
1147
  );
803
1148
  const newSession = await ctx.context.internalAdapter.createSession(
804
1149
  updatedUser.id,
805
- ctx.request,
1150
+ ctx.headers,
806
1151
  false,
807
1152
  ctx.context.session.session
808
1153
  );
@@ -834,7 +1179,7 @@ const twoFactor = (options) => {
834
1179
  const totpURI = createOTP(secret, {
835
1180
  digits: options?.totpOptions?.digits || 6,
836
1181
  period: options?.totpOptions?.period
837
- }).url(options?.issuer || ctx.context.appName, user.email);
1182
+ }).url(issuer || options?.issuer || ctx.context.appName, user.email);
838
1183
  return ctx.json({ totpURI, backupCodes: backupCodes.backupCodes });
839
1184
  }
840
1185
  ),
@@ -902,7 +1247,7 @@ const twoFactor = (options) => {
902
1247
  });
903
1248
  const newSession = await ctx.context.internalAdapter.createSession(
904
1249
  updatedUser.id,
905
- ctx.request,
1250
+ ctx.headers,
906
1251
  false,
907
1252
  ctx.context.session.session
908
1253
  );
@@ -961,16 +1306,22 @@ const twoFactor = (options) => {
961
1306
  }
962
1307
  deleteSessionCookie(ctx, true);
963
1308
  await ctx.context.internalAdapter.deleteSession(data.session.token);
1309
+ const maxAge = options?.otpOptions?.period || 60 * 5;
964
1310
  const twoFactorCookie = ctx.context.createAuthCookie(
965
1311
  TWO_FACTOR_COOKIE_NAME,
966
1312
  {
967
- maxAge: 60 * 10
968
- // 10 minutes
1313
+ maxAge
969
1314
  }
970
1315
  );
1316
+ const identifier = `2fa-${generateRandomString(20)}`;
1317
+ await ctx.context.internalAdapter.createVerificationValue({
1318
+ value: data.user.id,
1319
+ identifier,
1320
+ expiresAt: new Date(Date.now() + maxAge * 1e3)
1321
+ });
971
1322
  await ctx.setSignedCookie(
972
1323
  twoFactorCookie.name,
973
- data.user.id,
1324
+ identifier,
974
1325
  ctx.context.secret,
975
1326
  twoFactorCookie.attributes
976
1327
  );