better-auth 1.7.12 → 1.7.13

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 (270) hide show
  1. package/dist/adapters/index.d.mts +5 -10
  2. package/dist/api/dispatch.d.mts +3 -5
  3. package/dist/api/dispatch.mjs +6 -4
  4. package/dist/api/index.d.mts +506 -508
  5. package/dist/api/index.mjs +35 -34
  6. package/dist/api/middlewares/authorization.d.mts +15 -12
  7. package/dist/api/middlewares/authorization.mjs +2 -1
  8. package/dist/api/middlewares/index.d.mts +2 -1
  9. package/dist/api/middlewares/origin-check.d.mts +4 -7
  10. package/dist/api/routes/account.d.mts +11 -15
  11. package/dist/api/routes/account.mjs +7 -4
  12. package/dist/api/routes/callback.d.mts +2 -5
  13. package/dist/api/routes/callback.mjs +4 -2
  14. package/dist/api/routes/email-verification.d.mts +7 -12
  15. package/dist/api/routes/error.d.mts +2 -5
  16. package/dist/api/routes/index.d.mts +2 -1
  17. package/dist/api/routes/ok.d.mts +2 -5
  18. package/dist/api/routes/password.d.mts +8 -11
  19. package/dist/api/routes/password.mjs +3 -2
  20. package/dist/api/routes/session.d.mts +26 -29
  21. package/dist/api/routes/sign-in.d.mts +4 -6
  22. package/dist/api/routes/sign-out.d.mts +2 -5
  23. package/dist/api/routes/sign-up.d.mts +4 -6
  24. package/dist/api/routes/update-session.d.mts +4 -6
  25. package/dist/api/routes/update-user.d.mts +14 -16
  26. package/dist/api/routes/update-user.mjs +1 -1
  27. package/dist/api/state/oauth.d.mts +0 -3
  28. package/dist/api/state/oauth.mjs +2 -1
  29. package/dist/auth/full.d.mts +3 -4
  30. package/dist/auth/minimal.d.mts +3 -3
  31. package/dist/client/broadcast-channel.d.mts +6 -7
  32. package/dist/client/config.d.mts +15 -19
  33. package/dist/client/config.mjs +2 -2
  34. package/dist/client/equality.d.mts +3 -5
  35. package/dist/client/focus-manager.d.mts +4 -5
  36. package/dist/client/index.d.mts +8 -7
  37. package/dist/client/lynx/index.d.mts +6 -7
  38. package/dist/client/lynx/index.mjs +3 -2
  39. package/dist/client/lynx/lynx-store.d.mts +3 -4
  40. package/dist/client/online-manager.d.mts +4 -5
  41. package/dist/client/parser.d.mts +9 -5
  42. package/dist/client/path-to-object.d.mts +13 -14
  43. package/dist/client/plugins/index.d.mts +1 -1
  44. package/dist/client/plugins/infer-plugin.d.mts +2 -4
  45. package/dist/client/query.d.mts +4 -6
  46. package/dist/client/react/index.d.mts +6 -7
  47. package/dist/client/react/index.mjs +3 -2
  48. package/dist/client/react/react-store.d.mts +3 -4
  49. package/dist/client/session-atom.d.mts +4 -4
  50. package/dist/client/session-refresh.d.mts +3 -5
  51. package/dist/client/solid/index.d.mts +6 -7
  52. package/dist/client/solid/index.mjs +3 -2
  53. package/dist/client/svelte/index.d.mts +6 -7
  54. package/dist/client/svelte/index.mjs +3 -2
  55. package/dist/client/types.d.mts +11 -11
  56. package/dist/client/vanilla.d.mts +4 -5
  57. package/dist/client/vanilla.mjs +3 -2
  58. package/dist/client/vue/index.d.mts +6 -7
  59. package/dist/client/vue/index.mjs +3 -2
  60. package/dist/context/create-context.mjs +7 -7
  61. package/dist/context/helpers.mjs +9 -7
  62. package/dist/cookies/cookie-utils.d.mts +13 -13
  63. package/dist/cookies/cookie-utils.mjs +1 -3
  64. package/dist/cookies/index.d.mts +17 -18
  65. package/dist/cookies/index.mjs +11 -7
  66. package/dist/cookies/jwt.mjs +2 -1
  67. package/dist/cookies/session-store.d.mts +6 -5
  68. package/dist/cookies/session-store.mjs +3 -2
  69. package/dist/crypto/buffer.d.mts +2 -3
  70. package/dist/crypto/index.d.mts +9 -16
  71. package/dist/crypto/index.mjs +2 -1
  72. package/dist/crypto/jwt.d.mts +5 -7
  73. package/dist/crypto/jwt.mjs +2 -1
  74. package/dist/crypto/password.d.mts +1 -5
  75. package/dist/crypto/random.d.mts +2 -3
  76. package/dist/db/adapter-base.d.mts +2 -4
  77. package/dist/db/adapter-kysely.d.mts +2 -4
  78. package/dist/db/field-converter.d.mts +3 -5
  79. package/dist/db/field.d.mts +11 -12
  80. package/dist/db/get-migration.d.mts +4 -8
  81. package/dist/db/get-migration.mjs +22 -22
  82. package/dist/db/get-schema.d.mts +2 -4
  83. package/dist/db/internal-adapter.d.mts +2 -4
  84. package/dist/db/internal-adapter.mjs +6 -4
  85. package/dist/db/revoke-unproven-account-access.d.mts +3 -4
  86. package/dist/db/schema.d.mts +15 -16
  87. package/dist/db/schema.mjs +6 -3
  88. package/dist/db/to-zod.d.mts +5 -9
  89. package/dist/db/with-hooks.d.mts +3 -5
  90. package/dist/index.d.mts +4 -3
  91. package/dist/integrations/next-js.d.mts +7 -11
  92. package/dist/integrations/node.d.mts +5 -7
  93. package/dist/integrations/node.mjs +4 -2
  94. package/dist/integrations/solid-start.d.mts +2 -3
  95. package/dist/integrations/svelte-kit.d.mts +6 -14
  96. package/dist/integrations/tanstack-start-solid.d.mts +4 -8
  97. package/dist/integrations/tanstack-start.d.mts +4 -8
  98. package/dist/oauth2/link-account.d.mts +5 -11
  99. package/dist/oauth2/link-account.mjs +12 -6
  100. package/dist/oauth2/state.d.mts +5 -7
  101. package/dist/oauth2/state.mjs +1 -1
  102. package/dist/oauth2/utils.d.mts +4 -6
  103. package/dist/package.mjs +1 -1
  104. package/dist/plugins/access/access.d.mts +4 -6
  105. package/dist/plugins/access/index.mjs +1 -2
  106. package/dist/plugins/access/types.d.mts +12 -14
  107. package/dist/plugins/additional-fields/client.d.mts +2 -4
  108. package/dist/plugins/admin/access/index.mjs +1 -2
  109. package/dist/plugins/admin/access/statement.d.mts +7 -7
  110. package/dist/plugins/admin/admin.d.mts +122 -128
  111. package/dist/plugins/admin/client.d.mts +32 -32
  112. package/dist/plugins/admin/client.mjs +1 -1
  113. package/dist/plugins/admin/error-codes.d.mts +25 -28
  114. package/dist/plugins/admin/index.d.mts +1 -1
  115. package/dist/plugins/admin/index.mjs +1 -2
  116. package/dist/plugins/admin/schema.d.mts +3 -4
  117. package/dist/plugins/admin/types.d.mts +8 -8
  118. package/dist/plugins/anonymous/client.d.mts +10 -12
  119. package/dist/plugins/anonymous/client.mjs +1 -1
  120. package/dist/plugins/anonymous/error-codes.d.mts +10 -13
  121. package/dist/plugins/anonymous/index.d.mts +17 -21
  122. package/dist/plugins/anonymous/schema.d.mts +2 -3
  123. package/dist/plugins/anonymous/types.d.mts +5 -6
  124. package/dist/plugins/bearer/index.d.mts +7 -11
  125. package/dist/plugins/captcha/constants.d.mts +2 -3
  126. package/dist/plugins/captcha/index.d.mts +6 -9
  127. package/dist/plugins/captcha/types.d.mts +11 -13
  128. package/dist/plugins/custom-session/client.d.mts +2 -4
  129. package/dist/plugins/custom-session/index.d.mts +10 -16
  130. package/dist/plugins/device-authorization/client.d.mts +2 -4
  131. package/dist/plugins/device-authorization/index.d.mts +39 -44
  132. package/dist/plugins/device-authorization/index.mjs +10 -9
  133. package/dist/plugins/device-authorization/routes.d.mts +7 -5
  134. package/dist/plugins/device-authorization/routes.mjs +6 -5
  135. package/dist/plugins/device-authorization/schema.d.mts +2 -3
  136. package/dist/plugins/email-otp/client.d.mts +5 -7
  137. package/dist/plugins/email-otp/client.mjs +1 -1
  138. package/dist/plugins/email-otp/error-codes.d.mts +5 -8
  139. package/dist/plugins/email-otp/index.d.mts +69 -76
  140. package/dist/plugins/email-otp/otp-token.mjs +19 -7
  141. package/dist/plugins/email-otp/types.d.mts +2 -4
  142. package/dist/plugins/generic-oauth/index.d.mts +9 -13
  143. package/dist/plugins/generic-oauth/index.mjs +6 -4
  144. package/dist/plugins/generic-oauth/providers/auth0.d.mts +3 -5
  145. package/dist/plugins/generic-oauth/providers/gumroad.d.mts +3 -5
  146. package/dist/plugins/generic-oauth/providers/hubspot.d.mts +3 -5
  147. package/dist/plugins/generic-oauth/providers/hubspot.mjs +2 -1
  148. package/dist/plugins/generic-oauth/providers/index.d.mts +2 -1
  149. package/dist/plugins/generic-oauth/providers/keycloak.d.mts +3 -5
  150. package/dist/plugins/generic-oauth/providers/line.d.mts +3 -5
  151. package/dist/plugins/generic-oauth/providers/microsoft-entra-id.d.mts +3 -5
  152. package/dist/plugins/generic-oauth/providers/okta.d.mts +3 -5
  153. package/dist/plugins/generic-oauth/providers/patreon.d.mts +3 -5
  154. package/dist/plugins/generic-oauth/providers/slack.d.mts +3 -5
  155. package/dist/plugins/generic-oauth/providers/yandex.d.mts +3 -5
  156. package/dist/plugins/generic-oauth/types.d.mts +6 -7
  157. package/dist/plugins/haveibeenpwned/index.d.mts +7 -11
  158. package/dist/plugins/index.d.mts +4 -1
  159. package/dist/plugins/jwt/client.d.mts +2 -3
  160. package/dist/plugins/jwt/index.d.mts +11 -14
  161. package/dist/plugins/jwt/index.mjs +1 -1
  162. package/dist/plugins/jwt/schema.d.mts +2 -3
  163. package/dist/plugins/jwt/sign.d.mts +9 -8
  164. package/dist/plugins/jwt/types.d.mts +7 -8
  165. package/dist/plugins/jwt/utils.d.mts +6 -9
  166. package/dist/plugins/jwt/verify.d.mts +2 -4
  167. package/dist/plugins/last-login-method/client.d.mts +3 -4
  168. package/dist/plugins/last-login-method/index.d.mts +5 -9
  169. package/dist/plugins/last-login-method/index.mjs +1 -1
  170. package/dist/plugins/magic-link/client.d.mts +2 -4
  171. package/dist/plugins/magic-link/index.d.mts +7 -10
  172. package/dist/plugins/magic-link/index.mjs +20 -17
  173. package/dist/plugins/multi-session/client.d.mts +3 -5
  174. package/dist/plugins/multi-session/client.mjs +1 -1
  175. package/dist/plugins/multi-session/error-codes.d.mts +3 -6
  176. package/dist/plugins/multi-session/index.d.mts +10 -14
  177. package/dist/plugins/oauth-popup/client.d.mts +11 -17
  178. package/dist/plugins/oauth-popup/client.mjs +6 -4
  179. package/dist/plugins/oauth-popup/constants.d.mts +5 -6
  180. package/dist/plugins/oauth-popup/error-codes.d.mts +6 -9
  181. package/dist/plugins/oauth-popup/index.d.mts +11 -15
  182. package/dist/plugins/oauth-popup/index.mjs +8 -7
  183. package/dist/plugins/oauth-popup/types.d.mts +4 -6
  184. package/dist/plugins/oauth-proxy/index.d.mts +11 -15
  185. package/dist/plugins/oauth-proxy/index.mjs +10 -7
  186. package/dist/plugins/one-tap/client.d.mts +6 -9
  187. package/dist/plugins/one-tap/index.d.mts +4 -7
  188. package/dist/plugins/one-time-token/client.d.mts +2 -3
  189. package/dist/plugins/one-time-token/index.d.mts +8 -10
  190. package/dist/plugins/open-api/generator.d.mts +8 -8
  191. package/dist/plugins/open-api/generator.mjs +5 -5
  192. package/dist/plugins/open-api/index.d.mts +5 -7
  193. package/dist/plugins/organization/access/index.mjs +1 -2
  194. package/dist/plugins/organization/access/statement.d.mts +8 -8
  195. package/dist/plugins/organization/adapter.d.mts +60 -87
  196. package/dist/plugins/organization/adapter.mjs +14 -10
  197. package/dist/plugins/organization/client.d.mts +108 -107
  198. package/dist/plugins/organization/client.mjs +9 -5
  199. package/dist/plugins/organization/error-codes.d.mts +61 -64
  200. package/dist/plugins/organization/has-permission.d.mts +2 -4
  201. package/dist/plugins/organization/has-permission.mjs +1 -1
  202. package/dist/plugins/organization/index.d.mts +1 -1
  203. package/dist/plugins/organization/organization.d.mts +20 -20
  204. package/dist/plugins/organization/organization.mjs +13 -8
  205. package/dist/plugins/organization/permission.d.mts +4 -5
  206. package/dist/plugins/organization/routes/crud-access-control.d.mts +28 -28
  207. package/dist/plugins/organization/routes/crud-invites.d.mts +64 -65
  208. package/dist/plugins/organization/routes/crud-invites.mjs +21 -18
  209. package/dist/plugins/organization/routes/crud-members.d.mts +53 -56
  210. package/dist/plugins/organization/routes/crud-members.mjs +23 -21
  211. package/dist/plugins/organization/routes/crud-org.d.mts +63 -65
  212. package/dist/plugins/organization/routes/crud-org.mjs +4 -2
  213. package/dist/plugins/organization/routes/crud-team.d.mts +65 -66
  214. package/dist/plugins/organization/routes/crud-team.mjs +4 -2
  215. package/dist/plugins/organization/schema.d.mts +33 -33
  216. package/dist/plugins/organization/schema.mjs +1 -1
  217. package/dist/plugins/organization/types.d.mts +16 -17
  218. package/dist/plugins/phone-number/client.d.mts +14 -16
  219. package/dist/plugins/phone-number/client.mjs +1 -1
  220. package/dist/plugins/phone-number/error-codes.d.mts +14 -17
  221. package/dist/plugins/phone-number/index.d.mts +48 -54
  222. package/dist/plugins/phone-number/schema.d.mts +2 -3
  223. package/dist/plugins/phone-number/types.d.mts +4 -5
  224. package/dist/plugins/siwe/client.d.mts +2 -4
  225. package/dist/plugins/siwe/index.d.mts +7 -9
  226. package/dist/plugins/siwe/index.mjs +1 -1
  227. package/dist/plugins/siwe/parse-message.mjs +1 -3
  228. package/dist/plugins/siwe/schema.d.mts +3 -4
  229. package/dist/plugins/siwe/types.d.mts +4 -4
  230. package/dist/plugins/test-utils/auth-helpers.mjs +4 -2
  231. package/dist/plugins/test-utils/index.d.mts +3 -5
  232. package/dist/plugins/test-utils/types.d.mts +7 -7
  233. package/dist/plugins/two-factor/backup-codes/index.d.mts +11 -14
  234. package/dist/plugins/two-factor/backup-codes/index.mjs +12 -6
  235. package/dist/plugins/two-factor/client.d.mts +16 -19
  236. package/dist/plugins/two-factor/client.mjs +1 -1
  237. package/dist/plugins/two-factor/constant.mjs +1 -1
  238. package/dist/plugins/two-factor/error-code.d.mts +15 -18
  239. package/dist/plugins/two-factor/index.d.mts +31 -35
  240. package/dist/plugins/two-factor/index.mjs +6 -3
  241. package/dist/plugins/two-factor/otp/index.d.mts +5 -8
  242. package/dist/plugins/two-factor/otp/index.mjs +159 -154
  243. package/dist/plugins/two-factor/schema.d.mts +2 -3
  244. package/dist/plugins/two-factor/totp/index.d.mts +7 -10
  245. package/dist/plugins/two-factor/totp/index.mjs +153 -148
  246. package/dist/plugins/two-factor/types.d.mts +6 -7
  247. package/dist/plugins/username/client.d.mts +12 -14
  248. package/dist/plugins/username/client.mjs +1 -1
  249. package/dist/plugins/username/error-codes.d.mts +11 -14
  250. package/dist/plugins/username/index.d.mts +26 -31
  251. package/dist/plugins/username/schema.d.mts +7 -10
  252. package/dist/state.d.mts +4 -5
  253. package/dist/test-utils/headers.d.mts +2 -3
  254. package/dist/test-utils/http-test-instance.d.mts +26 -29
  255. package/dist/test-utils/test-instance.d.mts +7 -6
  256. package/dist/test-utils/test-instance.mjs +4 -2
  257. package/dist/types/adapter.d.mts +1 -1
  258. package/dist/types/api.d.mts +4 -6
  259. package/dist/types/auth.d.mts +2 -4
  260. package/dist/types/helper.d.mts +11 -12
  261. package/dist/types/index.d.mts +2 -2
  262. package/dist/types/models.d.mts +4 -5
  263. package/dist/types/plugins.d.mts +7 -8
  264. package/dist/utils/hide-metadata.d.mts +2 -3
  265. package/dist/utils/index.d.mts +2 -1
  266. package/dist/utils/is-api-error.mjs +1 -2
  267. package/dist/utils/time.d.mts +4 -4
  268. package/dist/utils/url.d.mts +13 -15
  269. package/dist/utils/wildcard.mjs +5 -3
  270. package/package.json +12 -12
