@hammadj/better-auth 1.5.0-beta.10

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 (687) hide show
  1. package/README.md +33 -0
  2. package/dist/_virtual/rolldown_runtime.mjs +36 -0
  3. package/dist/adapters/drizzle-adapter/index.d.mts +1 -0
  4. package/dist/adapters/drizzle-adapter/index.mjs +3 -0
  5. package/dist/adapters/index.d.mts +23 -0
  6. package/dist/adapters/index.mjs +13 -0
  7. package/dist/adapters/index.mjs.map +1 -0
  8. package/dist/adapters/kysely-adapter/index.d.mts +1 -0
  9. package/dist/adapters/kysely-adapter/index.mjs +3 -0
  10. package/dist/adapters/memory-adapter/index.d.mts +1 -0
  11. package/dist/adapters/memory-adapter/index.mjs +3 -0
  12. package/dist/adapters/mongodb-adapter/index.d.mts +1 -0
  13. package/dist/adapters/mongodb-adapter/index.mjs +3 -0
  14. package/dist/adapters/prisma-adapter/index.d.mts +1 -0
  15. package/dist/adapters/prisma-adapter/index.mjs +3 -0
  16. package/dist/api/index.d.mts +40 -0
  17. package/dist/api/index.mjs +205 -0
  18. package/dist/api/index.mjs.map +1 -0
  19. package/dist/api/middlewares/index.d.mts +1 -0
  20. package/dist/api/middlewares/index.mjs +3 -0
  21. package/dist/api/middlewares/origin-check.d.mts +17 -0
  22. package/dist/api/middlewares/origin-check.mjs +140 -0
  23. package/dist/api/middlewares/origin-check.mjs.map +1 -0
  24. package/dist/api/rate-limiter/index.mjs +177 -0
  25. package/dist/api/rate-limiter/index.mjs.map +1 -0
  26. package/dist/api/routes/account.d.mts +10 -0
  27. package/dist/api/routes/account.mjs +493 -0
  28. package/dist/api/routes/account.mjs.map +1 -0
  29. package/dist/api/routes/callback.d.mts +5 -0
  30. package/dist/api/routes/callback.mjs +178 -0
  31. package/dist/api/routes/callback.mjs.map +1 -0
  32. package/dist/api/routes/email-verification.d.mts +29 -0
  33. package/dist/api/routes/email-verification.mjs +301 -0
  34. package/dist/api/routes/email-verification.mjs.map +1 -0
  35. package/dist/api/routes/error.d.mts +5 -0
  36. package/dist/api/routes/error.mjs +386 -0
  37. package/dist/api/routes/error.mjs.map +1 -0
  38. package/dist/api/routes/index.d.mts +11 -0
  39. package/dist/api/routes/index.mjs +13 -0
  40. package/dist/api/routes/ok.d.mts +5 -0
  41. package/dist/api/routes/ok.mjs +30 -0
  42. package/dist/api/routes/ok.mjs.map +1 -0
  43. package/dist/api/routes/password.d.mts +8 -0
  44. package/dist/api/routes/password.mjs +198 -0
  45. package/dist/api/routes/password.mjs.map +1 -0
  46. package/dist/api/routes/session.d.mts +52 -0
  47. package/dist/api/routes/session.mjs +478 -0
  48. package/dist/api/routes/session.mjs.map +1 -0
  49. package/dist/api/routes/sign-in.d.mts +8 -0
  50. package/dist/api/routes/sign-in.mjs +262 -0
  51. package/dist/api/routes/sign-in.mjs.map +1 -0
  52. package/dist/api/routes/sign-out.d.mts +5 -0
  53. package/dist/api/routes/sign-out.mjs +33 -0
  54. package/dist/api/routes/sign-out.mjs.map +1 -0
  55. package/dist/api/routes/sign-up.d.mts +7 -0
  56. package/dist/api/routes/sign-up.mjs +227 -0
  57. package/dist/api/routes/sign-up.mjs.map +1 -0
  58. package/dist/api/routes/update-user.d.mts +12 -0
  59. package/dist/api/routes/update-user.mjs +493 -0
  60. package/dist/api/routes/update-user.mjs.map +1 -0
  61. package/dist/api/state/oauth.d.mts +5 -0
  62. package/dist/api/state/oauth.mjs +8 -0
  63. package/dist/api/state/oauth.mjs.map +1 -0
  64. package/dist/api/state/should-session-refresh.d.mts +13 -0
  65. package/dist/api/state/should-session-refresh.mjs +16 -0
  66. package/dist/api/state/should-session-refresh.mjs.map +1 -0
  67. package/dist/api/to-auth-endpoints.mjs +197 -0
  68. package/dist/api/to-auth-endpoints.mjs.map +1 -0
  69. package/dist/auth/base.mjs +44 -0
  70. package/dist/auth/base.mjs.map +1 -0
  71. package/dist/auth/full.d.mts +30 -0
  72. package/dist/auth/full.mjs +32 -0
  73. package/dist/auth/full.mjs.map +1 -0
  74. package/dist/auth/minimal.d.mts +12 -0
  75. package/dist/auth/minimal.mjs +14 -0
  76. package/dist/auth/minimal.mjs.map +1 -0
  77. package/dist/auth/trusted-origins.mjs +31 -0
  78. package/dist/auth/trusted-origins.mjs.map +1 -0
  79. package/dist/client/broadcast-channel.d.mts +20 -0
  80. package/dist/client/broadcast-channel.mjs +46 -0
  81. package/dist/client/broadcast-channel.mjs.map +1 -0
  82. package/dist/client/config.mjs +90 -0
  83. package/dist/client/config.mjs.map +1 -0
  84. package/dist/client/fetch-plugins.mjs +18 -0
  85. package/dist/client/fetch-plugins.mjs.map +1 -0
  86. package/dist/client/focus-manager.d.mts +11 -0
  87. package/dist/client/focus-manager.mjs +32 -0
  88. package/dist/client/focus-manager.mjs.map +1 -0
  89. package/dist/client/index.d.mts +30 -0
  90. package/dist/client/index.mjs +21 -0
  91. package/dist/client/index.mjs.map +1 -0
  92. package/dist/client/lynx/index.d.mts +62 -0
  93. package/dist/client/lynx/index.mjs +24 -0
  94. package/dist/client/lynx/index.mjs.map +1 -0
  95. package/dist/client/lynx/lynx-store.d.mts +47 -0
  96. package/dist/client/lynx/lynx-store.mjs +47 -0
  97. package/dist/client/lynx/lynx-store.mjs.map +1 -0
  98. package/dist/client/online-manager.d.mts +12 -0
  99. package/dist/client/online-manager.mjs +35 -0
  100. package/dist/client/online-manager.mjs.map +1 -0
  101. package/dist/client/parser.mjs +73 -0
  102. package/dist/client/parser.mjs.map +1 -0
  103. package/dist/client/path-to-object.d.mts +57 -0
  104. package/dist/client/plugins/index.d.mts +58 -0
  105. package/dist/client/plugins/index.mjs +33 -0
  106. package/dist/client/plugins/infer-plugin.d.mts +9 -0
  107. package/dist/client/plugins/infer-plugin.mjs +11 -0
  108. package/dist/client/plugins/infer-plugin.mjs.map +1 -0
  109. package/dist/client/proxy.mjs +79 -0
  110. package/dist/client/proxy.mjs.map +1 -0
  111. package/dist/client/query.d.mts +23 -0
  112. package/dist/client/query.mjs +98 -0
  113. package/dist/client/query.mjs.map +1 -0
  114. package/dist/client/react/index.d.mts +63 -0
  115. package/dist/client/react/index.mjs +24 -0
  116. package/dist/client/react/index.mjs.map +1 -0
  117. package/dist/client/react/react-store.d.mts +47 -0
  118. package/dist/client/react/react-store.mjs +47 -0
  119. package/dist/client/react/react-store.mjs.map +1 -0
  120. package/dist/client/session-atom.mjs +29 -0
  121. package/dist/client/session-atom.mjs.map +1 -0
  122. package/dist/client/session-refresh.d.mts +28 -0
  123. package/dist/client/session-refresh.mjs +140 -0
  124. package/dist/client/session-refresh.mjs.map +1 -0
  125. package/dist/client/solid/index.d.mts +57 -0
  126. package/dist/client/solid/index.mjs +22 -0
  127. package/dist/client/solid/index.mjs.map +1 -0
  128. package/dist/client/solid/solid-store.mjs +24 -0
  129. package/dist/client/solid/solid-store.mjs.map +1 -0
  130. package/dist/client/svelte/index.d.mts +63 -0
  131. package/dist/client/svelte/index.mjs +20 -0
  132. package/dist/client/svelte/index.mjs.map +1 -0
  133. package/dist/client/types.d.mts +58 -0
  134. package/dist/client/vanilla.d.mts +62 -0
  135. package/dist/client/vanilla.mjs +20 -0
  136. package/dist/client/vanilla.mjs.map +1 -0
  137. package/dist/client/vue/index.d.mts +86 -0
  138. package/dist/client/vue/index.mjs +38 -0
  139. package/dist/client/vue/index.mjs.map +1 -0
  140. package/dist/client/vue/vue-store.mjs +26 -0
  141. package/dist/client/vue/vue-store.mjs.map +1 -0
  142. package/dist/context/create-context.mjs +211 -0
  143. package/dist/context/create-context.mjs.map +1 -0
  144. package/dist/context/helpers.mjs +62 -0
  145. package/dist/context/helpers.mjs.map +1 -0
  146. package/dist/context/init-minimal.mjs +20 -0
  147. package/dist/context/init-minimal.mjs.map +1 -0
  148. package/dist/context/init.mjs +22 -0
  149. package/dist/context/init.mjs.map +1 -0
  150. package/dist/cookies/cookie-utils.d.mts +29 -0
  151. package/dist/cookies/cookie-utils.mjs +105 -0
  152. package/dist/cookies/cookie-utils.mjs.map +1 -0
  153. package/dist/cookies/index.d.mts +67 -0
  154. package/dist/cookies/index.mjs +264 -0
  155. package/dist/cookies/index.mjs.map +1 -0
  156. package/dist/cookies/session-store.d.mts +36 -0
  157. package/dist/cookies/session-store.mjs +200 -0
  158. package/dist/cookies/session-store.mjs.map +1 -0
  159. package/dist/crypto/buffer.d.mts +8 -0
  160. package/dist/crypto/buffer.mjs +18 -0
  161. package/dist/crypto/buffer.mjs.map +1 -0
  162. package/dist/crypto/index.d.mts +27 -0
  163. package/dist/crypto/index.mjs +38 -0
  164. package/dist/crypto/index.mjs.map +1 -0
  165. package/dist/crypto/jwt.d.mts +8 -0
  166. package/dist/crypto/jwt.mjs +95 -0
  167. package/dist/crypto/jwt.mjs.map +1 -0
  168. package/dist/crypto/password.d.mts +12 -0
  169. package/dist/crypto/password.mjs +36 -0
  170. package/dist/crypto/password.mjs.map +1 -0
  171. package/dist/crypto/random.d.mts +5 -0
  172. package/dist/crypto/random.mjs +8 -0
  173. package/dist/crypto/random.mjs.map +1 -0
  174. package/dist/db/adapter-base.d.mts +8 -0
  175. package/dist/db/adapter-base.mjs +28 -0
  176. package/dist/db/adapter-base.mjs.map +1 -0
  177. package/dist/db/adapter-kysely.d.mts +8 -0
  178. package/dist/db/adapter-kysely.mjs +21 -0
  179. package/dist/db/adapter-kysely.mjs.map +1 -0
  180. package/dist/db/field-converter.d.mts +8 -0
  181. package/dist/db/field-converter.mjs +21 -0
  182. package/dist/db/field-converter.mjs.map +1 -0
  183. package/dist/db/field.d.mts +55 -0
  184. package/dist/db/field.mjs +11 -0
  185. package/dist/db/field.mjs.map +1 -0
  186. package/dist/db/get-migration.d.mts +23 -0
  187. package/dist/db/get-migration.mjs +339 -0
  188. package/dist/db/get-migration.mjs.map +1 -0
  189. package/dist/db/get-schema.d.mts +11 -0
  190. package/dist/db/get-schema.mjs +39 -0
  191. package/dist/db/get-schema.mjs.map +1 -0
  192. package/dist/db/index.d.mts +9 -0
  193. package/dist/db/index.mjs +36 -0
  194. package/dist/db/index.mjs.map +1 -0
  195. package/dist/db/internal-adapter.d.mts +14 -0
  196. package/dist/db/internal-adapter.mjs +616 -0
  197. package/dist/db/internal-adapter.mjs.map +1 -0
  198. package/dist/db/schema.d.mts +26 -0
  199. package/dist/db/schema.mjs +118 -0
  200. package/dist/db/schema.mjs.map +1 -0
  201. package/dist/db/to-zod.d.mts +36 -0
  202. package/dist/db/to-zod.mjs +26 -0
  203. package/dist/db/to-zod.mjs.map +1 -0
  204. package/dist/db/verification-token-storage.mjs +28 -0
  205. package/dist/db/verification-token-storage.mjs.map +1 -0
  206. package/dist/db/with-hooks.d.mts +33 -0
  207. package/dist/db/with-hooks.mjs +159 -0
  208. package/dist/db/with-hooks.mjs.map +1 -0
  209. package/dist/index.d.mts +52 -0
  210. package/dist/index.mjs +26 -0
  211. package/dist/integrations/next-js.d.mts +14 -0
  212. package/dist/integrations/next-js.mjs +78 -0
  213. package/dist/integrations/next-js.mjs.map +1 -0
  214. package/dist/integrations/node.d.mts +13 -0
  215. package/dist/integrations/node.mjs +16 -0
  216. package/dist/integrations/node.mjs.map +1 -0
  217. package/dist/integrations/solid-start.d.mts +23 -0
  218. package/dist/integrations/solid-start.mjs +17 -0
  219. package/dist/integrations/solid-start.mjs.map +1 -0
  220. package/dist/integrations/svelte-kit.d.mts +29 -0
  221. package/dist/integrations/svelte-kit.mjs +57 -0
  222. package/dist/integrations/svelte-kit.mjs.map +1 -0
  223. package/dist/integrations/tanstack-start-solid.d.mts +22 -0
  224. package/dist/integrations/tanstack-start-solid.mjs +61 -0
  225. package/dist/integrations/tanstack-start-solid.mjs.map +1 -0
  226. package/dist/integrations/tanstack-start.d.mts +22 -0
  227. package/dist/integrations/tanstack-start.mjs +61 -0
  228. package/dist/integrations/tanstack-start.mjs.map +1 -0
  229. package/dist/oauth2/index.d.mts +5 -0
  230. package/dist/oauth2/index.mjs +7 -0
  231. package/dist/oauth2/link-account.d.mts +31 -0
  232. package/dist/oauth2/link-account.mjs +144 -0
  233. package/dist/oauth2/link-account.mjs.map +1 -0
  234. package/dist/oauth2/state.d.mts +26 -0
  235. package/dist/oauth2/state.mjs +51 -0
  236. package/dist/oauth2/state.mjs.map +1 -0
  237. package/dist/oauth2/utils.d.mts +8 -0
  238. package/dist/oauth2/utils.mjs +31 -0
  239. package/dist/oauth2/utils.mjs.map +1 -0
  240. package/dist/plugins/access/access.d.mts +30 -0
  241. package/dist/plugins/access/access.mjs +46 -0
  242. package/dist/plugins/access/access.mjs.map +1 -0
  243. package/dist/plugins/access/index.d.mts +3 -0
  244. package/dist/plugins/access/index.mjs +3 -0
  245. package/dist/plugins/access/types.d.mts +17 -0
  246. package/dist/plugins/additional-fields/client.d.mts +14 -0
  247. package/dist/plugins/additional-fields/client.mjs +11 -0
  248. package/dist/plugins/additional-fields/client.mjs.map +1 -0
  249. package/dist/plugins/admin/access/index.d.mts +2 -0
  250. package/dist/plugins/admin/access/index.mjs +3 -0
  251. package/dist/plugins/admin/access/statement.d.mts +118 -0
  252. package/dist/plugins/admin/access/statement.mjs +53 -0
  253. package/dist/plugins/admin/access/statement.mjs.map +1 -0
  254. package/dist/plugins/admin/admin.d.mts +14 -0
  255. package/dist/plugins/admin/admin.mjs +95 -0
  256. package/dist/plugins/admin/admin.mjs.map +1 -0
  257. package/dist/plugins/admin/client.d.mts +14 -0
  258. package/dist/plugins/admin/client.mjs +36 -0
  259. package/dist/plugins/admin/client.mjs.map +1 -0
  260. package/dist/plugins/admin/error-codes.d.mts +5 -0
  261. package/dist/plugins/admin/error-codes.mjs +30 -0
  262. package/dist/plugins/admin/error-codes.mjs.map +1 -0
  263. package/dist/plugins/admin/has-permission.mjs +16 -0
  264. package/dist/plugins/admin/has-permission.mjs.map +1 -0
  265. package/dist/plugins/admin/index.d.mts +3 -0
  266. package/dist/plugins/admin/index.mjs +3 -0
  267. package/dist/plugins/admin/routes.mjs +855 -0
  268. package/dist/plugins/admin/routes.mjs.map +1 -0
  269. package/dist/plugins/admin/schema.d.mts +6 -0
  270. package/dist/plugins/admin/schema.mjs +34 -0
  271. package/dist/plugins/admin/schema.mjs.map +1 -0
  272. package/dist/plugins/admin/types.d.mts +89 -0
  273. package/dist/plugins/anonymous/client.d.mts +9 -0
  274. package/dist/plugins/anonymous/client.mjs +22 -0
  275. package/dist/plugins/anonymous/client.mjs.map +1 -0
  276. package/dist/plugins/anonymous/error-codes.d.mts +5 -0
  277. package/dist/plugins/anonymous/error-codes.mjs +16 -0
  278. package/dist/plugins/anonymous/error-codes.mjs.map +1 -0
  279. package/dist/plugins/anonymous/index.d.mts +14 -0
  280. package/dist/plugins/anonymous/index.mjs +163 -0
  281. package/dist/plugins/anonymous/index.mjs.map +1 -0
  282. package/dist/plugins/anonymous/schema.d.mts +5 -0
  283. package/dist/plugins/anonymous/schema.mjs +11 -0
  284. package/dist/plugins/anonymous/schema.mjs.map +1 -0
  285. package/dist/plugins/anonymous/types.d.mts +68 -0
  286. package/dist/plugins/api-key/adapter.mjs +468 -0
  287. package/dist/plugins/api-key/adapter.mjs.map +1 -0
  288. package/dist/plugins/api-key/client.d.mts +9 -0
  289. package/dist/plugins/api-key/client.mjs +19 -0
  290. package/dist/plugins/api-key/client.mjs.map +1 -0
  291. package/dist/plugins/api-key/error-codes.d.mts +5 -0
  292. package/dist/plugins/api-key/error-codes.mjs +34 -0
  293. package/dist/plugins/api-key/error-codes.mjs.map +1 -0
  294. package/dist/plugins/api-key/index.d.mts +17 -0
  295. package/dist/plugins/api-key/index.mjs +134 -0
  296. package/dist/plugins/api-key/index.mjs.map +1 -0
  297. package/dist/plugins/api-key/rate-limit.mjs +74 -0
  298. package/dist/plugins/api-key/rate-limit.mjs.map +1 -0
  299. package/dist/plugins/api-key/routes/create-api-key.mjs +252 -0
  300. package/dist/plugins/api-key/routes/create-api-key.mjs.map +1 -0
  301. package/dist/plugins/api-key/routes/delete-all-expired-api-keys.mjs +24 -0
  302. package/dist/plugins/api-key/routes/delete-all-expired-api-keys.mjs.map +1 -0
  303. package/dist/plugins/api-key/routes/delete-api-key.mjs +74 -0
  304. package/dist/plugins/api-key/routes/delete-api-key.mjs.map +1 -0
  305. package/dist/plugins/api-key/routes/get-api-key.mjs +158 -0
  306. package/dist/plugins/api-key/routes/get-api-key.mjs.map +1 -0
  307. package/dist/plugins/api-key/routes/index.mjs +71 -0
  308. package/dist/plugins/api-key/routes/index.mjs.map +1 -0
  309. package/dist/plugins/api-key/routes/list-api-keys.mjs +194 -0
  310. package/dist/plugins/api-key/routes/list-api-keys.mjs.map +1 -0
  311. package/dist/plugins/api-key/routes/update-api-key.mjs +248 -0
  312. package/dist/plugins/api-key/routes/update-api-key.mjs.map +1 -0
  313. package/dist/plugins/api-key/routes/verify-api-key.mjs +223 -0
  314. package/dist/plugins/api-key/routes/verify-api-key.mjs.map +1 -0
  315. package/dist/plugins/api-key/schema.d.mts +11 -0
  316. package/dist/plugins/api-key/schema.mjs +130 -0
  317. package/dist/plugins/api-key/schema.mjs.map +1 -0
  318. package/dist/plugins/api-key/types.d.mts +346 -0
  319. package/dist/plugins/bearer/index.d.mts +25 -0
  320. package/dist/plugins/bearer/index.mjs +66 -0
  321. package/dist/plugins/bearer/index.mjs.map +1 -0
  322. package/dist/plugins/captcha/constants.d.mts +10 -0
  323. package/dist/plugins/captcha/constants.mjs +22 -0
  324. package/dist/plugins/captcha/constants.mjs.map +1 -0
  325. package/dist/plugins/captcha/error-codes.mjs +16 -0
  326. package/dist/plugins/captcha/error-codes.mjs.map +1 -0
  327. package/dist/plugins/captcha/index.d.mts +14 -0
  328. package/dist/plugins/captcha/index.mjs +60 -0
  329. package/dist/plugins/captcha/index.mjs.map +1 -0
  330. package/dist/plugins/captcha/types.d.mts +28 -0
  331. package/dist/plugins/captcha/utils.mjs +11 -0
  332. package/dist/plugins/captcha/utils.mjs.map +1 -0
  333. package/dist/plugins/captcha/verify-handlers/captchafox.mjs +27 -0
  334. package/dist/plugins/captcha/verify-handlers/captchafox.mjs.map +1 -0
  335. package/dist/plugins/captcha/verify-handlers/cloudflare-turnstile.mjs +25 -0
  336. package/dist/plugins/captcha/verify-handlers/cloudflare-turnstile.mjs.map +1 -0
  337. package/dist/plugins/captcha/verify-handlers/google-recaptcha.mjs +29 -0
  338. package/dist/plugins/captcha/verify-handlers/google-recaptcha.mjs.map +1 -0
  339. package/dist/plugins/captcha/verify-handlers/h-captcha.mjs +27 -0
  340. package/dist/plugins/captcha/verify-handlers/h-captcha.mjs.map +1 -0
  341. package/dist/plugins/captcha/verify-handlers/index.mjs +6 -0
  342. package/dist/plugins/custom-session/client.d.mts +10 -0
  343. package/dist/plugins/custom-session/client.mjs +11 -0
  344. package/dist/plugins/custom-session/client.mjs.map +1 -0
  345. package/dist/plugins/custom-session/index.d.mts +26 -0
  346. package/dist/plugins/custom-session/index.mjs +70 -0
  347. package/dist/plugins/custom-session/index.mjs.map +1 -0
  348. package/dist/plugins/device-authorization/client.d.mts +5 -0
  349. package/dist/plugins/device-authorization/client.mjs +18 -0
  350. package/dist/plugins/device-authorization/client.mjs.map +1 -0
  351. package/dist/plugins/device-authorization/error-codes.mjs +21 -0
  352. package/dist/plugins/device-authorization/error-codes.mjs.map +1 -0
  353. package/dist/plugins/device-authorization/index.d.mts +28 -0
  354. package/dist/plugins/device-authorization/index.mjs +50 -0
  355. package/dist/plugins/device-authorization/index.mjs.map +1 -0
  356. package/dist/plugins/device-authorization/routes.mjs +510 -0
  357. package/dist/plugins/device-authorization/routes.mjs.map +1 -0
  358. package/dist/plugins/device-authorization/schema.mjs +57 -0
  359. package/dist/plugins/device-authorization/schema.mjs.map +1 -0
  360. package/dist/plugins/email-otp/client.d.mts +7 -0
  361. package/dist/plugins/email-otp/client.mjs +18 -0
  362. package/dist/plugins/email-otp/client.mjs.map +1 -0
  363. package/dist/plugins/email-otp/error-codes.d.mts +5 -0
  364. package/dist/plugins/email-otp/error-codes.mjs +12 -0
  365. package/dist/plugins/email-otp/error-codes.mjs.map +1 -0
  366. package/dist/plugins/email-otp/index.d.mts +14 -0
  367. package/dist/plugins/email-otp/index.mjs +108 -0
  368. package/dist/plugins/email-otp/index.mjs.map +1 -0
  369. package/dist/plugins/email-otp/otp-token.mjs +29 -0
  370. package/dist/plugins/email-otp/otp-token.mjs.map +1 -0
  371. package/dist/plugins/email-otp/routes.mjs +564 -0
  372. package/dist/plugins/email-otp/routes.mjs.map +1 -0
  373. package/dist/plugins/email-otp/types.d.mts +74 -0
  374. package/dist/plugins/email-otp/utils.mjs +17 -0
  375. package/dist/plugins/email-otp/utils.mjs.map +1 -0
  376. package/dist/plugins/generic-oauth/client.d.mts +19 -0
  377. package/dist/plugins/generic-oauth/client.mjs +14 -0
  378. package/dist/plugins/generic-oauth/client.mjs.map +1 -0
  379. package/dist/plugins/generic-oauth/error-codes.d.mts +5 -0
  380. package/dist/plugins/generic-oauth/error-codes.mjs +15 -0
  381. package/dist/plugins/generic-oauth/error-codes.mjs.map +1 -0
  382. package/dist/plugins/generic-oauth/index.d.mts +34 -0
  383. package/dist/plugins/generic-oauth/index.mjs +137 -0
  384. package/dist/plugins/generic-oauth/index.mjs.map +1 -0
  385. package/dist/plugins/generic-oauth/providers/auth0.d.mts +37 -0
  386. package/dist/plugins/generic-oauth/providers/auth0.mjs +62 -0
  387. package/dist/plugins/generic-oauth/providers/auth0.mjs.map +1 -0
  388. package/dist/plugins/generic-oauth/providers/gumroad.d.mts +32 -0
  389. package/dist/plugins/generic-oauth/providers/gumroad.mjs +60 -0
  390. package/dist/plugins/generic-oauth/providers/gumroad.mjs.map +1 -0
  391. package/dist/plugins/generic-oauth/providers/hubspot.d.mts +37 -0
  392. package/dist/plugins/generic-oauth/providers/hubspot.mjs +60 -0
  393. package/dist/plugins/generic-oauth/providers/hubspot.mjs.map +1 -0
  394. package/dist/plugins/generic-oauth/providers/index.d.mts +9 -0
  395. package/dist/plugins/generic-oauth/providers/index.mjs +11 -0
  396. package/dist/plugins/generic-oauth/providers/keycloak.d.mts +37 -0
  397. package/dist/plugins/generic-oauth/providers/keycloak.mjs +62 -0
  398. package/dist/plugins/generic-oauth/providers/keycloak.mjs.map +1 -0
  399. package/dist/plugins/generic-oauth/providers/line.d.mts +55 -0
  400. package/dist/plugins/generic-oauth/providers/line.mjs +91 -0
  401. package/dist/plugins/generic-oauth/providers/line.mjs.map +1 -0
  402. package/dist/plugins/generic-oauth/providers/microsoft-entra-id.d.mts +37 -0
  403. package/dist/plugins/generic-oauth/providers/microsoft-entra-id.mjs +66 -0
  404. package/dist/plugins/generic-oauth/providers/microsoft-entra-id.mjs.map +1 -0
  405. package/dist/plugins/generic-oauth/providers/okta.d.mts +37 -0
  406. package/dist/plugins/generic-oauth/providers/okta.mjs +62 -0
  407. package/dist/plugins/generic-oauth/providers/okta.mjs.map +1 -0
  408. package/dist/plugins/generic-oauth/providers/patreon.d.mts +30 -0
  409. package/dist/plugins/generic-oauth/providers/patreon.mjs +59 -0
  410. package/dist/plugins/generic-oauth/providers/patreon.mjs.map +1 -0
  411. package/dist/plugins/generic-oauth/providers/slack.d.mts +30 -0
  412. package/dist/plugins/generic-oauth/providers/slack.mjs +61 -0
  413. package/dist/plugins/generic-oauth/providers/slack.mjs.map +1 -0
  414. package/dist/plugins/generic-oauth/routes.mjs +394 -0
  415. package/dist/plugins/generic-oauth/routes.mjs.map +1 -0
  416. package/dist/plugins/generic-oauth/types.d.mts +145 -0
  417. package/dist/plugins/haveibeenpwned/index.d.mts +21 -0
  418. package/dist/plugins/haveibeenpwned/index.mjs +56 -0
  419. package/dist/plugins/haveibeenpwned/index.mjs.map +1 -0
  420. package/dist/plugins/index.d.mts +68 -0
  421. package/dist/plugins/index.mjs +51 -0
  422. package/dist/plugins/jwt/adapter.mjs +27 -0
  423. package/dist/plugins/jwt/adapter.mjs.map +1 -0
  424. package/dist/plugins/jwt/client.d.mts +18 -0
  425. package/dist/plugins/jwt/client.mjs +19 -0
  426. package/dist/plugins/jwt/client.mjs.map +1 -0
  427. package/dist/plugins/jwt/index.d.mts +17 -0
  428. package/dist/plugins/jwt/index.mjs +202 -0
  429. package/dist/plugins/jwt/index.mjs.map +1 -0
  430. package/dist/plugins/jwt/schema.d.mts +5 -0
  431. package/dist/plugins/jwt/schema.mjs +23 -0
  432. package/dist/plugins/jwt/schema.mjs.map +1 -0
  433. package/dist/plugins/jwt/sign.d.mts +57 -0
  434. package/dist/plugins/jwt/sign.mjs +66 -0
  435. package/dist/plugins/jwt/sign.mjs.map +1 -0
  436. package/dist/plugins/jwt/types.d.mts +194 -0
  437. package/dist/plugins/jwt/utils.d.mts +42 -0
  438. package/dist/plugins/jwt/utils.mjs +64 -0
  439. package/dist/plugins/jwt/utils.mjs.map +1 -0
  440. package/dist/plugins/jwt/verify.d.mts +12 -0
  441. package/dist/plugins/jwt/verify.mjs +46 -0
  442. package/dist/plugins/jwt/verify.mjs.map +1 -0
  443. package/dist/plugins/last-login-method/client.d.mts +18 -0
  444. package/dist/plugins/last-login-method/client.mjs +32 -0
  445. package/dist/plugins/last-login-method/client.mjs.map +1 -0
  446. package/dist/plugins/last-login-method/index.d.mts +52 -0
  447. package/dist/plugins/last-login-method/index.mjs +77 -0
  448. package/dist/plugins/last-login-method/index.mjs.map +1 -0
  449. package/dist/plugins/magic-link/client.d.mts +5 -0
  450. package/dist/plugins/magic-link/client.mjs +11 -0
  451. package/dist/plugins/magic-link/client.mjs.map +1 -0
  452. package/dist/plugins/magic-link/index.d.mts +61 -0
  453. package/dist/plugins/magic-link/index.mjs +167 -0
  454. package/dist/plugins/magic-link/index.mjs.map +1 -0
  455. package/dist/plugins/magic-link/utils.mjs +12 -0
  456. package/dist/plugins/magic-link/utils.mjs.map +1 -0
  457. package/dist/plugins/mcp/authorize.mjs +133 -0
  458. package/dist/plugins/mcp/authorize.mjs.map +1 -0
  459. package/dist/plugins/mcp/index.d.mts +46 -0
  460. package/dist/plugins/mcp/index.mjs +717 -0
  461. package/dist/plugins/mcp/index.mjs.map +1 -0
  462. package/dist/plugins/multi-session/client.d.mts +8 -0
  463. package/dist/plugins/multi-session/client.mjs +20 -0
  464. package/dist/plugins/multi-session/client.mjs.map +1 -0
  465. package/dist/plugins/multi-session/error-codes.d.mts +5 -0
  466. package/dist/plugins/multi-session/error-codes.mjs +8 -0
  467. package/dist/plugins/multi-session/error-codes.mjs.map +1 -0
  468. package/dist/plugins/multi-session/index.d.mts +22 -0
  469. package/dist/plugins/multi-session/index.mjs +172 -0
  470. package/dist/plugins/multi-session/index.mjs.map +1 -0
  471. package/dist/plugins/oauth-proxy/index.d.mts +39 -0
  472. package/dist/plugins/oauth-proxy/index.mjs +305 -0
  473. package/dist/plugins/oauth-proxy/index.mjs.map +1 -0
  474. package/dist/plugins/oauth-proxy/utils.mjs +44 -0
  475. package/dist/plugins/oauth-proxy/utils.mjs.map +1 -0
  476. package/dist/plugins/oidc-provider/authorize.mjs +194 -0
  477. package/dist/plugins/oidc-provider/authorize.mjs.map +1 -0
  478. package/dist/plugins/oidc-provider/client.d.mts +8 -0
  479. package/dist/plugins/oidc-provider/client.mjs +11 -0
  480. package/dist/plugins/oidc-provider/client.mjs.map +1 -0
  481. package/dist/plugins/oidc-provider/error.mjs +17 -0
  482. package/dist/plugins/oidc-provider/error.mjs.map +1 -0
  483. package/dist/plugins/oidc-provider/index.d.mts +32 -0
  484. package/dist/plugins/oidc-provider/index.mjs +1093 -0
  485. package/dist/plugins/oidc-provider/index.mjs.map +1 -0
  486. package/dist/plugins/oidc-provider/schema.d.mts +26 -0
  487. package/dist/plugins/oidc-provider/schema.mjs +132 -0
  488. package/dist/plugins/oidc-provider/schema.mjs.map +1 -0
  489. package/dist/plugins/oidc-provider/types.d.mts +517 -0
  490. package/dist/plugins/oidc-provider/utils/prompt.mjs +19 -0
  491. package/dist/plugins/oidc-provider/utils/prompt.mjs.map +1 -0
  492. package/dist/plugins/oidc-provider/utils.mjs +15 -0
  493. package/dist/plugins/oidc-provider/utils.mjs.map +1 -0
  494. package/dist/plugins/one-tap/client.d.mts +159 -0
  495. package/dist/plugins/one-tap/client.mjs +214 -0
  496. package/dist/plugins/one-tap/client.mjs.map +1 -0
  497. package/dist/plugins/one-tap/index.d.mts +27 -0
  498. package/dist/plugins/one-tap/index.mjs +96 -0
  499. package/dist/plugins/one-tap/index.mjs.map +1 -0
  500. package/dist/plugins/one-time-token/client.d.mts +7 -0
  501. package/dist/plugins/one-time-token/client.mjs +11 -0
  502. package/dist/plugins/one-time-token/client.mjs.map +1 -0
  503. package/dist/plugins/one-time-token/index.d.mts +53 -0
  504. package/dist/plugins/one-time-token/index.mjs +82 -0
  505. package/dist/plugins/one-time-token/index.mjs.map +1 -0
  506. package/dist/plugins/one-time-token/utils.mjs +12 -0
  507. package/dist/plugins/one-time-token/utils.mjs.map +1 -0
  508. package/dist/plugins/open-api/generator.d.mts +115 -0
  509. package/dist/plugins/open-api/generator.mjs +315 -0
  510. package/dist/plugins/open-api/generator.mjs.map +1 -0
  511. package/dist/plugins/open-api/index.d.mts +45 -0
  512. package/dist/plugins/open-api/index.mjs +67 -0
  513. package/dist/plugins/open-api/index.mjs.map +1 -0
  514. package/dist/plugins/open-api/logo.mjs +15 -0
  515. package/dist/plugins/open-api/logo.mjs.map +1 -0
  516. package/dist/plugins/organization/access/index.d.mts +2 -0
  517. package/dist/plugins/organization/access/index.mjs +3 -0
  518. package/dist/plugins/organization/access/statement.d.mts +249 -0
  519. package/dist/plugins/organization/access/statement.mjs +81 -0
  520. package/dist/plugins/organization/access/statement.mjs.map +1 -0
  521. package/dist/plugins/organization/adapter.d.mts +205 -0
  522. package/dist/plugins/organization/adapter.mjs +624 -0
  523. package/dist/plugins/organization/adapter.mjs.map +1 -0
  524. package/dist/plugins/organization/call.mjs +19 -0
  525. package/dist/plugins/organization/call.mjs.map +1 -0
  526. package/dist/plugins/organization/client.d.mts +151 -0
  527. package/dist/plugins/organization/client.mjs +107 -0
  528. package/dist/plugins/organization/client.mjs.map +1 -0
  529. package/dist/plugins/organization/error-codes.d.mts +5 -0
  530. package/dist/plugins/organization/error-codes.mjs +65 -0
  531. package/dist/plugins/organization/error-codes.mjs.map +1 -0
  532. package/dist/plugins/organization/has-permission.mjs +35 -0
  533. package/dist/plugins/organization/has-permission.mjs.map +1 -0
  534. package/dist/plugins/organization/index.d.mts +5 -0
  535. package/dist/plugins/organization/index.mjs +4 -0
  536. package/dist/plugins/organization/organization.d.mts +252 -0
  537. package/dist/plugins/organization/organization.mjs +428 -0
  538. package/dist/plugins/organization/organization.mjs.map +1 -0
  539. package/dist/plugins/organization/permission.d.mts +26 -0
  540. package/dist/plugins/organization/permission.mjs +16 -0
  541. package/dist/plugins/organization/permission.mjs.map +1 -0
  542. package/dist/plugins/organization/routes/crud-access-control.d.mts +11 -0
  543. package/dist/plugins/organization/routes/crud-access-control.mjs +656 -0
  544. package/dist/plugins/organization/routes/crud-access-control.mjs.map +1 -0
  545. package/dist/plugins/organization/routes/crud-invites.d.mts +16 -0
  546. package/dist/plugins/organization/routes/crud-invites.mjs +555 -0
  547. package/dist/plugins/organization/routes/crud-invites.mjs.map +1 -0
  548. package/dist/plugins/organization/routes/crud-members.d.mts +13 -0
  549. package/dist/plugins/organization/routes/crud-members.mjs +473 -0
  550. package/dist/plugins/organization/routes/crud-members.mjs.map +1 -0
  551. package/dist/plugins/organization/routes/crud-org.d.mts +13 -0
  552. package/dist/plugins/organization/routes/crud-org.mjs +447 -0
  553. package/dist/plugins/organization/routes/crud-org.mjs.map +1 -0
  554. package/dist/plugins/organization/routes/crud-team.d.mts +15 -0
  555. package/dist/plugins/organization/routes/crud-team.mjs +676 -0
  556. package/dist/plugins/organization/routes/crud-team.mjs.map +1 -0
  557. package/dist/plugins/organization/schema.d.mts +376 -0
  558. package/dist/plugins/organization/schema.mjs +68 -0
  559. package/dist/plugins/organization/schema.mjs.map +1 -0
  560. package/dist/plugins/organization/types.d.mts +733 -0
  561. package/dist/plugins/phone-number/client.d.mts +8 -0
  562. package/dist/plugins/phone-number/client.mjs +20 -0
  563. package/dist/plugins/phone-number/client.mjs.map +1 -0
  564. package/dist/plugins/phone-number/error-codes.d.mts +5 -0
  565. package/dist/plugins/phone-number/error-codes.mjs +21 -0
  566. package/dist/plugins/phone-number/error-codes.mjs.map +1 -0
  567. package/dist/plugins/phone-number/index.d.mts +14 -0
  568. package/dist/plugins/phone-number/index.mjs +49 -0
  569. package/dist/plugins/phone-number/index.mjs.map +1 -0
  570. package/dist/plugins/phone-number/routes.mjs +459 -0
  571. package/dist/plugins/phone-number/routes.mjs.map +1 -0
  572. package/dist/plugins/phone-number/schema.d.mts +5 -0
  573. package/dist/plugins/phone-number/schema.mjs +20 -0
  574. package/dist/plugins/phone-number/schema.mjs.map +1 -0
  575. package/dist/plugins/phone-number/types.d.mts +118 -0
  576. package/dist/plugins/siwe/client.d.mts +5 -0
  577. package/dist/plugins/siwe/client.mjs +11 -0
  578. package/dist/plugins/siwe/client.mjs.map +1 -0
  579. package/dist/plugins/siwe/error-codes.mjs +13 -0
  580. package/dist/plugins/siwe/error-codes.mjs.map +1 -0
  581. package/dist/plugins/siwe/index.d.mts +26 -0
  582. package/dist/plugins/siwe/index.mjs +261 -0
  583. package/dist/plugins/siwe/index.mjs.map +1 -0
  584. package/dist/plugins/siwe/schema.d.mts +5 -0
  585. package/dist/plugins/siwe/schema.mjs +32 -0
  586. package/dist/plugins/siwe/schema.mjs.map +1 -0
  587. package/dist/plugins/siwe/types.d.mts +44 -0
  588. package/dist/plugins/two-factor/backup-codes/index.d.mts +91 -0
  589. package/dist/plugins/two-factor/backup-codes/index.mjs +277 -0
  590. package/dist/plugins/two-factor/backup-codes/index.mjs.map +1 -0
  591. package/dist/plugins/two-factor/client.d.mts +17 -0
  592. package/dist/plugins/two-factor/client.mjs +37 -0
  593. package/dist/plugins/two-factor/client.mjs.map +1 -0
  594. package/dist/plugins/two-factor/constant.mjs +8 -0
  595. package/dist/plugins/two-factor/constant.mjs.map +1 -0
  596. package/dist/plugins/two-factor/error-code.d.mts +5 -0
  597. package/dist/plugins/two-factor/error-code.mjs +18 -0
  598. package/dist/plugins/two-factor/error-code.mjs.map +1 -0
  599. package/dist/plugins/two-factor/index.d.mts +19 -0
  600. package/dist/plugins/two-factor/index.mjs +207 -0
  601. package/dist/plugins/two-factor/index.mjs.map +1 -0
  602. package/dist/plugins/two-factor/otp/index.d.mts +96 -0
  603. package/dist/plugins/two-factor/otp/index.mjs +199 -0
  604. package/dist/plugins/two-factor/otp/index.mjs.map +1 -0
  605. package/dist/plugins/two-factor/schema.d.mts +5 -0
  606. package/dist/plugins/two-factor/schema.mjs +36 -0
  607. package/dist/plugins/two-factor/schema.mjs.map +1 -0
  608. package/dist/plugins/two-factor/totp/index.d.mts +81 -0
  609. package/dist/plugins/two-factor/totp/index.mjs +157 -0
  610. package/dist/plugins/two-factor/totp/index.mjs.map +1 -0
  611. package/dist/plugins/two-factor/types.d.mts +65 -0
  612. package/dist/plugins/two-factor/utils.mjs +12 -0
  613. package/dist/plugins/two-factor/utils.mjs.map +1 -0
  614. package/dist/plugins/two-factor/verify-two-factor.mjs +76 -0
  615. package/dist/plugins/two-factor/verify-two-factor.mjs.map +1 -0
  616. package/dist/plugins/username/client.d.mts +7 -0
  617. package/dist/plugins/username/client.mjs +18 -0
  618. package/dist/plugins/username/client.mjs.map +1 -0
  619. package/dist/plugins/username/error-codes.d.mts +5 -0
  620. package/dist/plugins/username/error-codes.mjs +17 -0
  621. package/dist/plugins/username/error-codes.mjs.map +1 -0
  622. package/dist/plugins/username/index.d.mts +74 -0
  623. package/dist/plugins/username/index.mjs +237 -0
  624. package/dist/plugins/username/index.mjs.map +1 -0
  625. package/dist/plugins/username/schema.d.mts +9 -0
  626. package/dist/plugins/username/schema.mjs +26 -0
  627. package/dist/plugins/username/schema.mjs.map +1 -0
  628. package/dist/social-providers/index.d.mts +1 -0
  629. package/dist/social-providers/index.mjs +3 -0
  630. package/dist/state.d.mts +42 -0
  631. package/dist/state.mjs +107 -0
  632. package/dist/state.mjs.map +1 -0
  633. package/dist/test-utils/headers.d.mts +9 -0
  634. package/dist/test-utils/headers.mjs +24 -0
  635. package/dist/test-utils/headers.mjs.map +1 -0
  636. package/dist/test-utils/index.d.mts +3 -0
  637. package/dist/test-utils/index.mjs +4 -0
  638. package/dist/test-utils/test-instance.d.mts +181 -0
  639. package/dist/test-utils/test-instance.mjs +210 -0
  640. package/dist/test-utils/test-instance.mjs.map +1 -0
  641. package/dist/types/adapter.d.mts +24 -0
  642. package/dist/types/api.d.mts +62 -0
  643. package/dist/types/auth.d.mts +30 -0
  644. package/dist/types/helper.d.mts +21 -0
  645. package/dist/types/index.d.mts +11 -0
  646. package/dist/types/index.mjs +1 -0
  647. package/dist/types/models.d.mts +17 -0
  648. package/dist/types/plugins.d.mts +16 -0
  649. package/dist/utils/boolean.mjs +8 -0
  650. package/dist/utils/boolean.mjs.map +1 -0
  651. package/dist/utils/constants.mjs +6 -0
  652. package/dist/utils/constants.mjs.map +1 -0
  653. package/dist/utils/date.mjs +8 -0
  654. package/dist/utils/date.mjs.map +1 -0
  655. package/dist/utils/get-request-ip.d.mts +7 -0
  656. package/dist/utils/get-request-ip.mjs +23 -0
  657. package/dist/utils/get-request-ip.mjs.map +1 -0
  658. package/dist/utils/hashing.mjs +21 -0
  659. package/dist/utils/hashing.mjs.map +1 -0
  660. package/dist/utils/hide-metadata.d.mts +7 -0
  661. package/dist/utils/hide-metadata.mjs +6 -0
  662. package/dist/utils/hide-metadata.mjs.map +1 -0
  663. package/dist/utils/index.d.mts +3 -0
  664. package/dist/utils/index.mjs +5 -0
  665. package/dist/utils/is-api-error.d.mts +7 -0
  666. package/dist/utils/is-api-error.mjs +11 -0
  667. package/dist/utils/is-api-error.mjs.map +1 -0
  668. package/dist/utils/is-atom.mjs +8 -0
  669. package/dist/utils/is-atom.mjs.map +1 -0
  670. package/dist/utils/is-promise.mjs +8 -0
  671. package/dist/utils/is-promise.mjs.map +1 -0
  672. package/dist/utils/middleware-response.mjs +6 -0
  673. package/dist/utils/middleware-response.mjs.map +1 -0
  674. package/dist/utils/password.mjs +26 -0
  675. package/dist/utils/password.mjs.map +1 -0
  676. package/dist/utils/plugin-helper.mjs +17 -0
  677. package/dist/utils/plugin-helper.mjs.map +1 -0
  678. package/dist/utils/shim.mjs +24 -0
  679. package/dist/utils/shim.mjs.map +1 -0
  680. package/dist/utils/time.d.mts +49 -0
  681. package/dist/utils/time.mjs +100 -0
  682. package/dist/utils/time.mjs.map +1 -0
  683. package/dist/utils/url.mjs +92 -0
  684. package/dist/utils/url.mjs.map +1 -0
  685. package/dist/utils/wildcard.mjs +108 -0
  686. package/dist/utils/wildcard.mjs.map +1 -0
  687. package/package.json +601 -0