@@ -57,6 +57,163 @@ const otp2fa = (options) => {
57
57
  if (typeof opts.storeOTP === "object" && "hash" in opts.storeOTP) return [storedOtp, await opts.storeOTP.hash(userInput)];
58
58
  return [storedOtp, userInput];
59
59
  }
60
+ /**
61
+ * Generate OTP and send it to the user.
62
+ */
63
+ const send2FaOTP = createAuthEndpoint("/two-factor/send-otp", {
64
+ method: "POST",
65
+ body: send2FaOTPBodySchema,
66
+ metadata: { openapi: {
67
+ summary: "Send two factor OTP",
68
+ description: "Send two factor OTP to the user",
69
+ responses: { 200: {
70
+ description: "Successful response",
71
+ content: { "application/json": { schema: {
72
+ type: "object",
73
+ properties: { status: { type: "boolean" } }
74
+ } } }
75
+ } }
76
+ } }
77
+ }, async (ctx) => {
78
+ if (!options || !options.sendOTP) {
79
+ ctx.context.logger.error("send otp isn't configured. Please configure the send otp function on otp options.");
80
+ throw APIError.from("BAD_REQUEST", {
81
+ message: "otp isn't configured",
82
+ code: "OTP_NOT_CONFIGURED"
83
+ });
84
+ }
85
+ const { session, key } = await verifyTwoFactor(ctx);
86
+ const code = generateRandomString(opts.digits, "0-9");
87
+ const hashedCode = await storeOTP(ctx, code);
88
+ await ctx.context.internalAdapter.createVerificationValue({
89
+ value: `${hashedCode}:0`,
90
+ identifier: `2fa-otp-${key}`,
91
+ expiresAt: new Date(Date.now() + opts.period)
92
+ });
93
+ const sendOTPResult = options.sendOTP({
94
+ user: session.user,
95
+ otp: code
96
+ }, ctx);
97
+ if (sendOTPResult instanceof Promise) await ctx.context.runInBackgroundOrAwait(sendOTPResult.catch((e) => {
98
+ ctx.context.logger.error("Failed to send two-factor OTP", e);
99
+ }));
100
+ return ctx.json({ status: true });
101
+ });
102
+ const verifyOTP = createAuthEndpoint("/two-factor/verify-otp", {
103
+ method: "POST",
104
+ body: verifyOTPBodySchema,
105
+ metadata: { openapi: {
106
+ summary: "Verify two factor OTP",
107
+ description: "Verify two factor OTP",
108
+ responses: { "200": {
109
+ description: "Two-factor OTP verified successfully",
110
+ content: { "application/json": { schema: {
111
+ type: "object",
112
+ properties: {
113
+ token: {
114
+ type: "string",
115
+ description: "Session token for the authenticated session"
116
+ },
117
+ user: {
118
+ type: "object",
119
+ properties: {
120
+ id: {
121
+ type: "string",
122
+ description: "Unique identifier of the user"
123
+ },
124
+ email: {
125
+ type: "string",
126
+ format: "email",
127
+ nullable: true,
128
+ description: "User's email address"
129
+ },
130
+ emailVerified: {
131
+ type: "boolean",
132
+ nullable: true,
133
+ description: "Whether the email is verified"
134
+ },
135
+ name: {
136
+ type: "string",
137
+ nullable: true,
138
+ description: "User's name"
139
+ },
140
+ image: {
141
+ type: "string",
142
+ format: "uri",
143
+ nullable: true,
144
+ description: "User's profile image URL"
145
+ },
146
+ createdAt: {
147
+ type: "string",
148
+ format: "date-time",
149
+ description: "Timestamp when the user was created"
150
+ },
151
+ updatedAt: {
152
+ type: "string",
153
+ format: "date-time",
154
+ description: "Timestamp when the user was last updated"
155
+ }
156
+ },
157
+ required: [
158
+ "id",
159
+ "createdAt",
160
+ "updatedAt"
161
+ ],
162
+ description: "The authenticated user object"
163
+ }
164
+ },
165
+ required: ["token", "user"]
166
+ } } }
167
+ } }
168
+ } }
169
+ }, async (ctx) => {
170
+ const { session, key, valid, invalid } = await verifyTwoFactor(ctx);
171
+ const isSignIn = !session.session;
172
+ const twoFactorTable = "twoFactor";
173
+ let twoFactor = null;
174
+ if (isSignIn) {
175
+ twoFactor = await ctx.context.adapter.findOne({
176
+ model: twoFactorTable,
177
+ where: [{
178
+ field: "userId",
179
+ value: session.user.id
180
+ }]
181
+ });
182
+ if (twoFactor) await assertTwoFactorNotLocked(ctx, twoFactorTable, twoFactor);
183
+ }
184
+ const consumed = await ctx.context.internalAdapter.consumeVerificationValue(`2fa-otp-${key}`);
185
+ if (!consumed) throw APIError.from("BAD_REQUEST", TWO_FACTOR_ERROR_CODES.OTP_HAS_EXPIRED);
186
+ const [otp, counter] = consumed.value?.split(":") ?? [];
187
+ const allowedAttempts = options?.allowedAttempts || 5;
188
+ const attempts = parseInt(counter, 10) || 0;
189
+ if (attempts >= allowedAttempts) throw APIError.from("BAD_REQUEST", TWO_FACTOR_ERROR_CODES.TOO_MANY_ATTEMPTS_REQUEST_NEW_CODE);
190
+ const [storedValue, inputValue] = await decryptOrHashForComparison(ctx, otp, ctx.body.code);
191
+ if (constantTimeEqual(new TextEncoder().encode(storedValue), new TextEncoder().encode(inputValue))) {
192
+ if (twoFactor) await resetTwoFactorFailures(ctx, twoFactorTable, twoFactor);
193
+ if (!session.user.twoFactorEnabled) {
194
+ if (!session.session) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION);
195
+ const updatedUser = await ctx.context.internalAdapter.updateUser(session.user.id, { twoFactorEnabled: true });
196
+ const newSession = await ctx.context.internalAdapter.createSession(session.user.id, false, session.session);
197
+ await setSessionCookie(ctx, {
198
+ session: newSession,
199
+ user: updatedUser
200
+ });
201
+ await ctx.context.internalAdapter.deleteSession(session.session.token);
202
+ return ctx.json({
203
+ token: newSession.token,
204
+ user: parseUserOutput(ctx.context.options, updatedUser)
205
+ });
206
+ }
207
+ return valid(ctx);
208
+ }
209
+ await ctx.context.internalAdapter.createVerificationValue({
210
+ value: `${otp}:${attempts + 1}`,
211
+ identifier: `2fa-otp-${key}`,
212
+ expiresAt: consumed.expiresAt
213
+ });
214
+ if (twoFactor) await recordTwoFactorFailure(ctx, twoFactorTable, twoFactor);
215
+ return invalid("INVALID_CODE");
216
+ });
60
217
  return {
61
218
  id: "otp",
62
219
  version: PACKAGE_VERSION,
@@ -76,45 +233,7 @@ const otp2fa = (options) => {
76
233
  *
77
234
  * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/2fa#api-method-two-factor-send-otp)
78
235
  */
79
- sendTwoFactorOTP: createAuthEndpoint("/two-factor/send-otp", {
80
- method: "POST",
81
- body: send2FaOTPBodySchema,
82
- metadata: { openapi: {
83
- summary: "Send two factor OTP",
84
- description: "Send two factor OTP to the user",
85
- responses: { 200: {
86
- description: "Successful response",
87
- content: { "application/json": { schema: {
88
- type: "object",
89
- properties: { status: { type: "boolean" } }
90
- } } }
91
- } }
92
- } }
93
- }, async (ctx) => {
94
- if (!options || !options.sendOTP) {
95
- ctx.context.logger.error("send otp isn't configured. Please configure the send otp function on otp options.");
96
- throw APIError.from("BAD_REQUEST", {
97
- message: "otp isn't configured",
98
- code: "OTP_NOT_CONFIGURED"
99
- });
100
- }
101
- const { session, key } = await verifyTwoFactor(ctx);
102
- const code = generateRandomString(opts.digits, "0-9");
103
- const hashedCode = await storeOTP(ctx, code);
104
- await ctx.context.internalAdapter.createVerificationValue({
105
- value: `${hashedCode}:0`,
106
- identifier: `2fa-otp-${key}`,
107
- expiresAt: new Date(Date.now() + opts.period)
108
- });
109
- const sendOTPResult = options.sendOTP({
110
- user: session.user,
111
- otp: code
112
- }, ctx);
113
- if (sendOTPResult instanceof Promise) await ctx.context.runInBackgroundOrAwait(sendOTPResult.catch((e) => {
114
- ctx.context.logger.error("Failed to send two-factor OTP", e);
115
- }));
116
- return ctx.json({ status: true });
117
- }),
236
+ sendTwoFactorOTP: send2FaOTP,
118
237
  /**
119
238
  * ### Endpoint
120
239
  *
@@ -130,121 +249,7 @@ const otp2fa = (options) => {
130
249
  *
131
250
  * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/2fa#api-method-two-factor-verify-otp)
132
251
  */
133
- verifyTwoFactorOTP: createAuthEndpoint("/two-factor/verify-otp", {
134
- method: "POST",
135
- body: verifyOTPBodySchema,
136
- metadata: { openapi: {
137
- summary: "Verify two factor OTP",
138
- description: "Verify two factor OTP",
139
- responses: { "200": {
140
- description: "Two-factor OTP verified successfully",
141
- content: { "application/json": { schema: {
142
- type: "object",
143
- properties: {
144
- token: {
145
- type: "string",
146
- description: "Session token for the authenticated session"
147
- },
148
- user: {
149
- type: "object",
150
- properties: {
151
- id: {
152
- type: "string",
153
- description: "Unique identifier of the user"
154
- },
155
- email: {
156
- type: "string",
157
- format: "email",
158
- nullable: true,
159
- description: "User's email address"
160
- },
161
- emailVerified: {
162
- type: "boolean",
163
- nullable: true,
164
- description: "Whether the email is verified"
165
- },
166
- name: {
167
- type: "string",
168
- nullable: true,
169
- description: "User's name"
170
- },
171
- image: {
172
- type: "string",
173
- format: "uri",
174
- nullable: true,
175
- description: "User's profile image URL"
176
- },
177
- createdAt: {
178
- type: "string",
179
- format: "date-time",
180
- description: "Timestamp when the user was created"
181
- },
182
- updatedAt: {
183
- type: "string",
184
- format: "date-time",
185
- description: "Timestamp when the user was last updated"
186
- }
187
- },
188
- required: [
189
- "id",
190
- "createdAt",
191
- "updatedAt"
192
- ],
193
- description: "The authenticated user object"
194
- }
195
- },
196
- required: ["token", "user"]
197
- } } }
198
- } }
199
- } }
200
- }, async (ctx) => {
201
- const { session, key, valid, invalid } = await verifyTwoFactor(ctx);
202
- const isSignIn = !session.session;
203
- const twoFactorTable = "twoFactor";
204
- let twoFactor = null;
205
- if (isSignIn) {
206
- twoFactor = await ctx.context.adapter.findOne({
207
- model: twoFactorTable,
208
- where: [{
209
- field: "userId",
210
- value: session.user.id
211
- }]
212
- });
213
- if (twoFactor) await assertTwoFactorNotLocked(ctx, twoFactorTable, twoFactor);
214
- }
215
- const consumed = await ctx.context.internalAdapter.consumeVerificationValue(`2fa-otp-${key}`);
216
- if (!consumed) throw APIError.from("BAD_REQUEST", TWO_FACTOR_ERROR_CODES.OTP_HAS_EXPIRED);
217
- const [otp, counter] = consumed.value?.split(":") ?? [];
218
- const allowedAttempts = options?.allowedAttempts || 5;
219
- const attempts = parseInt(counter, 10) || 0;
220
- if (attempts >= allowedAttempts) throw APIError.from("BAD_REQUEST", TWO_FACTOR_ERROR_CODES.TOO_MANY_ATTEMPTS_REQUEST_NEW_CODE);
221
- const [storedValue, inputValue] = await decryptOrHashForComparison(ctx, otp, ctx.body.code);
222
- if (constantTimeEqual(new TextEncoder().encode(storedValue), new TextEncoder().encode(inputValue))) {
223
- if (twoFactor) await resetTwoFactorFailures(ctx, twoFactorTable, twoFactor);
224
- if (!session.user.twoFactorEnabled) {
225
- if (!session.session) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION);
226
- const updatedUser = await ctx.context.internalAdapter.updateUser(session.user.id, { twoFactorEnabled: true });
227
- const newSession = await ctx.context.internalAdapter.createSession(session.user.id, false, session.session);
228
- await setSessionCookie(ctx, {
229
- session: newSession,
230
- user: updatedUser
231
- });
232
- await ctx.context.internalAdapter.deleteSession(session.session.token);
233
- return ctx.json({
234
- token: newSession.token,
235
- user: parseUserOutput(ctx.context.options, updatedUser)
236
- });
237
- }
238
- return valid(ctx);
239
- }
240
- await ctx.context.internalAdapter.createVerificationValue({
241
- value: `${otp}:${attempts + 1}`,
242
- identifier: `2fa-otp-${key}`,
243
- expiresAt: consumed.expiresAt
244
- });
245
- if (twoFactor) await recordTwoFactorFailure(ctx, twoFactorTable, twoFactor);
246
- return invalid("INVALID_CODE");
247
- })
252
+ verifyTwoFactorOTP: verifyOTP
248
253
  }