@@ -0,0 +1,64 @@
1
+ import { symmetricEncrypt } from "../../crypto/index.mjs";
2
+ import { sec } from "../../utils/time.mjs";
3
+ import { getJwksAdapter } from "./adapter.mjs";
4
+ import { exportJWK, generateKeyPair } from "jose";
5
+
6
+ //#region src/plugins/jwt/utils.ts
7
+ /**
8
+ * Converts an expirationTime to ISO seconds expiration time (the format of JWT exp)
9
+ *
10
+ * See https://github.com/panva/jose/blob/main/src/lib/jwt_claims_set.ts#L245
11
+ *
12
+ * @param expirationTime - see options.jwt.expirationTime
13
+ * @param iat - the iat time to consolidate on
14
+ * @returns
15
+ */
16
+ function toExpJWT(expirationTime, iat) {
17
+ if (typeof expirationTime === "number") return expirationTime;
18
+ else if (expirationTime instanceof Date) return Math.floor(expirationTime.getTime() / 1e3);
19
+ else return iat + sec(expirationTime);
20
+ }
21
+ async function generateExportedKeyPair(options) {
22
+ const { alg, ...cfg } = options?.jwks?.keyPairConfig ?? {
23
+ alg: "EdDSA",
24
+ crv: "Ed25519"
25
+ };
26
+ const { publicKey, privateKey } = await generateKeyPair(alg, {
27
+ ...cfg,
28
+ extractable: true
29
+ });
30
+ return {
31
+ publicWebKey: await exportJWK(publicKey),
32
+ privateWebKey: await exportJWK(privateKey),
33
+ alg,
34
+ cfg
35
+ };
36
+ }
37
+ /**
38
+ * Creates a Jwk on the database
39
+ *
40
+ * @param ctx
41
+ * @param options
42
+ * @returns
43
+ */
44
+ async function createJwk(ctx, options) {
45
+ const { publicWebKey, privateWebKey, alg, cfg } = await generateExportedKeyPair(options);
46
+ const stringifiedPrivateWebKey = JSON.stringify(privateWebKey);
47
+ const privateKeyEncryptionEnabled = !options?.jwks?.disablePrivateKeyEncryption;
48
+ const jwk = {
49
+ alg,
50
+ ...cfg && "crv" in cfg ? { crv: cfg.crv } : {},
51
+ publicKey: JSON.stringify(publicWebKey),
52
+ privateKey: privateKeyEncryptionEnabled ? JSON.stringify(await symmetricEncrypt({
53
+ key: ctx.context.secret,
54
+ data: stringifiedPrivateWebKey
55
+ })) : stringifiedPrivateWebKey,
56
+ createdAt: /* @__PURE__ */ new Date(),
57
+ ...options?.jwks?.rotationInterval ? { expiresAt: new Date(Date.now() + options.jwks.rotationInterval * 1e3) } : {}
58
+ };
59
+ return await getJwksAdapter(ctx.context.adapter, options).createJwk(ctx, jwk);
60
+ }
61
+
62
+ //#endregion
63
+ export { createJwk, generateExportedKeyPair, toExpJWT };
64
+ //# sourceMappingURL=utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.mjs","names":[],"sources":["../../../src/plugins/jwt/utils.ts"],"sourcesContent":["import type { GenericEndpointContext } from \"@better-auth/core\";\nimport { exportJWK, generateKeyPair } from \"jose\";\nimport { symmetricEncrypt } from \"../../crypto\";\nimport type { TimeString } from \"../../utils/time\";\nimport { sec } from \"../../utils/time\";\nimport { getJwksAdapter } from \"./adapter\";\nimport type { Jwk, JwtOptions } from \"./types\";\n\n/**\n * Converts an expirationTime to ISO seconds expiration time (the format of JWT exp)\n *\n * See https://github.com/panva/jose/blob/main/src/lib/jwt_claims_set.ts#L245\n *\n * @param expirationTime - see options.jwt.expirationTime\n * @param iat - the iat time to consolidate on\n * @returns\n */\nexport function toExpJWT(\n\texpirationTime: number | Date | string,\n\tiat: number,\n): number {\n\tif (typeof expirationTime === \"number\") {\n\t\treturn expirationTime;\n\t} else if (expirationTime instanceof Date) {\n\t\treturn Math.floor(expirationTime.getTime() / 1000);\n\t} else {\n\t\treturn iat + sec(expirationTime as TimeString);\n\t}\n}\n\nexport async function generateExportedKeyPair(\n\toptions?: JwtOptions | undefined,\n) {\n\tconst { alg, ...cfg } = options?.jwks?.keyPairConfig ?? {\n\t\talg: \"EdDSA\",\n\t\tcrv: \"Ed25519\",\n\t};\n\tconst { publicKey, privateKey } = await generateKeyPair(alg, {\n\t\t...cfg,\n\t\textractable: true,\n\t});\n\n\tconst publicWebKey = await exportJWK(publicKey);\n\tconst privateWebKey = await exportJWK(privateKey);\n\n\treturn { publicWebKey, privateWebKey, alg, cfg };\n}\n\n/**\n * Creates a Jwk on the database\n *\n * @param ctx\n * @param options\n * @returns\n */\nexport async function createJwk(\n\tctx: GenericEndpointContext,\n\toptions?: JwtOptions | undefined,\n) {\n\tconst { publicWebKey, privateWebKey, alg, cfg } =\n\t\tawait generateExportedKeyPair(options);\n\n\tconst stringifiedPrivateWebKey = JSON.stringify(privateWebKey);\n\tconst privateKeyEncryptionEnabled =\n\t\t!options?.jwks?.disablePrivateKeyEncryption;\n\tconst jwk: Omit<Jwk, \"id\"> = {\n\t\talg,\n\t\t...(cfg && \"crv\" in cfg\n\t\t\t? {\n\t\t\t\t\tcrv: (cfg as { crv: (typeof jwk)[\"crv\"] }).crv,\n\t\t\t\t}\n\t\t\t: {}),\n\t\tpublicKey: JSON.stringify(publicWebKey),\n\t\tprivateKey: privateKeyEncryptionEnabled\n\t\t\t? JSON.stringify(\n\t\t\t\t\tawait symmetricEncrypt({\n\t\t\t\t\t\tkey: ctx.context.secret,\n\t\t\t\t\t\tdata: stringifiedPrivateWebKey,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t: stringifiedPrivateWebKey,\n\t\tcreatedAt: new Date(),\n\t\t...(options?.jwks?.rotationInterval\n\t\t\t? {\n\t\t\t\t\texpiresAt: new Date(\n\t\t\t\t\t\tDate.now() + options.jwks.rotationInterval * 1000,\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n\n\tconst adapter = getJwksAdapter(ctx.context.adapter, options);\n\tconst key = await adapter.createJwk(ctx, jwk as Jwk);\n\n\treturn key;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAiBA,SAAgB,SACf,gBACA,KACS;AACT,KAAI,OAAO,mBAAmB,SAC7B,QAAO;UACG,0BAA0B,KACpC,QAAO,KAAK,MAAM,eAAe,SAAS,GAAG,IAAK;KAElD,QAAO,MAAM,IAAI,eAA6B;;AAIhD,eAAsB,wBACrB,SACC;CACD,MAAM,EAAE,KAAK,GAAG,QAAQ,SAAS,MAAM,iBAAiB;EACvD,KAAK;EACL,KAAK;EACL;CACD,MAAM,EAAE,WAAW,eAAe,MAAM,gBAAgB,KAAK;EAC5D,GAAG;EACH,aAAa;EACb,CAAC;AAKF,QAAO;EAAE,cAHY,MAAM,UAAU,UAAU;EAGxB,eAFD,MAAM,UAAU,WAAW;EAEX;EAAK;EAAK;;;;;;;;;AAUjD,eAAsB,UACrB,KACA,SACC;CACD,MAAM,EAAE,cAAc,eAAe,KAAK,QACzC,MAAM,wBAAwB,QAAQ;CAEvC,MAAM,2BAA2B,KAAK,UAAU,cAAc;CAC9D,MAAM,8BACL,CAAC,SAAS,MAAM;CACjB,MAAM,MAAuB;EAC5B;EACA,GAAI,OAAO,SAAS,MACjB,EACA,KAAM,IAAqC,KAC3C,GACA,EAAE;EACL,WAAW,KAAK,UAAU,aAAa;EACvC,YAAY,8BACT,KAAK,UACL,MAAM,iBAAiB;GACtB,KAAK,IAAI,QAAQ;GACjB,MAAM;GACN,CAAC,CACF,GACA;EACH,2BAAW,IAAI,MAAM;EACrB,GAAI,SAAS,MAAM,mBAChB,EACA,WAAW,IAAI,KACd,KAAK,KAAK,GAAG,QAAQ,KAAK,mBAAmB,IAC7C,EACD,GACA,EAAE;EACL;AAKD,QAFY,MADI,eAAe,IAAI,QAAQ,SAAS,QAAQ,CAClC,UAAU,KAAK,IAAW"}
@@ -0,0 +1,12 @@
1
+ import { JwtOptions } from "./types.mjs";
2
+ import { JWTPayload } from "jose";
3
+
4
+ //#region src/plugins/jwt/verify.d.ts
5
+ /**
6
+ * Verify a JWT token using the JWKS public keys
7
+ * Returns the payload if valid, null otherwise
8
+ */
9
+ declare function verifyJWT<T extends JWTPayload = JWTPayload>(token: string, options?: JwtOptions): Promise<(T & Required<Pick<JWTPayload, "sub" | "aud">>) | null>;
10
+ //#endregion
11
+ export { verifyJWT };
12
+ //# sourceMappingURL=verify.d.mts.map
@@ -0,0 +1,46 @@
1
+ import { getJwksAdapter } from "./adapter.mjs";
2
+ import { getCurrentAuthContext } from "@better-auth/core/context";
3
+ import { importJWK, jwtVerify } from "jose";
4
+ import { base64 } from "@better-auth/utils/base64";
5
+
6
+ //#region src/plugins/jwt/verify.ts
7
+ /**
8
+ * Verify a JWT token using the JWKS public keys
9
+ * Returns the payload if valid, null otherwise
10
+ */
11
+ async function verifyJWT(token, options) {
12
+ const ctx = await getCurrentAuthContext();
13
+ try {
14
+ const parts = token.split(".");
15
+ if (parts.length !== 3) return null;
16
+ const headerStr = new TextDecoder().decode(base64.decode(parts[0]));
17
+ const kid = JSON.parse(headerStr).kid;
18
+ if (!kid) {
19
+ ctx.context.logger.debug("JWT missing kid in header");
20
+ return null;
21
+ }
22
+ const keys = await getJwksAdapter(ctx.context.adapter, options).getAllKeys(ctx);
23
+ if (!keys || keys.length === 0) {
24
+ ctx.context.logger.debug("No JWKS keys available");
25
+ return null;
26
+ }
27
+ const key = keys.find((k) => k.id === kid);
28
+ if (!key) {
29
+ ctx.context.logger.debug(`No JWKS key found for kid: ${kid}`);
30
+ return null;
31
+ }
32
+ const { payload } = await jwtVerify(token, await importJWK(JSON.parse(key.publicKey), key.alg ?? options?.jwks?.keyPairConfig?.alg ?? "EdDSA"), {
33
+ issuer: options?.jwt?.issuer ?? ctx.context.options.baseURL,
34
+ audience: options?.jwt?.audience ?? ctx.context.options.baseURL
35
+ });
36
+ if (!payload.sub || !payload.aud) return null;
37
+ return payload;
38
+ } catch (error) {
39
+ ctx.context.logger.debug("JWT verification failed", error);
40
+ return null;
41
+ }
42
+ }
43
+
44
+ //#endregion
45
+ export { verifyJWT };
46
+ //# sourceMappingURL=verify.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.mjs","names":[],"sources":["../../../src/plugins/jwt/verify.ts"],"sourcesContent":["import type { GenericEndpointContext } from \"@better-auth/core\";\nimport { getCurrentAuthContext } from \"@better-auth/core/context\";\nimport { base64 } from \"@better-auth/utils/base64\";\nimport type { JWTPayload } from \"jose\";\nimport { importJWK, jwtVerify } from \"jose\";\nimport { getJwksAdapter } from \"./adapter\";\nimport type { JwtOptions } from \"./types\";\n\n/**\n * Verify a JWT token using the JWKS public keys\n * Returns the payload if valid, null otherwise\n */\nexport async function verifyJWT<T extends JWTPayload = JWTPayload>(\n\ttoken: string,\n\toptions?: JwtOptions,\n): Promise<(T & Required<Pick<JWTPayload, \"sub\" | \"aud\">>) | null> {\n\tconst ctx = await getCurrentAuthContext();\n\ttry {\n\t\tconst parts = token.split(\".\");\n\t\tif (parts.length !== 3) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst headerStr = new TextDecoder().decode(base64.decode(parts[0]!));\n\t\tconst header = JSON.parse(headerStr);\n\t\tconst kid = header.kid;\n\n\t\tif (!kid) {\n\t\t\tctx.context.logger.debug(\"JWT missing kid in header\");\n\t\t\treturn null;\n\t\t}\n\n\t\t// Get all JWKS keys\n\t\tconst adapter = getJwksAdapter(ctx.context.adapter, options);\n\t\tconst keys = await adapter.getAllKeys(ctx as GenericEndpointContext);\n\n\t\tif (!keys || keys.length === 0) {\n\t\t\tctx.context.logger.debug(\"No JWKS keys available\");\n\t\t\treturn null;\n\t\t}\n\n\t\tconst key = keys.find((k) => k.id === kid);\n\t\tif (!key) {\n\t\t\tctx.context.logger.debug(`No JWKS key found for kid: ${kid}`);\n\t\t\treturn null;\n\t\t}\n\n\t\tconst publicKey = JSON.parse(key.publicKey);\n\t\tconst alg = key.alg ?? options?.jwks?.keyPairConfig?.alg ?? \"EdDSA\";\n\t\tconst cryptoKey = await importJWK(publicKey, alg);\n\n\t\tconst { payload } = await jwtVerify(token, cryptoKey, {\n\t\t\tissuer: options?.jwt?.issuer ?? ctx.context.options.baseURL,\n\t\t\taudience: options?.jwt?.audience ?? ctx.context.options.baseURL,\n\t\t});\n\n\t\tif (!payload.sub || !payload.aud) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn payload as T & Required<Pick<JWTPayload, \"sub\" | \"aud\">>;\n\t} catch (error) {\n\t\tctx.context.logger.debug(\"JWT verification failed\", error);\n\t\treturn null;\n\t}\n}\n"],"mappings":";;;;;;;;;;AAYA,eAAsB,UACrB,OACA,SACkE;CAClE,MAAM,MAAM,MAAM,uBAAuB;AACzC,KAAI;EACH,MAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,MAAI,MAAM,WAAW,EACpB,QAAO;EAGR,MAAM,YAAY,IAAI,aAAa,CAAC,OAAO,OAAO,OAAO,MAAM,GAAI,CAAC;EAEpE,MAAM,MADS,KAAK,MAAM,UAAU,CACjB;AAEnB,MAAI,CAAC,KAAK;AACT,OAAI,QAAQ,OAAO,MAAM,4BAA4B;AACrD,UAAO;;EAKR,MAAM,OAAO,MADG,eAAe,IAAI,QAAQ,SAAS,QAAQ,CACjC,WAAW,IAA8B;AAEpE,MAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAC/B,OAAI,QAAQ,OAAO,MAAM,yBAAyB;AAClD,UAAO;;EAGR,MAAM,MAAM,KAAK,MAAM,MAAM,EAAE,OAAO,IAAI;AAC1C,MAAI,CAAC,KAAK;AACT,OAAI,QAAQ,OAAO,MAAM,8BAA8B,MAAM;AAC7D,UAAO;;EAOR,MAAM,EAAE,YAAY,MAAM,UAAU,OAFlB,MAAM,UAFN,KAAK,MAAM,IAAI,UAAU,EAC/B,IAAI,OAAO,SAAS,MAAM,eAAe,OAAO,QACX,EAEK;GACrD,QAAQ,SAAS,KAAK,UAAU,IAAI,QAAQ,QAAQ;GACpD,UAAU,SAAS,KAAK,YAAY,IAAI,QAAQ,QAAQ;GACxD,CAAC;AAEF,MAAI,CAAC,QAAQ,OAAO,CAAC,QAAQ,IAC5B,QAAO;AAGR,SAAO;UACC,OAAO;AACf,MAAI,QAAQ,OAAO,MAAM,2BAA2B,MAAM;AAC1D,SAAO"}
@@ -0,0 +1,18 @@
1
+ //#region src/plugins/last-login-method/client.d.ts
2
+ /**
3
+ * Configuration for the client-side last login method plugin
4
+ */
5
+ interface LastLoginMethodClientConfig {
6
+ /**
7
+ * Name of the cookie to read the last login method from
8
+ * @default "better-auth.last_used_login_method"
9
+ */
10
+ cookieName?: string | undefined;
11
+ }
12
+ /**
13
+ * Client-side plugin to retrieve the last used login method
14
+ */
15
+ declare const lastLoginMethodClient: (config?: LastLoginMethodClientConfig) => BetterAuthClientPlugin;
16
+ //#endregion
17
+ export { LastLoginMethodClientConfig, lastLoginMethodClient };
18
+ //# sourceMappingURL=client.d.mts.map
@@ -0,0 +1,32 @@
1
+ //#region src/plugins/last-login-method/client.ts
2
+ function getCookieValue(name) {
3
+ if (typeof document === "undefined") return null;
4
+ const cookie = document.cookie.split("; ").find((row) => row.startsWith(`${name}=`));
5
+ return cookie ? cookie.split("=")[1] : null;
6
+ }
7
+ /**
8
+ * Client-side plugin to retrieve the last used login method
9
+ */
10
+ const lastLoginMethodClient = (config = {}) => {
11
+ const cookieName = config.cookieName || "better-auth.last_used_login_method";
12
+ return {
13
+ id: "last-login-method-client",
14
+ getActions() {
15
+ return {
16
+ getLastUsedLoginMethod: () => {
17
+ return getCookieValue(cookieName);
18
+ },
19
+ clearLastUsedLoginMethod: () => {
20
+ if (typeof document !== "undefined") document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
21
+ },
22
+ isLastUsedLoginMethod: (method) => {
23
+ return getCookieValue(cookieName) === method;
24
+ }
25
+ };
26
+ }
27
+ };
28
+ };
29
+
30
+ //#endregion
31
+ export { lastLoginMethodClient };
32
+ //# sourceMappingURL=client.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.mjs","names":[],"sources":["../../../src/plugins/last-login-method/client.ts"],"sourcesContent":["import type { BetterAuthClientPlugin } from \"@better-auth/core\";\n\n/**\n * Configuration for the client-side last login method plugin\n */\nexport interface LastLoginMethodClientConfig {\n\t/**\n\t * Name of the cookie to read the last login method from\n\t * @default \"better-auth.last_used_login_method\"\n\t */\n\tcookieName?: string | undefined;\n}\n\nfunction getCookieValue(name: string): string | null {\n\tif (typeof document === \"undefined\") {\n\t\treturn null;\n\t}\n\n\tconst cookie = document.cookie\n\t\t.split(\"; \")\n\t\t.find((row) => row.startsWith(`${name}=`));\n\n\treturn cookie ? cookie.split(\"=\")[1]! : null;\n}\n\n/**\n * Client-side plugin to retrieve the last used login method\n */\nexport const lastLoginMethodClient = (\n\tconfig: LastLoginMethodClientConfig = {},\n) => {\n\tconst cookieName = config.cookieName || \"better-auth.last_used_login_method\";\n\n\treturn {\n\t\tid: \"last-login-method-client\",\n\t\tgetActions() {\n\t\t\treturn {\n\t\t\t\t/**\n\t\t\t\t * Get the last used login method from cookies\n\t\t\t\t * @returns The last used login method or null if not found\n\t\t\t\t */\n\t\t\t\tgetLastUsedLoginMethod: (): string | null => {\n\t\t\t\t\treturn getCookieValue(cookieName);\n\t\t\t\t},\n\t\t\t\t/**\n\t\t\t\t * Clear the last used login method cookie\n\t\t\t\t * This sets the cookie with an expiration date in the past\n\t\t\t\t */\n\t\t\t\tclearLastUsedLoginMethod: (): void => {\n\t\t\t\t\tif (typeof document !== \"undefined\") {\n\t\t\t\t\t\tdocument.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t/**\n\t\t\t\t * Check if a specific login method was the last used\n\t\t\t\t * @param method The method to check\n\t\t\t\t * @returns True if the method was the last used, false otherwise\n\t\t\t\t */\n\t\t\t\tisLastUsedLoginMethod: (method: string): boolean => {\n\t\t\t\t\tconst lastMethod = getCookieValue(cookieName);\n\t\t\t\t\treturn lastMethod === method;\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t} satisfies BetterAuthClientPlugin;\n};\n"],"mappings":";AAaA,SAAS,eAAe,MAA6B;AACpD,KAAI,OAAO,aAAa,YACvB,QAAO;CAGR,MAAM,SAAS,SAAS,OACtB,MAAM,KAAK,CACX,MAAM,QAAQ,IAAI,WAAW,GAAG,KAAK,GAAG,CAAC;AAE3C,QAAO,SAAS,OAAO,MAAM,IAAI,CAAC,KAAM;;;;;AAMzC,MAAa,yBACZ,SAAsC,EAAE,KACpC;CACJ,MAAM,aAAa,OAAO,cAAc;AAExC,QAAO;EACN,IAAI;EACJ,aAAa;AACZ,UAAO;IAKN,8BAA6C;AAC5C,YAAO,eAAe,WAAW;;IAMlC,gCAAsC;AACrC,SAAI,OAAO,aAAa,YACvB,UAAS,SAAS,GAAG,WAAW;;IAQlC,wBAAwB,WAA4B;AAEnD,YADmB,eAAe,WAAW,KACvB;;IAEvB;;EAEF"}
@@ -0,0 +1,52 @@
1
+ import { GenericEndpointContext } from "@better-auth/core";
2
+
3
+ //#region src/plugins/last-login-method/index.d.ts
4
+ declare module "@better-auth/core" {
5
+ interface BetterAuthPluginRegistry<AuthOptions, Options> {
6
+ "last-login-method": {
7
+ creator: typeof lastLoginMethod;
8
+ };
9
+ }
10
+ }
11
+ /**
12
+ * Configuration for tracking different authentication methods
13
+ */
14
+ interface LastLoginMethodOptions {
15
+ /**
16
+ * Name of the cookie to store the last login method
17
+ * @default "better-auth.last_used_login_method"
18
+ */
19
+ cookieName?: string | undefined;
20
+ /**
21
+ * Cookie expiration time in seconds
22
+ * @default 2592000 (30 days)
23
+ */
24
+ maxAge?: number | undefined;
25
+ /**
26
+ * Custom method to resolve the last login method
27
+ * @param ctx - The context from the hook
28
+ * @returns The last login method
29
+ */
30
+ customResolveMethod?: ((ctx: GenericEndpointContext) => string | null) | undefined;
31
+ /**
32
+ * Store the last login method in the database. This will create a new field in the user table.
33
+ * @default false
34
+ */
35
+ storeInDatabase?: boolean | undefined;
36
+ /**
37
+ * Custom schema for the plugin
38
+ * @default undefined
39
+ */
40
+ schema?: {
41
+ user?: {
42
+ lastLoginMethod?: string;
43
+ };
44
+ } | undefined;
45
+ }
46
+ /**
47
+ * Plugin to track the last used login method
48
+ */
49
+ declare const lastLoginMethod: <O extends LastLoginMethodOptions>(userConfig?: O | undefined) => BetterAuthPlugin;
50
+ //#endregion
51
+ export { LastLoginMethodOptions, lastLoginMethod };
52
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1,77 @@
1
+ import { createAuthMiddleware } from "@better-auth/core/api";
2
+
3
+ //#region src/plugins/last-login-method/index.ts
4
+ /**
5
+ * Plugin to track the last used login method
6
+ */
7
+ const lastLoginMethod = (userConfig) => {
8
+ const defaultResolveMethod = (ctx) => {
9
+ if (ctx.path.startsWith("/callback/") || ctx.path.startsWith("/oauth2/callback/")) return ctx.params?.id || ctx.params?.providerId || ctx.path.split("/").pop();
10
+ if (ctx.path === "/sign-in/email" || ctx.path === "/sign-up/email") return "email";
11
+ if (ctx.path.includes("siwe")) return "siwe";
12
+ if (ctx.path.includes("/passkey/verify-authentication")) return "passkey";
13
+ return null;
14
+ };
15
+ const config = {
16
+ cookieName: "better-auth.last_used_login_method",
17
+ maxAge: 3600 * 24 * 30,
18
+ ...userConfig
19
+ };
20
+ return {
21
+ id: "last-login-method",
22
+ init(ctx) {
23
+ return { options: { databaseHooks: {
24
+ user: { create: { async before(user, context) {
25
+ if (!config.storeInDatabase) return;
26
+ if (!context) return;
27
+ const lastUsedLoginMethod = config.customResolveMethod?.(context) ?? defaultResolveMethod(context);
28
+ if (lastUsedLoginMethod) return { data: {
29
+ ...user,
30
+ lastLoginMethod: lastUsedLoginMethod
31
+ } };
32
+ } } },
33
+ session: { create: { async after(session, context) {
34
+ if (!config.storeInDatabase) return;
35
+ if (!context) return;
36
+ const lastUsedLoginMethod = config.customResolveMethod?.(context) ?? defaultResolveMethod(context);
37
+ if (lastUsedLoginMethod && session?.userId) try {
38
+ await ctx.internalAdapter.updateUser(session.userId, { lastLoginMethod: lastUsedLoginMethod });
39
+ } catch (error) {
40
+ ctx.logger.error("Failed to update lastLoginMethod", error);
41
+ }
42
+ } } }
43
+ } } };
44
+ },
45
+ hooks: { after: [{
46
+ matcher() {
47
+ return true;
48
+ },
49
+ handler: createAuthMiddleware(async (ctx) => {
50
+ const lastUsedLoginMethod = config.customResolveMethod?.(ctx) ?? defaultResolveMethod(ctx);
51
+ if (lastUsedLoginMethod) {
52
+ const setCookie = ctx.context.responseHeaders?.get("set-cookie");
53
+ const sessionTokenName = ctx.context.authCookies.sessionToken.name;
54
+ if (setCookie && setCookie.includes(sessionTokenName)) {
55
+ const cookieAttributes = {
56
+ ...ctx.context.authCookies.sessionToken.attributes,
57
+ maxAge: config.maxAge,
58
+ httpOnly: false
59
+ };
60
+ ctx.setCookie(config.cookieName, lastUsedLoginMethod, cookieAttributes);
61
+ }
62
+ }
63
+ })
64
+ }] },
65
+ schema: config.storeInDatabase ? { user: { fields: { lastLoginMethod: {
66
+ type: "string",
67
+ input: false,
68
+ required: false,
69
+ fieldName: config.schema?.user?.lastLoginMethod || "lastLoginMethod"
70
+ } } } } : void 0,
71
+ options: userConfig
72
+ };
73
+ };
74
+
75
+ //#endregion
76
+ export { lastLoginMethod };
77
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/last-login-method/index.ts"],"sourcesContent":["import type {\n\tBetterAuthPlugin,\n\tGenericEndpointContext,\n} from \"@better-auth/core\";\nimport { createAuthMiddleware } from \"@better-auth/core/api\";\n\ndeclare module \"@better-auth/core\" {\n\tinterface BetterAuthPluginRegistry<AuthOptions, Options> {\n\t\t\"last-login-method\": {\n\t\t\tcreator: typeof lastLoginMethod;\n\t\t};\n\t}\n}\n/**\n * Configuration for tracking different authentication methods\n */\nexport interface LastLoginMethodOptions {\n\t/**\n\t * Name of the cookie to store the last login method\n\t * @default \"better-auth.last_used_login_method\"\n\t */\n\tcookieName?: string | undefined;\n\t/**\n\t * Cookie expiration time in seconds\n\t * @default 2592000 (30 days)\n\t */\n\tmaxAge?: number | undefined;\n\t/**\n\t * Custom method to resolve the last login method\n\t * @param ctx - The context from the hook\n\t * @returns The last login method\n\t */\n\tcustomResolveMethod?:\n\t\t| ((ctx: GenericEndpointContext) => string | null)\n\t\t| undefined;\n\t/**\n\t * Store the last login method in the database. This will create a new field in the user table.\n\t * @default false\n\t */\n\tstoreInDatabase?: boolean | undefined;\n\t/**\n\t * Custom schema for the plugin\n\t * @default undefined\n\t */\n\tschema?:\n\t\t| {\n\t\t\t\tuser?: {\n\t\t\t\t\tlastLoginMethod?: string;\n\t\t\t\t};\n\t\t }\n\t\t| undefined;\n}\n\n/**\n * Plugin to track the last used login method\n */\nexport const lastLoginMethod = <O extends LastLoginMethodOptions>(\n\tuserConfig?: O | undefined,\n) => {\n\tconst defaultResolveMethod = (ctx: GenericEndpointContext) => {\n\t\t// Check for OAuth callbacks (/callback/:id or /oauth2/callback/:providerId)\n\t\tif (\n\t\t\tctx.path.startsWith(\"/callback/\") ||\n\t\t\tctx.path.startsWith(\"/oauth2/callback/\")\n\t\t) {\n\t\t\treturn (\n\t\t\t\tctx.params?.id || ctx.params?.providerId || ctx.path.split(\"/\").pop()\n\t\t\t);\n\t\t}\n\t\t// Check for email sign-in/sign-up\n\t\tif (ctx.path === \"/sign-in/email\" || ctx.path === \"/sign-up/email\") {\n\t\t\treturn \"email\";\n\t\t}\n\t\tif (ctx.path.includes(\"siwe\")) return \"siwe\";\n\t\tif (ctx.path.includes(\"/passkey/verify-authentication\")) return \"passkey\";\n\t\treturn null;\n\t};\n\n\tconst config = {\n\t\tcookieName: \"better-auth.last_used_login_method\",\n\t\tmaxAge: 60 * 60 * 24 * 30,\n\t\t...userConfig,\n\t} satisfies LastLoginMethodOptions;\n\n\treturn {\n\t\tid: \"last-login-method\",\n\t\tinit(ctx) {\n\t\t\treturn {\n\t\t\t\toptions: {\n\t\t\t\t\tdatabaseHooks: {\n\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\t\tasync before(user, context) {\n\t\t\t\t\t\t\t\t\tif (!config.storeInDatabase) return;\n\t\t\t\t\t\t\t\t\tif (!context) return;\n\t\t\t\t\t\t\t\t\tconst lastUsedLoginMethod =\n\t\t\t\t\t\t\t\t\t\tconfig.customResolveMethod?.(context) ??\n\t\t\t\t\t\t\t\t\t\tdefaultResolveMethod(context);\n\t\t\t\t\t\t\t\t\tif (lastUsedLoginMethod) {\n\t\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\t\t\t...user,\n\t\t\t\t\t\t\t\t\t\t\t\tlastLoginMethod: lastUsedLoginMethod,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\t\tasync after(session, context) {\n\t\t\t\t\t\t\t\t\tif (!config.storeInDatabase) return;\n\t\t\t\t\t\t\t\t\tif (!context) return;\n\t\t\t\t\t\t\t\t\tconst lastUsedLoginMethod =\n\t\t\t\t\t\t\t\t\t\tconfig.customResolveMethod?.(context) ??\n\t\t\t\t\t\t\t\t\t\tdefaultResolveMethod(context);\n\t\t\t\t\t\t\t\t\tif (lastUsedLoginMethod && session?.userId) {\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tawait ctx.internalAdapter.updateUser(session.userId, {\n\t\t\t\t\t\t\t\t\t\t\t\tlastLoginMethod: lastUsedLoginMethod,\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t\t\t\tctx.logger.error(\n\t\t\t\t\t\t\t\t\t\t\t\t\"Failed to update lastLoginMethod\",\n\t\t\t\t\t\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\thooks: {\n\t\t\tafter: [\n\t\t\t\t{\n\t\t\t\t\tmatcher() {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t},\n\t\t\t\t\thandler: createAuthMiddleware(async (ctx) => {\n\t\t\t\t\t\tconst lastUsedLoginMethod =\n\t\t\t\t\t\t\tconfig.customResolveMethod?.(ctx) ?? defaultResolveMethod(ctx);\n\t\t\t\t\t\tif (lastUsedLoginMethod) {\n\t\t\t\t\t\t\tconst setCookie = ctx.context.responseHeaders?.get(\"set-cookie\");\n\t\t\t\t\t\t\tconst sessionTokenName =\n\t\t\t\t\t\t\t\tctx.context.authCookies.sessionToken.name;\n\t\t\t\t\t\t\tconst hasSessionToken =\n\t\t\t\t\t\t\t\tsetCookie && setCookie.includes(sessionTokenName);\n\t\t\t\t\t\t\tif (hasSessionToken) {\n\t\t\t\t\t\t\t\t// Inherit cookie attributes from Better Auth's centralized cookie system\n\t\t\t\t\t\t\t\t// This ensures consistency with cross-origin, cross-subdomain, and security settings\n\t\t\t\t\t\t\t\tconst cookieAttributes = {\n\t\t\t\t\t\t\t\t\t...ctx.context.authCookies.sessionToken.attributes,\n\t\t\t\t\t\t\t\t\tmaxAge: config.maxAge,\n\t\t\t\t\t\t\t\t\thttpOnly: false, // Override: plugin cookies are not httpOnly\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\tctx.setCookie(\n\t\t\t\t\t\t\t\t\tconfig.cookieName,\n\t\t\t\t\t\t\t\t\tlastUsedLoginMethod,\n\t\t\t\t\t\t\t\t\tcookieAttributes,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\tschema: (config.storeInDatabase\n\t\t\t? {\n\t\t\t\t\tuser: {\n\t\t\t\t\t\tfields: {\n\t\t\t\t\t\t\tlastLoginMethod: {\n\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\tinput: false,\n\t\t\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\t\t\tfieldName:\n\t\t\t\t\t\t\t\t\tconfig.schema?.user?.lastLoginMethod || \"lastLoginMethod\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: undefined) as O[\"storeInDatabase\"] extends true\n\t\t\t? {\n\t\t\t\t\tuser: {\n\t\t\t\t\t\tfields: {\n\t\t\t\t\t\t\tlastLoginMethod: {\n\t\t\t\t\t\t\t\ttype: \"string\";\n\t\t\t\t\t\t\t\trequired: false;\n\t\t\t\t\t\t\t\tinput: false;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t: undefined,\n\t\toptions: userConfig as NoInfer<O>,\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":";;;;;;AAwDA,MAAa,mBACZ,eACI;CACJ,MAAM,wBAAwB,QAAgC;AAE7D,MACC,IAAI,KAAK,WAAW,aAAa,IACjC,IAAI,KAAK,WAAW,oBAAoB,CAExC,QACC,IAAI,QAAQ,MAAM,IAAI,QAAQ,cAAc,IAAI,KAAK,MAAM,IAAI,CAAC,KAAK;AAIvE,MAAI,IAAI,SAAS,oBAAoB,IAAI,SAAS,iBACjD,QAAO;AAER,MAAI,IAAI,KAAK,SAAS,OAAO,CAAE,QAAO;AACtC,MAAI,IAAI,KAAK,SAAS,iCAAiC,CAAE,QAAO;AAChE,SAAO;;CAGR,MAAM,SAAS;EACd,YAAY;EACZ,QAAQ,OAAU,KAAK;EACvB,GAAG;EACH;AAED,QAAO;EACN,IAAI;EACJ,KAAK,KAAK;AACT,UAAO,EACN,SAAS,EACR,eAAe;IACd,MAAM,EACL,QAAQ,EACP,MAAM,OAAO,MAAM,SAAS;AAC3B,SAAI,CAAC,OAAO,gBAAiB;AAC7B,SAAI,CAAC,QAAS;KACd,MAAM,sBACL,OAAO,sBAAsB,QAAQ,IACrC,qBAAqB,QAAQ;AAC9B,SAAI,oBACH,QAAO,EACN,MAAM;MACL,GAAG;MACH,iBAAiB;MACjB,EACD;OAGH,EACD;IACD,SAAS,EACR,QAAQ,EACP,MAAM,MAAM,SAAS,SAAS;AAC7B,SAAI,CAAC,OAAO,gBAAiB;AAC7B,SAAI,CAAC,QAAS;KACd,MAAM,sBACL,OAAO,sBAAsB,QAAQ,IACrC,qBAAqB,QAAQ;AAC9B,SAAI,uBAAuB,SAAS,OACnC,KAAI;AACH,YAAM,IAAI,gBAAgB,WAAW,QAAQ,QAAQ,EACpD,iBAAiB,qBACjB,CAAC;cACM,OAAO;AACf,UAAI,OAAO,MACV,oCACA,MACA;;OAIJ,EACD;IACD,EACD,EACD;;EAEF,OAAO,EACN,OAAO,CACN;GACC,UAAU;AACT,WAAO;;GAER,SAAS,qBAAqB,OAAO,QAAQ;IAC5C,MAAM,sBACL,OAAO,sBAAsB,IAAI,IAAI,qBAAqB,IAAI;AAC/D,QAAI,qBAAqB;KACxB,MAAM,YAAY,IAAI,QAAQ,iBAAiB,IAAI,aAAa;KAChE,MAAM,mBACL,IAAI,QAAQ,YAAY,aAAa;AAGtC,SADC,aAAa,UAAU,SAAS,iBAAiB,EAC7B;MAGpB,MAAM,mBAAmB;OACxB,GAAG,IAAI,QAAQ,YAAY,aAAa;OACxC,QAAQ,OAAO;OACf,UAAU;OACV;AAED,UAAI,UACH,OAAO,YACP,qBACA,iBACA;;;KAGF;GACF,CACD,EACD;EACD,QAAS,OAAO,kBACb,EACA,MAAM,EACL,QAAQ,EACP,iBAAiB;GAChB,MAAM;GACN,OAAO;GACP,UAAU;GACV,WACC,OAAO,QAAQ,MAAM,mBAAmB;GACzC,EACD,EACD,EACD,GACA;EAaH,SAAS;EACT"}
@@ -0,0 +1,5 @@
1
+ //#region src/plugins/magic-link/client.d.ts
2
+ declare const magicLinkClient: () => BetterAuthClientPlugin;
3
+ //#endregion
4
+ export { magicLinkClient };
5
+ //# sourceMappingURL=client.d.mts.map
@@ -0,0 +1,11 @@
1
+ //#region src/plugins/magic-link/client.ts
2
+ const magicLinkClient = () => {
3
+ return {
4
+ id: "magic-link",
5
+ $InferServerPlugin: {}
6
+ };
7
+ };
8
+
9
+ //#endregion
10
+ export { magicLinkClient };
11
+ //# sourceMappingURL=client.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.mjs","names":[],"sources":["../../../src/plugins/magic-link/client.ts"],"sourcesContent":["import type { BetterAuthClientPlugin } from \"@better-auth/core\";\nimport type { magicLink } from \".\";\n\nexport const magicLinkClient = () => {\n\treturn {\n\t\tid: \"magic-link\",\n\t\t$InferServerPlugin: {} as ReturnType<typeof magicLink>,\n\t} satisfies BetterAuthClientPlugin;\n};\n"],"mappings":";AAGA,MAAa,wBAAwB;AACpC,QAAO;EACN,IAAI;EACJ,oBAAoB,EAAE;EACtB"}
@@ -0,0 +1,61 @@
1
+ import { Awaitable, GenericEndpointContext } from "@better-auth/core";
2
+
3
+ //#region src/plugins/magic-link/index.d.ts
4
+ declare module "@better-auth/core" {
5
+ interface BetterAuthPluginRegistry<AuthOptions, Options> {
6
+ "magic-link": {
7
+ creator: typeof magicLink;
8
+ };
9
+ }
10
+ }
11
+ interface MagicLinkOptions {
12
+ /**
13
+ * Time in seconds until the magic link expires.
14
+ * @default (60 * 5) // 5 minutes
15
+ */
16
+ expiresIn?: number | undefined;
17
+ /**
18
+ * Send magic link implementation.
19
+ */
20
+ sendMagicLink: (data: {
21
+ email: string;
22
+ url: string;
23
+ token: string;
24
+ }, ctx?: GenericEndpointContext | undefined) => Awaitable<void>;
25
+ /**
26
+ * Disable sign up if user is not found.
27
+ *
28
+ * @default false
29
+ */
30
+ disableSignUp?: boolean | undefined;
31
+ /**
32
+ * Rate limit configuration.
33
+ *
34
+ * @default {
35
+ * window: 60,
36
+ * max: 5,
37
+ * }
38
+ */
39
+ rateLimit?: {
40
+ window: number;
41
+ max: number;
42
+ } | undefined;
43
+ /**
44
+ * Custom function to generate a token
45
+ */
46
+ generateToken?: ((email: string) => Awaitable<string>) | undefined;
47
+ /**
48
+ * This option allows you to configure how the token is stored in your database.
49
+ * Note: This will not affect the token that's sent, it will only affect the token stored in your database.
50
+ *
51
+ * @default "plain"
52
+ */
53
+ storeToken?: ("plain" | "hashed" | {
54
+ type: "custom-hasher";
55
+ hash: (token: string) => Promise<string>;
56
+ }) | undefined;
57
+ }
58
+ declare const magicLink: (options: MagicLinkOptions) => BetterAuthPlugin;
59
+ //#endregion
60
+ export { MagicLinkOptions, magicLink };
61
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1,167 @@
1
+ import { originCheck } from "../../api/middlewares/origin-check.mjs";
2
+ import { generateRandomString } from "../../crypto/random.mjs";
3
+ import "../../crypto/index.mjs";
4
+ import { parseUserOutput } from "../../db/schema.mjs";
5
+ import { setSessionCookie } from "../../cookies/index.mjs";
6
+ import "../../api/index.mjs";
7
+ import { defaultKeyHasher } from "./utils.mjs";
8
+ import { createAuthEndpoint } from "@better-auth/core/api";
9
+ import * as z from "zod";
10
+
11
+ //#region src/plugins/magic-link/index.ts
12
+ const signInMagicLinkBodySchema = z.object({
13
+ email: z.email().meta({ description: "Email address to send the magic link" }),
14
+ name: z.string().meta({ description: "User display name. Only used if the user is registering for the first time. Eg: \"my-name\"" }).optional(),
15
+ callbackURL: z.string().meta({ description: "URL to redirect after magic link verification" }).optional(),
16
+ newUserCallbackURL: z.string().meta({ description: "URL to redirect after new user signup. Only used if the user is registering for the first time." }).optional(),
17
+ errorCallbackURL: z.string().meta({ description: "URL to redirect after error." }).optional()
18
+ });
19
+ const magicLinkVerifyQuerySchema = z.object({
20
+ token: z.string().meta({ description: "Verification token" }),
21
+ callbackURL: z.string().meta({ description: "URL to redirect after magic link verification, if not provided the user will be redirected to the root URL. Eg: \"/dashboard\"" }).optional(),
22
+ errorCallbackURL: z.string().meta({ description: "URL to redirect after error." }).optional(),
23
+ newUserCallbackURL: z.string().meta({ description: "URL to redirect after new user signup. Only used if the user is registering for the first time." }).optional()
24
+ });
25
+ const magicLink = (options) => {
26
+ const opts = {
27
+ storeToken: "plain",
28
+ ...options
29
+ };
30
+ async function storeToken(ctx, token) {
31
+ if (opts.storeToken === "hashed") return await defaultKeyHasher(token);
32
+ if (typeof opts.storeToken === "object" && "type" in opts.storeToken && opts.storeToken.type === "custom-hasher") return await opts.storeToken.hash(token);
33
+ return token;
34
+ }
35
+ return {
36
+ id: "magic-link",
37
+ endpoints: {
38
+ signInMagicLink: createAuthEndpoint("/sign-in/magic-link", {
39
+ method: "POST",
40
+ requireHeaders: true,
41
+ body: signInMagicLinkBodySchema,
42
+ metadata: { openapi: {
43
+ operationId: "signInWithMagicLink",
44
+ description: "Sign in with magic link",
45
+ responses: { 200: {
46
+ description: "Success",
47
+ content: { "application/json": { schema: {
48
+ type: "object",
49
+ properties: { status: { type: "boolean" } }
50
+ } } }
51
+ } }
52
+ } }
53
+ }, async (ctx) => {
54
+ const { email } = ctx.body;
55
+ const verificationToken = opts?.generateToken ? await opts.generateToken(email) : generateRandomString(32, "a-z", "A-Z");
56
+ const storedToken = await storeToken(ctx, verificationToken);
57
+ await ctx.context.internalAdapter.createVerificationValue({
58
+ identifier: storedToken,
59
+ value: JSON.stringify({
60
+ email,
61
+ name: ctx.body.name
62
+ }),
63
+ expiresAt: new Date(Date.now() + (opts.expiresIn || 300) * 1e3)
64
+ });
65
+ const realBaseURL = new URL(ctx.context.baseURL);
66
+ const pathname = realBaseURL.pathname === "/" ? "" : realBaseURL.pathname;
67
+ const basePath = pathname ? "" : ctx.context.options.basePath || "";
68
+ const url = new URL(`${pathname}${basePath}/magic-link/verify`, realBaseURL.origin);
69
+ url.searchParams.set("token", verificationToken);
70
+ url.searchParams.set("callbackURL", ctx.body.callbackURL || "/");
71
+ if (ctx.body.newUserCallbackURL) url.searchParams.set("newUserCallbackURL", ctx.body.newUserCallbackURL);
72
+ if (ctx.body.errorCallbackURL) url.searchParams.set("errorCallbackURL", ctx.body.errorCallbackURL);
73
+ await options.sendMagicLink({
74
+ email,
75
+ url: url.toString(),
76
+ token: verificationToken
77
+ }, ctx);
78
+ return ctx.json({ status: true });
79
+ }),
80
+ magicLinkVerify: createAuthEndpoint("/magic-link/verify", {
81
+ method: "GET",
82
+ query: magicLinkVerifyQuerySchema,
83
+ use: [
84
+ originCheck((ctx) => {
85
+ return ctx.query.callbackURL ? decodeURIComponent(ctx.query.callbackURL) : "/";
86
+ }),
87
+ originCheck((ctx) => {
88
+ return ctx.query.newUserCallbackURL ? decodeURIComponent(ctx.query.newUserCallbackURL) : "/";
89
+ }),
90
+ originCheck((ctx) => {
91
+ return ctx.query.errorCallbackURL ? decodeURIComponent(ctx.query.errorCallbackURL) : "/";
92
+ })
93
+ ],
94
+ requireHeaders: true,
95
+ metadata: { openapi: {
96
+ operationId: "verifyMagicLink",
97
+ description: "Verify magic link",
98
+ responses: { 200: {
99
+ description: "Success",
100
+ content: { "application/json": { schema: {
101
+ type: "object",
102
+ properties: {
103
+ session: { $ref: "#/components/schemas/Session" },
104
+ user: { $ref: "#/components/schemas/User" }
105
+ }
106
+ } } }
107
+ } }
108
+ } }
109
+ }, async (ctx) => {
110
+ const token = ctx.query.token;
111
+ const callbackURL = new URL(ctx.query.callbackURL ? decodeURIComponent(ctx.query.callbackURL) : "/", ctx.context.baseURL).toString();
112
+ const errorCallbackURL = new URL(ctx.query.errorCallbackURL ? decodeURIComponent(ctx.query.errorCallbackURL) : callbackURL, ctx.context.baseURL);
113
+ function redirectWithError(error) {
114
+ errorCallbackURL.searchParams.set("error", error);
115
+ throw ctx.redirect(errorCallbackURL.toString());
116
+ }
117
+ const newUserCallbackURL = new URL(ctx.query.newUserCallbackURL ? decodeURIComponent(ctx.query.newUserCallbackURL) : callbackURL, ctx.context.baseURL).toString();
118
+ const storedToken = await storeToken(ctx, token);
119
+ const tokenValue = await ctx.context.internalAdapter.findVerificationValue(storedToken);
120
+ if (!tokenValue) redirectWithError("INVALID_TOKEN");
121
+ if (tokenValue.expiresAt < /* @__PURE__ */ new Date()) {
122
+ await ctx.context.internalAdapter.deleteVerificationValue(tokenValue.id);
123
+ redirectWithError("EXPIRED_TOKEN");
124
+ }
125
+ await ctx.context.internalAdapter.deleteVerificationValue(tokenValue.id);
126
+ const { email, name } = JSON.parse(tokenValue.value);
127
+ let isNewUser = false;
128
+ let user = await ctx.context.internalAdapter.findUserByEmail(email).then((res) => res?.user);
129
+ if (!user) if (!opts.disableSignUp) {
130
+ const newUser = await ctx.context.internalAdapter.createUser({
131
+ email,
132
+ emailVerified: true,
133
+ name: name || ""
134
+ });
135
+ isNewUser = true;
136
+ user = newUser;
137
+ if (!user) redirectWithError("failed_to_create_user");
138
+ } else redirectWithError("new_user_signup_disabled");
139
+ if (!user.emailVerified) user = await ctx.context.internalAdapter.updateUser(user.id, { emailVerified: true });
140
+ const session = await ctx.context.internalAdapter.createSession(user.id);
141
+ if (!session) redirectWithError("failed_to_create_session");
142
+ await setSessionCookie(ctx, {
143
+ session,
144
+ user
145
+ });
146
+ if (!ctx.query.callbackURL) return ctx.json({
147
+ token: session.token,
148
+ user: parseUserOutput(ctx.context.options, user)
149
+ });
150
+ if (isNewUser) throw ctx.redirect(newUserCallbackURL);
151
+ throw ctx.redirect(callbackURL);
152
+ })
153
+ },
154
+ rateLimit: [{
155
+ pathMatcher(path) {
156
+ return path.startsWith("/sign-in/magic-link") || path.startsWith("/magic-link/verify");
157
+ },
158
+ window: opts.rateLimit?.window || 60,
159
+ max: opts.rateLimit?.max || 5
160
+ }],
161
+ options
162
+ };
163
+ };
164
+
165
+ //#endregion
166
+ export { magicLink };
167
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/magic-link/index.ts"],"sourcesContent":["import type {\n\tAwaitable,\n\tBetterAuthPlugin,\n\tGenericEndpointContext,\n} from \"@better-auth/core\";\nimport { createAuthEndpoint } from \"@better-auth/core/api\";\nimport * as z from \"zod\";\nimport { originCheck } from \"../../api\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { generateRandomString } from \"../../crypto\";\nimport { parseUserOutput } from \"../../db/schema\";\nimport { defaultKeyHasher } from \"./utils\";\n\ndeclare module \"@better-auth/core\" {\n\tinterface BetterAuthPluginRegistry<AuthOptions, Options> {\n\t\t\"magic-link\": {\n\t\t\tcreator: typeof magicLink;\n\t\t};\n\t}\n}\n\nexport interface MagicLinkOptions {\n\t/**\n\t * Time in seconds until the magic link expires.\n\t * @default (60 * 5) // 5 minutes\n\t */\n\texpiresIn?: number | undefined;\n\t/**\n\t * Send magic link implementation.\n\t */\n\tsendMagicLink: (\n\t\tdata: {\n\t\t\temail: string;\n\t\t\turl: string;\n\t\t\ttoken: string;\n\t\t},\n\t\tctx?: GenericEndpointContext | undefined,\n\t) => Awaitable<void>;\n\t/**\n\t * Disable sign up if user is not found.\n\t *\n\t * @default false\n\t */\n\tdisableSignUp?: boolean | undefined;\n\t/**\n\t * Rate limit configuration.\n\t *\n\t * @default {\n\t * window: 60,\n\t * max: 5,\n\t * }\n\t */\n\trateLimit?:\n\t\t| {\n\t\t\t\twindow: number;\n\t\t\t\tmax: number;\n\t\t }\n\t\t| undefined;\n\t/**\n\t * Custom function to generate a token\n\t */\n\tgenerateToken?: ((email: string) => Awaitable<string>) | undefined;\n\n\t/**\n\t * This option allows you to configure how the token is stored in your database.\n\t * Note: This will not affect the token that's sent, it will only affect the token stored in your database.\n\t *\n\t * @default \"plain\"\n\t */\n\tstoreToken?:\n\t\t| (\n\t\t\t\t| \"plain\"\n\t\t\t\t| \"hashed\"\n\t\t\t\t| { type: \"custom-hasher\"; hash: (token: string) => Promise<string> }\n\t\t )\n\t\t| undefined;\n}\n\nconst signInMagicLinkBodySchema = z.object({\n\temail: z.email().meta({\n\t\tdescription: \"Email address to send the magic link\",\n\t}),\n\tname: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'User display name. Only used if the user is registering for the first time. Eg: \"my-name\"',\n\t\t})\n\t\t.optional(),\n\tcallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"URL to redirect after magic link verification\",\n\t\t})\n\t\t.optional(),\n\tnewUserCallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"URL to redirect after new user signup. Only used if the user is registering for the first time.\",\n\t\t})\n\t\t.optional(),\n\terrorCallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"URL to redirect after error.\",\n\t\t})\n\t\t.optional(),\n});\nconst magicLinkVerifyQuerySchema = z.object({\n\ttoken: z.string().meta({\n\t\tdescription: \"Verification token\",\n\t}),\n\tcallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'URL to redirect after magic link verification, if not provided the user will be redirected to the root URL. Eg: \"/dashboard\"',\n\t\t})\n\t\t.optional(),\n\terrorCallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"URL to redirect after error.\",\n\t\t})\n\t\t.optional(),\n\tnewUserCallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"URL to redirect after new user signup. Only used if the user is registering for the first time.\",\n\t\t})\n\t\t.optional(),\n});\nexport const magicLink = (options: MagicLinkOptions) => {\n\tconst opts = {\n\t\tstoreToken: \"plain\",\n\t\t...options,\n\t} satisfies MagicLinkOptions;\n\n\tasync function storeToken(ctx: GenericEndpointContext, token: string) {\n\t\tif (opts.storeToken === \"hashed\") {\n\t\t\treturn await defaultKeyHasher(token);\n\t\t}\n\t\tif (\n\t\t\ttypeof opts.storeToken === \"object\" &&\n\t\t\t\"type\" in opts.storeToken &&\n\t\t\topts.storeToken.type === \"custom-hasher\"\n\t\t) {\n\t\t\treturn await opts.storeToken.hash(token);\n\t\t}\n\t\treturn token;\n\t}\n\n\treturn {\n\t\tid: \"magic-link\",\n\t\tendpoints: {\n\t\t\t/**\n\t\t\t * ### Endpoint\n\t\t\t *\n\t\t\t * POST `/sign-in/magic-link`\n\t\t\t *\n\t\t\t * ### API Methods\n\t\t\t *\n\t\t\t * **server:**\n\t\t\t * `auth.api.signInMagicLink`\n\t\t\t *\n\t\t\t * **client:**\n\t\t\t * `authClient.signIn.magicLink`\n\t\t\t *\n\t\t\t * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/sign-in#api-method-sign-in-magic-link)\n\t\t\t */\n\t\t\tsignInMagicLink: createAuthEndpoint(\n\t\t\t\t\"/sign-in/magic-link\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\trequireHeaders: true,\n\t\t\t\t\tbody: signInMagicLinkBodySchema,\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\topenapi: {\n\t\t\t\t\t\t\toperationId: \"signInWithMagicLink\",\n\t\t\t\t\t\t\tdescription: \"Sign in with magic link\",\n\t\t\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\t\t200: {\n\t\t\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst { email } = ctx.body;\n\n\t\t\t\t\tconst verificationToken = opts?.generateToken\n\t\t\t\t\t\t? await opts.generateToken(email)\n\t\t\t\t\t\t: generateRandomString(32, \"a-z\", \"A-Z\");\n\t\t\t\t\tconst storedToken = await storeToken(ctx, verificationToken);\n\t\t\t\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\t\t\t\tidentifier: storedToken,\n\t\t\t\t\t\tvalue: JSON.stringify({ email, name: ctx.body.name }),\n\t\t\t\t\t\texpiresAt: new Date(Date.now() + (opts.expiresIn || 60 * 5) * 1000),\n\t\t\t\t\t});\n\t\t\t\t\tconst realBaseURL = new URL(ctx.context.baseURL);\n\t\t\t\t\tconst pathname =\n\t\t\t\t\t\trealBaseURL.pathname === \"/\" ? \"\" : realBaseURL.pathname;\n\t\t\t\t\tconst basePath = pathname ? \"\" : ctx.context.options.basePath || \"\";\n\t\t\t\t\tconst url = new URL(\n\t\t\t\t\t\t`${pathname}${basePath}/magic-link/verify`,\n\t\t\t\t\t\trealBaseURL.origin,\n\t\t\t\t\t);\n\t\t\t\t\turl.searchParams.set(\"token\", verificationToken);\n\t\t\t\t\turl.searchParams.set(\"callbackURL\", ctx.body.callbackURL || \"/\");\n\t\t\t\t\tif (ctx.body.newUserCallbackURL) {\n\t\t\t\t\t\turl.searchParams.set(\n\t\t\t\t\t\t\t\"newUserCallbackURL\",\n\t\t\t\t\t\t\tctx.body.newUserCallbackURL,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (ctx.body.errorCallbackURL) {\n\t\t\t\t\t\turl.searchParams.set(\"errorCallbackURL\", ctx.body.errorCallbackURL);\n\t\t\t\t\t}\n\t\t\t\t\tawait options.sendMagicLink(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\temail,\n\t\t\t\t\t\t\turl: url.toString(),\n\t\t\t\t\t\t\ttoken: verificationToken,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tctx,\n\t\t\t\t\t);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tstatus: true,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t),\n\t\t\t/**\n\t\t\t * ### Endpoint\n\t\t\t *\n\t\t\t * GET `/magic-link/verify`\n\t\t\t *\n\t\t\t * ### API Methods\n\t\t\t *\n\t\t\t * **server:**\n\t\t\t * `auth.api.magicLinkVerify`\n\t\t\t *\n\t\t\t * **client:**\n\t\t\t * `authClient.magicLink.verify`\n\t\t\t *\n\t\t\t * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/magic-link#api-method-magic-link-verify)\n\t\t\t */\n\t\t\tmagicLinkVerify: createAuthEndpoint(\n\t\t\t\t\"/magic-link/verify\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tquery: magicLinkVerifyQuerySchema,\n\t\t\t\t\tuse: [\n\t\t\t\t\t\toriginCheck((ctx) => {\n\t\t\t\t\t\t\treturn ctx.query.callbackURL\n\t\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.callbackURL)\n\t\t\t\t\t\t\t\t: \"/\";\n\t\t\t\t\t\t}),\n\t\t\t\t\t\toriginCheck((ctx) => {\n\t\t\t\t\t\t\treturn ctx.query.newUserCallbackURL\n\t\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.newUserCallbackURL)\n\t\t\t\t\t\t\t\t: \"/\";\n\t\t\t\t\t\t}),\n\t\t\t\t\t\toriginCheck((ctx) => {\n\t\t\t\t\t\t\treturn ctx.query.errorCallbackURL\n\t\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.errorCallbackURL)\n\t\t\t\t\t\t\t\t: \"/\";\n\t\t\t\t\t\t}),\n\t\t\t\t\t],\n\t\t\t\t\trequireHeaders: true,\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\topenapi: {\n\t\t\t\t\t\t\toperationId: \"verifyMagicLink\",\n\t\t\t\t\t\t\tdescription: \"Verify magic link\",\n\t\t\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\t\t200: {\n\t\t\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/Session\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/User\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tasync (ctx) => {\n\t\t\t\t\tconst token = ctx.query.token;\n\t\t\t\t\t// If the first argument provides the origin, it will ignore the second argument of `new URL`.\n\t\t\t\t\t// new URL(\"http://localhost:3001/hello\", \"http://localhost:3000\").toString()\n\t\t\t\t\t// Returns http://localhost:3001/hello\n\t\t\t\t\tconst callbackURL = new URL(\n\t\t\t\t\t\tctx.query.callbackURL\n\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.callbackURL)\n\t\t\t\t\t\t\t: \"/\",\n\t\t\t\t\t\tctx.context.baseURL,\n\t\t\t\t\t).toString();\n\t\t\t\t\tconst errorCallbackURL = new URL(\n\t\t\t\t\t\tctx.query.errorCallbackURL\n\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.errorCallbackURL)\n\t\t\t\t\t\t\t: callbackURL,\n\t\t\t\t\t\tctx.context.baseURL,\n\t\t\t\t\t);\n\n\t\t\t\t\tfunction redirectWithError(error: string): never {\n\t\t\t\t\t\terrorCallbackURL.searchParams.set(\"error\", error);\n\t\t\t\t\t\tthrow ctx.redirect(errorCallbackURL.toString());\n\t\t\t\t\t}\n\n\t\t\t\t\tconst newUserCallbackURL = new URL(\n\t\t\t\t\t\tctx.query.newUserCallbackURL\n\t\t\t\t\t\t\t? decodeURIComponent(ctx.query.newUserCallbackURL)\n\t\t\t\t\t\t\t: callbackURL,\n\t\t\t\t\t\tctx.context.baseURL,\n\t\t\t\t\t).toString();\n\t\t\t\t\tconst storedToken = await storeToken(ctx, token);\n\t\t\t\t\tconst tokenValue =\n\t\t\t\t\t\tawait ctx.context.internalAdapter.findVerificationValue(\n\t\t\t\t\t\t\tstoredToken,\n\t\t\t\t\t\t);\n\t\t\t\t\tif (!tokenValue) {\n\t\t\t\t\t\tredirectWithError(\"INVALID_TOKEN\");\n\t\t\t\t\t}\n\t\t\t\t\tif (tokenValue.expiresAt < new Date()) {\n\t\t\t\t\t\tawait ctx.context.internalAdapter.deleteVerificationValue(\n\t\t\t\t\t\t\ttokenValue.id,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tredirectWithError(\"EXPIRED_TOKEN\");\n\t\t\t\t\t}\n\t\t\t\t\tawait ctx.context.internalAdapter.deleteVerificationValue(\n\t\t\t\t\t\ttokenValue.id,\n\t\t\t\t\t);\n\t\t\t\t\tconst { email, name } = JSON.parse(tokenValue.value) as {\n\t\t\t\t\t\temail: string;\n\t\t\t\t\t\tname?: string | undefined;\n\t\t\t\t\t};\n\t\t\t\t\tlet isNewUser = false;\n\t\t\t\t\tlet user = await ctx.context.internalAdapter\n\t\t\t\t\t\t.findUserByEmail(email)\n\t\t\t\t\t\t.then((res) => res?.user);\n\n\t\t\t\t\tif (!user) {\n\t\t\t\t\t\tif (!opts.disableSignUp) {\n\t\t\t\t\t\t\tconst newUser = await ctx.context.internalAdapter.createUser({\n\t\t\t\t\t\t\t\temail: email,\n\t\t\t\t\t\t\t\temailVerified: true,\n\t\t\t\t\t\t\t\tname: name || \"\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tisNewUser = true;\n\t\t\t\t\t\t\tuser = newUser;\n\t\t\t\t\t\t\tif (!user) {\n\t\t\t\t\t\t\t\tredirectWithError(\"failed_to_create_user\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tredirectWithError(\"new_user_signup_disabled\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!user.emailVerified) {\n\t\t\t\t\t\tuser = await ctx.context.internalAdapter.updateUser(user.id, {\n\t\t\t\t\t\t\temailVerified: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tconst session = await ctx.context.internalAdapter.createSession(\n\t\t\t\t\t\tuser.id,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (!session) {\n\t\t\t\t\t\tredirectWithError(\"failed_to_create_session\");\n\t\t\t\t\t}\n\n\t\t\t\t\tawait setSessionCookie(ctx, {\n\t\t\t\t\t\tsession,\n\t\t\t\t\t\tuser,\n\t\t\t\t\t});\n\t\t\t\t\tif (!ctx.query.callbackURL) {\n\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\ttoken: session.token,\n\t\t\t\t\t\t\tuser: parseUserOutput(ctx.context.options, user),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (isNewUser) {\n\t\t\t\t\t\tthrow ctx.redirect(newUserCallbackURL);\n\t\t\t\t\t}\n\t\t\t\t\tthrow ctx.redirect(callbackURL);\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\trateLimit: [\n\t\t\t{\n\t\t\t\tpathMatcher(path) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\tpath.startsWith(\"/sign-in/magic-link\") ||\n\t\t\t\t\t\tpath.startsWith(\"/magic-link/verify\")\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\twindow: opts.rateLimit?.window || 60,\n\t\t\t\tmax: opts.rateLimit?.max || 5,\n\t\t\t},\n\t\t],\n\t\toptions,\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":"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"}