249
254
  };
250
255
  };
@@ -1,5 +1,5 @@
1
1
  //#region src/plugins/two-factor/schema.d.ts
2
- declare const schema: {
2
+ export declare const schema: {
3
3
  user: {
4
4
  fields: {
5
5
  twoFactorEnabled: {
@@ -55,5 +55,4 @@ declare const schema: {
55
55
  };
56
56
  };
57
57
  };
58
- //#endregion
59
- export { schema };
58
+ //#endregion
@@ -1,10 +1,8 @@
1
1
  import { BackupCodeOptions } from "../backup-codes/index.mjs";
2
2
  import { UserWithTwoFactor } from "../types.mjs";
3
- import * as _$better_call0 from "better-call";
4
3
  import * as z from "zod";
5
-
6
4
  //#region src/plugins/two-factor/totp/index.d.ts
7
- type TOTPOptions = {
5
+ export type TOTPOptions = {
8
6
  /**
9
7
  * Issuer
10
8
  */
@@ -36,7 +34,7 @@ type TOTPOptions = {
36
34
  */
37
35
  disable?: boolean | undefined;
38
36
  };
39
- declare const totp2fa: (options?: TOTPOptions | undefined) => {
37
+ export declare const totp2fa: (options?: TOTPOptions | undefined) => {
40
38
  id: "totp";
41
39
  version: string;
42
40
  endpoints: {
@@ -52,7 +50,7 @@ declare const totp2fa: (options?: TOTPOptions | undefined) => {
52
50
  *
53
51
  * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/2fa#totp)
54
52
  */
55
- generateTOTP: _$better_call0.StrictEndpoint<string, {
53
+ generateTOTP: import("better-call").StrictEndpoint<string, {
56
54
  method: "POST";
57
55
  body: z.ZodObject<{
58
56
  secret: z.ZodString;
@@ -98,9 +96,9 @@ declare const totp2fa: (options?: TOTPOptions | undefined) => {
98
96
  *
99
97
  * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/2fa#getting-totp-uri)
100
98
  */
101
- getTOTPURI: _$better_call0.StrictEndpoint<"/two-factor/get-totp-uri", {
99
+ getTOTPURI: import("better-call").StrictEndpoint<"/two-factor/get-totp-uri", {
102
100
  method: "POST";
103
- use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
101
+ use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
104
102
  session: {
105
103
  session: Record<string, any> & {
106
104
  id: string;
@@ -169,7 +167,7 @@ declare const totp2fa: (options?: TOTPOptions | undefined) => {
169
167
  *
170
168
  * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/2fa#verifying-totp)
171
169
  */
172
- verifyTOTP: _$better_call0.StrictEndpoint<"/two-factor/verify-totp", {
170
+ verifyTOTP: import("better-call").StrictEndpoint<"/two-factor/verify-totp", {
173
171
  method: "POST";
174
172
  body: z.ZodObject<{
175
173
  code: z.ZodString;
@@ -215,5 +213,4 @@ declare const totp2fa: (options?: TOTPOptions | undefined) => {
215
213
  }>;
216
214
  };
217
215
  };
218
- //#endregion
219
- export { TOTPOptions, totp2fa };
216
+ //#endregion