@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.
- package/README.md +33 -0
- package/dist/_virtual/rolldown_runtime.mjs +36 -0
- package/dist/adapters/drizzle-adapter/index.d.mts +1 -0
- package/dist/adapters/drizzle-adapter/index.mjs +3 -0
- package/dist/adapters/index.d.mts +23 -0
- package/dist/adapters/index.mjs +13 -0
- package/dist/adapters/index.mjs.map +1 -0
- package/dist/adapters/kysely-adapter/index.d.mts +1 -0
- package/dist/adapters/kysely-adapter/index.mjs +3 -0
- package/dist/adapters/memory-adapter/index.d.mts +1 -0
- package/dist/adapters/memory-adapter/index.mjs +3 -0
- package/dist/adapters/mongodb-adapter/index.d.mts +1 -0
- package/dist/adapters/mongodb-adapter/index.mjs +3 -0
- package/dist/adapters/prisma-adapter/index.d.mts +1 -0
- package/dist/adapters/prisma-adapter/index.mjs +3 -0
- package/dist/api/index.d.mts +40 -0
- package/dist/api/index.mjs +205 -0
- package/dist/api/index.mjs.map +1 -0
- package/dist/api/middlewares/index.d.mts +1 -0
- package/dist/api/middlewares/index.mjs +3 -0
- package/dist/api/middlewares/origin-check.d.mts +17 -0
- package/dist/api/middlewares/origin-check.mjs +140 -0
- package/dist/api/middlewares/origin-check.mjs.map +1 -0
- package/dist/api/rate-limiter/index.mjs +177 -0
- package/dist/api/rate-limiter/index.mjs.map +1 -0
- package/dist/api/routes/account.d.mts +10 -0
- package/dist/api/routes/account.mjs +493 -0
- package/dist/api/routes/account.mjs.map +1 -0
- package/dist/api/routes/callback.d.mts +5 -0
- package/dist/api/routes/callback.mjs +178 -0
- package/dist/api/routes/callback.mjs.map +1 -0
- package/dist/api/routes/email-verification.d.mts +29 -0
- package/dist/api/routes/email-verification.mjs +301 -0
- package/dist/api/routes/email-verification.mjs.map +1 -0
- package/dist/api/routes/error.d.mts +5 -0
- package/dist/api/routes/error.mjs +386 -0
- package/dist/api/routes/error.mjs.map +1 -0
- package/dist/api/routes/index.d.mts +11 -0
- package/dist/api/routes/index.mjs +13 -0
- package/dist/api/routes/ok.d.mts +5 -0
- package/dist/api/routes/ok.mjs +30 -0
- package/dist/api/routes/ok.mjs.map +1 -0
- package/dist/api/routes/password.d.mts +8 -0
- package/dist/api/routes/password.mjs +198 -0
- package/dist/api/routes/password.mjs.map +1 -0
- package/dist/api/routes/session.d.mts +52 -0
- package/dist/api/routes/session.mjs +478 -0
- package/dist/api/routes/session.mjs.map +1 -0
- package/dist/api/routes/sign-in.d.mts +8 -0
- package/dist/api/routes/sign-in.mjs +262 -0
- package/dist/api/routes/sign-in.mjs.map +1 -0
- package/dist/api/routes/sign-out.d.mts +5 -0
- package/dist/api/routes/sign-out.mjs +33 -0
- package/dist/api/routes/sign-out.mjs.map +1 -0
- package/dist/api/routes/sign-up.d.mts +7 -0
- package/dist/api/routes/sign-up.mjs +227 -0
- package/dist/api/routes/sign-up.mjs.map +1 -0
- package/dist/api/routes/update-user.d.mts +12 -0
- package/dist/api/routes/update-user.mjs +493 -0
- package/dist/api/routes/update-user.mjs.map +1 -0
- package/dist/api/state/oauth.d.mts +5 -0
- package/dist/api/state/oauth.mjs +8 -0
- package/dist/api/state/oauth.mjs.map +1 -0
- package/dist/api/state/should-session-refresh.d.mts +13 -0
- package/dist/api/state/should-session-refresh.mjs +16 -0
- package/dist/api/state/should-session-refresh.mjs.map +1 -0
- package/dist/api/to-auth-endpoints.mjs +197 -0
- package/dist/api/to-auth-endpoints.mjs.map +1 -0
- package/dist/auth/base.mjs +44 -0
- package/dist/auth/base.mjs.map +1 -0
- package/dist/auth/full.d.mts +30 -0
- package/dist/auth/full.mjs +32 -0
- package/dist/auth/full.mjs.map +1 -0
- package/dist/auth/minimal.d.mts +12 -0
- package/dist/auth/minimal.mjs +14 -0
- package/dist/auth/minimal.mjs.map +1 -0
- package/dist/auth/trusted-origins.mjs +31 -0
- package/dist/auth/trusted-origins.mjs.map +1 -0
- package/dist/client/broadcast-channel.d.mts +20 -0
- package/dist/client/broadcast-channel.mjs +46 -0
- package/dist/client/broadcast-channel.mjs.map +1 -0
- package/dist/client/config.mjs +90 -0
- package/dist/client/config.mjs.map +1 -0
- package/dist/client/fetch-plugins.mjs +18 -0
- package/dist/client/fetch-plugins.mjs.map +1 -0
- package/dist/client/focus-manager.d.mts +11 -0
- package/dist/client/focus-manager.mjs +32 -0
- package/dist/client/focus-manager.mjs.map +1 -0
- package/dist/client/index.d.mts +30 -0
- package/dist/client/index.mjs +21 -0
- package/dist/client/index.mjs.map +1 -0
- package/dist/client/lynx/index.d.mts +62 -0
- package/dist/client/lynx/index.mjs +24 -0
- package/dist/client/lynx/index.mjs.map +1 -0
- package/dist/client/lynx/lynx-store.d.mts +47 -0
- package/dist/client/lynx/lynx-store.mjs +47 -0
- package/dist/client/lynx/lynx-store.mjs.map +1 -0
- package/dist/client/online-manager.d.mts +12 -0
- package/dist/client/online-manager.mjs +35 -0
- package/dist/client/online-manager.mjs.map +1 -0
- package/dist/client/parser.mjs +73 -0
- package/dist/client/parser.mjs.map +1 -0
- package/dist/client/path-to-object.d.mts +57 -0
- package/dist/client/plugins/index.d.mts +58 -0
- package/dist/client/plugins/index.mjs +33 -0
- package/dist/client/plugins/infer-plugin.d.mts +9 -0
- package/dist/client/plugins/infer-plugin.mjs +11 -0
- package/dist/client/plugins/infer-plugin.mjs.map +1 -0
- package/dist/client/proxy.mjs +79 -0
- package/dist/client/proxy.mjs.map +1 -0
- package/dist/client/query.d.mts +23 -0
- package/dist/client/query.mjs +98 -0
- package/dist/client/query.mjs.map +1 -0
- package/dist/client/react/index.d.mts +63 -0
- package/dist/client/react/index.mjs +24 -0
- package/dist/client/react/index.mjs.map +1 -0
- package/dist/client/react/react-store.d.mts +47 -0
- package/dist/client/react/react-store.mjs +47 -0
- package/dist/client/react/react-store.mjs.map +1 -0
- package/dist/client/session-atom.mjs +29 -0
- package/dist/client/session-atom.mjs.map +1 -0
- package/dist/client/session-refresh.d.mts +28 -0
- package/dist/client/session-refresh.mjs +140 -0
- package/dist/client/session-refresh.mjs.map +1 -0
- package/dist/client/solid/index.d.mts +57 -0
- package/dist/client/solid/index.mjs +22 -0
- package/dist/client/solid/index.mjs.map +1 -0
- package/dist/client/solid/solid-store.mjs +24 -0
- package/dist/client/solid/solid-store.mjs.map +1 -0
- package/dist/client/svelte/index.d.mts +63 -0
- package/dist/client/svelte/index.mjs +20 -0
- package/dist/client/svelte/index.mjs.map +1 -0
- package/dist/client/types.d.mts +58 -0
- package/dist/client/vanilla.d.mts +62 -0
- package/dist/client/vanilla.mjs +20 -0
- package/dist/client/vanilla.mjs.map +1 -0
- package/dist/client/vue/index.d.mts +86 -0
- package/dist/client/vue/index.mjs +38 -0
- package/dist/client/vue/index.mjs.map +1 -0
- package/dist/client/vue/vue-store.mjs +26 -0
- package/dist/client/vue/vue-store.mjs.map +1 -0
- package/dist/context/create-context.mjs +211 -0
- package/dist/context/create-context.mjs.map +1 -0
- package/dist/context/helpers.mjs +62 -0
- package/dist/context/helpers.mjs.map +1 -0
- package/dist/context/init-minimal.mjs +20 -0
- package/dist/context/init-minimal.mjs.map +1 -0
- package/dist/context/init.mjs +22 -0
- package/dist/context/init.mjs.map +1 -0
- package/dist/cookies/cookie-utils.d.mts +29 -0
- package/dist/cookies/cookie-utils.mjs +105 -0
- package/dist/cookies/cookie-utils.mjs.map +1 -0
- package/dist/cookies/index.d.mts +67 -0
- package/dist/cookies/index.mjs +264 -0
- package/dist/cookies/index.mjs.map +1 -0
- package/dist/cookies/session-store.d.mts +36 -0
- package/dist/cookies/session-store.mjs +200 -0
- package/dist/cookies/session-store.mjs.map +1 -0
- package/dist/crypto/buffer.d.mts +8 -0
- package/dist/crypto/buffer.mjs +18 -0
- package/dist/crypto/buffer.mjs.map +1 -0
- package/dist/crypto/index.d.mts +27 -0
- package/dist/crypto/index.mjs +38 -0
- package/dist/crypto/index.mjs.map +1 -0
- package/dist/crypto/jwt.d.mts +8 -0
- package/dist/crypto/jwt.mjs +95 -0
- package/dist/crypto/jwt.mjs.map +1 -0
- package/dist/crypto/password.d.mts +12 -0
- package/dist/crypto/password.mjs +36 -0
- package/dist/crypto/password.mjs.map +1 -0
- package/dist/crypto/random.d.mts +5 -0
- package/dist/crypto/random.mjs +8 -0
- package/dist/crypto/random.mjs.map +1 -0
- package/dist/db/adapter-base.d.mts +8 -0
- package/dist/db/adapter-base.mjs +28 -0
- package/dist/db/adapter-base.mjs.map +1 -0
- package/dist/db/adapter-kysely.d.mts +8 -0
- package/dist/db/adapter-kysely.mjs +21 -0
- package/dist/db/adapter-kysely.mjs.map +1 -0
- package/dist/db/field-converter.d.mts +8 -0
- package/dist/db/field-converter.mjs +21 -0
- package/dist/db/field-converter.mjs.map +1 -0
- package/dist/db/field.d.mts +55 -0
- package/dist/db/field.mjs +11 -0
- package/dist/db/field.mjs.map +1 -0
- package/dist/db/get-migration.d.mts +23 -0
- package/dist/db/get-migration.mjs +339 -0
- package/dist/db/get-migration.mjs.map +1 -0
- package/dist/db/get-schema.d.mts +11 -0
- package/dist/db/get-schema.mjs +39 -0
- package/dist/db/get-schema.mjs.map +1 -0
- package/dist/db/index.d.mts +9 -0
- package/dist/db/index.mjs +36 -0
- package/dist/db/index.mjs.map +1 -0
- package/dist/db/internal-adapter.d.mts +14 -0
- package/dist/db/internal-adapter.mjs +616 -0
- package/dist/db/internal-adapter.mjs.map +1 -0
- package/dist/db/schema.d.mts +26 -0
- package/dist/db/schema.mjs +118 -0
- package/dist/db/schema.mjs.map +1 -0
- package/dist/db/to-zod.d.mts +36 -0
- package/dist/db/to-zod.mjs +26 -0
- package/dist/db/to-zod.mjs.map +1 -0
- package/dist/db/verification-token-storage.mjs +28 -0
- package/dist/db/verification-token-storage.mjs.map +1 -0
- package/dist/db/with-hooks.d.mts +33 -0
- package/dist/db/with-hooks.mjs +159 -0
- package/dist/db/with-hooks.mjs.map +1 -0
- package/dist/index.d.mts +52 -0
- package/dist/index.mjs +26 -0
- package/dist/integrations/next-js.d.mts +14 -0
- package/dist/integrations/next-js.mjs +78 -0
- package/dist/integrations/next-js.mjs.map +1 -0
- package/dist/integrations/node.d.mts +13 -0
- package/dist/integrations/node.mjs +16 -0
- package/dist/integrations/node.mjs.map +1 -0
- package/dist/integrations/solid-start.d.mts +23 -0
- package/dist/integrations/solid-start.mjs +17 -0
- package/dist/integrations/solid-start.mjs.map +1 -0
- package/dist/integrations/svelte-kit.d.mts +29 -0
- package/dist/integrations/svelte-kit.mjs +57 -0
- package/dist/integrations/svelte-kit.mjs.map +1 -0
- package/dist/integrations/tanstack-start-solid.d.mts +22 -0
- package/dist/integrations/tanstack-start-solid.mjs +61 -0
- package/dist/integrations/tanstack-start-solid.mjs.map +1 -0
- package/dist/integrations/tanstack-start.d.mts +22 -0
- package/dist/integrations/tanstack-start.mjs +61 -0
- package/dist/integrations/tanstack-start.mjs.map +1 -0
- package/dist/oauth2/index.d.mts +5 -0
- package/dist/oauth2/index.mjs +7 -0
- package/dist/oauth2/link-account.d.mts +31 -0
- package/dist/oauth2/link-account.mjs +144 -0
- package/dist/oauth2/link-account.mjs.map +1 -0
- package/dist/oauth2/state.d.mts +26 -0
- package/dist/oauth2/state.mjs +51 -0
- package/dist/oauth2/state.mjs.map +1 -0
- package/dist/oauth2/utils.d.mts +8 -0
- package/dist/oauth2/utils.mjs +31 -0
- package/dist/oauth2/utils.mjs.map +1 -0
- package/dist/plugins/access/access.d.mts +30 -0
- package/dist/plugins/access/access.mjs +46 -0
- package/dist/plugins/access/access.mjs.map +1 -0
- package/dist/plugins/access/index.d.mts +3 -0
- package/dist/plugins/access/index.mjs +3 -0
- package/dist/plugins/access/types.d.mts +17 -0
- package/dist/plugins/additional-fields/client.d.mts +14 -0
- package/dist/plugins/additional-fields/client.mjs +11 -0
- package/dist/plugins/additional-fields/client.mjs.map +1 -0
- package/dist/plugins/admin/access/index.d.mts +2 -0
- package/dist/plugins/admin/access/index.mjs +3 -0
- package/dist/plugins/admin/access/statement.d.mts +118 -0
- package/dist/plugins/admin/access/statement.mjs +53 -0
- package/dist/plugins/admin/access/statement.mjs.map +1 -0
- package/dist/plugins/admin/admin.d.mts +14 -0
- package/dist/plugins/admin/admin.mjs +95 -0
- package/dist/plugins/admin/admin.mjs.map +1 -0
- package/dist/plugins/admin/client.d.mts +14 -0
- package/dist/plugins/admin/client.mjs +36 -0
- package/dist/plugins/admin/client.mjs.map +1 -0
- package/dist/plugins/admin/error-codes.d.mts +5 -0
- package/dist/plugins/admin/error-codes.mjs +30 -0
- package/dist/plugins/admin/error-codes.mjs.map +1 -0
- package/dist/plugins/admin/has-permission.mjs +16 -0
- package/dist/plugins/admin/has-permission.mjs.map +1 -0
- package/dist/plugins/admin/index.d.mts +3 -0
- package/dist/plugins/admin/index.mjs +3 -0
- package/dist/plugins/admin/routes.mjs +855 -0
- package/dist/plugins/admin/routes.mjs.map +1 -0
- package/dist/plugins/admin/schema.d.mts +6 -0
- package/dist/plugins/admin/schema.mjs +34 -0
- package/dist/plugins/admin/schema.mjs.map +1 -0
- package/dist/plugins/admin/types.d.mts +89 -0
- package/dist/plugins/anonymous/client.d.mts +9 -0
- package/dist/plugins/anonymous/client.mjs +22 -0
- package/dist/plugins/anonymous/client.mjs.map +1 -0
- package/dist/plugins/anonymous/error-codes.d.mts +5 -0
- package/dist/plugins/anonymous/error-codes.mjs +16 -0
- package/dist/plugins/anonymous/error-codes.mjs.map +1 -0
- package/dist/plugins/anonymous/index.d.mts +14 -0
- package/dist/plugins/anonymous/index.mjs +163 -0
- package/dist/plugins/anonymous/index.mjs.map +1 -0
- package/dist/plugins/anonymous/schema.d.mts +5 -0
- package/dist/plugins/anonymous/schema.mjs +11 -0
- package/dist/plugins/anonymous/schema.mjs.map +1 -0
- package/dist/plugins/anonymous/types.d.mts +68 -0
- package/dist/plugins/api-key/adapter.mjs +468 -0
- package/dist/plugins/api-key/adapter.mjs.map +1 -0
- package/dist/plugins/api-key/client.d.mts +9 -0
- package/dist/plugins/api-key/client.mjs +19 -0
- package/dist/plugins/api-key/client.mjs.map +1 -0
- package/dist/plugins/api-key/error-codes.d.mts +5 -0
- package/dist/plugins/api-key/error-codes.mjs +34 -0
- package/dist/plugins/api-key/error-codes.mjs.map +1 -0
- package/dist/plugins/api-key/index.d.mts +17 -0
- package/dist/plugins/api-key/index.mjs +134 -0
- package/dist/plugins/api-key/index.mjs.map +1 -0
- package/dist/plugins/api-key/rate-limit.mjs +74 -0
- package/dist/plugins/api-key/rate-limit.mjs.map +1 -0
- package/dist/plugins/api-key/routes/create-api-key.mjs +252 -0
- package/dist/plugins/api-key/routes/create-api-key.mjs.map +1 -0
- package/dist/plugins/api-key/routes/delete-all-expired-api-keys.mjs +24 -0
- package/dist/plugins/api-key/routes/delete-all-expired-api-keys.mjs.map +1 -0
- package/dist/plugins/api-key/routes/delete-api-key.mjs +74 -0
- package/dist/plugins/api-key/routes/delete-api-key.mjs.map +1 -0
- package/dist/plugins/api-key/routes/get-api-key.mjs +158 -0
- package/dist/plugins/api-key/routes/get-api-key.mjs.map +1 -0
- package/dist/plugins/api-key/routes/index.mjs +71 -0
- package/dist/plugins/api-key/routes/index.mjs.map +1 -0
- package/dist/plugins/api-key/routes/list-api-keys.mjs +194 -0
- package/dist/plugins/api-key/routes/list-api-keys.mjs.map +1 -0
- package/dist/plugins/api-key/routes/update-api-key.mjs +248 -0
- package/dist/plugins/api-key/routes/update-api-key.mjs.map +1 -0
- package/dist/plugins/api-key/routes/verify-api-key.mjs +223 -0
- package/dist/plugins/api-key/routes/verify-api-key.mjs.map +1 -0
- package/dist/plugins/api-key/schema.d.mts +11 -0
- package/dist/plugins/api-key/schema.mjs +130 -0
- package/dist/plugins/api-key/schema.mjs.map +1 -0
- package/dist/plugins/api-key/types.d.mts +346 -0
- package/dist/plugins/bearer/index.d.mts +25 -0
- package/dist/plugins/bearer/index.mjs +66 -0
- package/dist/plugins/bearer/index.mjs.map +1 -0
- package/dist/plugins/captcha/constants.d.mts +10 -0
- package/dist/plugins/captcha/constants.mjs +22 -0
- package/dist/plugins/captcha/constants.mjs.map +1 -0
- package/dist/plugins/captcha/error-codes.mjs +16 -0
- package/dist/plugins/captcha/error-codes.mjs.map +1 -0
- package/dist/plugins/captcha/index.d.mts +14 -0
- package/dist/plugins/captcha/index.mjs +60 -0
- package/dist/plugins/captcha/index.mjs.map +1 -0
- package/dist/plugins/captcha/types.d.mts +28 -0
- package/dist/plugins/captcha/utils.mjs +11 -0
- package/dist/plugins/captcha/utils.mjs.map +1 -0
- package/dist/plugins/captcha/verify-handlers/captchafox.mjs +27 -0
- package/dist/plugins/captcha/verify-handlers/captchafox.mjs.map +1 -0
- package/dist/plugins/captcha/verify-handlers/cloudflare-turnstile.mjs +25 -0
- package/dist/plugins/captcha/verify-handlers/cloudflare-turnstile.mjs.map +1 -0
- package/dist/plugins/captcha/verify-handlers/google-recaptcha.mjs +29 -0
- package/dist/plugins/captcha/verify-handlers/google-recaptcha.mjs.map +1 -0
- package/dist/plugins/captcha/verify-handlers/h-captcha.mjs +27 -0
- package/dist/plugins/captcha/verify-handlers/h-captcha.mjs.map +1 -0
- package/dist/plugins/captcha/verify-handlers/index.mjs +6 -0
- package/dist/plugins/custom-session/client.d.mts +10 -0
- package/dist/plugins/custom-session/client.mjs +11 -0
- package/dist/plugins/custom-session/client.mjs.map +1 -0
- package/dist/plugins/custom-session/index.d.mts +26 -0
- package/dist/plugins/custom-session/index.mjs +70 -0
- package/dist/plugins/custom-session/index.mjs.map +1 -0
- package/dist/plugins/device-authorization/client.d.mts +5 -0
- package/dist/plugins/device-authorization/client.mjs +18 -0
- package/dist/plugins/device-authorization/client.mjs.map +1 -0
- package/dist/plugins/device-authorization/error-codes.mjs +21 -0
- package/dist/plugins/device-authorization/error-codes.mjs.map +1 -0
- package/dist/plugins/device-authorization/index.d.mts +28 -0
- package/dist/plugins/device-authorization/index.mjs +50 -0
- package/dist/plugins/device-authorization/index.mjs.map +1 -0
- package/dist/plugins/device-authorization/routes.mjs +510 -0
- package/dist/plugins/device-authorization/routes.mjs.map +1 -0
- package/dist/plugins/device-authorization/schema.mjs +57 -0
- package/dist/plugins/device-authorization/schema.mjs.map +1 -0
- package/dist/plugins/email-otp/client.d.mts +7 -0
- package/dist/plugins/email-otp/client.mjs +18 -0
- package/dist/plugins/email-otp/client.mjs.map +1 -0
- package/dist/plugins/email-otp/error-codes.d.mts +5 -0
- package/dist/plugins/email-otp/error-codes.mjs +12 -0
- package/dist/plugins/email-otp/error-codes.mjs.map +1 -0
- package/dist/plugins/email-otp/index.d.mts +14 -0
- package/dist/plugins/email-otp/index.mjs +108 -0
- package/dist/plugins/email-otp/index.mjs.map +1 -0
- package/dist/plugins/email-otp/otp-token.mjs +29 -0
- package/dist/plugins/email-otp/otp-token.mjs.map +1 -0
- package/dist/plugins/email-otp/routes.mjs +564 -0
- package/dist/plugins/email-otp/routes.mjs.map +1 -0
- package/dist/plugins/email-otp/types.d.mts +74 -0
- package/dist/plugins/email-otp/utils.mjs +17 -0
- package/dist/plugins/email-otp/utils.mjs.map +1 -0
- package/dist/plugins/generic-oauth/client.d.mts +19 -0
- package/dist/plugins/generic-oauth/client.mjs +14 -0
- package/dist/plugins/generic-oauth/client.mjs.map +1 -0
- package/dist/plugins/generic-oauth/error-codes.d.mts +5 -0
- package/dist/plugins/generic-oauth/error-codes.mjs +15 -0
- package/dist/plugins/generic-oauth/error-codes.mjs.map +1 -0
- package/dist/plugins/generic-oauth/index.d.mts +34 -0
- package/dist/plugins/generic-oauth/index.mjs +137 -0
- package/dist/plugins/generic-oauth/index.mjs.map +1 -0
- package/dist/plugins/generic-oauth/providers/auth0.d.mts +37 -0
- package/dist/plugins/generic-oauth/providers/auth0.mjs +62 -0
- package/dist/plugins/generic-oauth/providers/auth0.mjs.map +1 -0
- package/dist/plugins/generic-oauth/providers/gumroad.d.mts +32 -0
- package/dist/plugins/generic-oauth/providers/gumroad.mjs +60 -0
- package/dist/plugins/generic-oauth/providers/gumroad.mjs.map +1 -0
- package/dist/plugins/generic-oauth/providers/hubspot.d.mts +37 -0
- package/dist/plugins/generic-oauth/providers/hubspot.mjs +60 -0
- package/dist/plugins/generic-oauth/providers/hubspot.mjs.map +1 -0
- package/dist/plugins/generic-oauth/providers/index.d.mts +9 -0
- package/dist/plugins/generic-oauth/providers/index.mjs +11 -0
- package/dist/plugins/generic-oauth/providers/keycloak.d.mts +37 -0
- package/dist/plugins/generic-oauth/providers/keycloak.mjs +62 -0
- package/dist/plugins/generic-oauth/providers/keycloak.mjs.map +1 -0
- package/dist/plugins/generic-oauth/providers/line.d.mts +55 -0
- package/dist/plugins/generic-oauth/providers/line.mjs +91 -0
- package/dist/plugins/generic-oauth/providers/line.mjs.map +1 -0
- package/dist/plugins/generic-oauth/providers/microsoft-entra-id.d.mts +37 -0
- package/dist/plugins/generic-oauth/providers/microsoft-entra-id.mjs +66 -0
- package/dist/plugins/generic-oauth/providers/microsoft-entra-id.mjs.map +1 -0
- package/dist/plugins/generic-oauth/providers/okta.d.mts +37 -0
- package/dist/plugins/generic-oauth/providers/okta.mjs +62 -0
- package/dist/plugins/generic-oauth/providers/okta.mjs.map +1 -0
- package/dist/plugins/generic-oauth/providers/patreon.d.mts +30 -0
- package/dist/plugins/generic-oauth/providers/patreon.mjs +59 -0
- package/dist/plugins/generic-oauth/providers/patreon.mjs.map +1 -0
- package/dist/plugins/generic-oauth/providers/slack.d.mts +30 -0
- package/dist/plugins/generic-oauth/providers/slack.mjs +61 -0
- package/dist/plugins/generic-oauth/providers/slack.mjs.map +1 -0
- package/dist/plugins/generic-oauth/routes.mjs +394 -0
- package/dist/plugins/generic-oauth/routes.mjs.map +1 -0
- package/dist/plugins/generic-oauth/types.d.mts +145 -0
- package/dist/plugins/haveibeenpwned/index.d.mts +21 -0
- package/dist/plugins/haveibeenpwned/index.mjs +56 -0
- package/dist/plugins/haveibeenpwned/index.mjs.map +1 -0
- package/dist/plugins/index.d.mts +68 -0
- package/dist/plugins/index.mjs +51 -0
- package/dist/plugins/jwt/adapter.mjs +27 -0
- package/dist/plugins/jwt/adapter.mjs.map +1 -0
- package/dist/plugins/jwt/client.d.mts +18 -0
- package/dist/plugins/jwt/client.mjs +19 -0
- package/dist/plugins/jwt/client.mjs.map +1 -0
- package/dist/plugins/jwt/index.d.mts +17 -0
- package/dist/plugins/jwt/index.mjs +202 -0
- package/dist/plugins/jwt/index.mjs.map +1 -0
- package/dist/plugins/jwt/schema.d.mts +5 -0
- package/dist/plugins/jwt/schema.mjs +23 -0
- package/dist/plugins/jwt/schema.mjs.map +1 -0
- package/dist/plugins/jwt/sign.d.mts +57 -0
- package/dist/plugins/jwt/sign.mjs +66 -0
- package/dist/plugins/jwt/sign.mjs.map +1 -0
- package/dist/plugins/jwt/types.d.mts +194 -0
- package/dist/plugins/jwt/utils.d.mts +42 -0
- package/dist/plugins/jwt/utils.mjs +64 -0
- package/dist/plugins/jwt/utils.mjs.map +1 -0
- package/dist/plugins/jwt/verify.d.mts +12 -0
- package/dist/plugins/jwt/verify.mjs +46 -0
- package/dist/plugins/jwt/verify.mjs.map +1 -0
- package/dist/plugins/last-login-method/client.d.mts +18 -0
- package/dist/plugins/last-login-method/client.mjs +32 -0
- package/dist/plugins/last-login-method/client.mjs.map +1 -0
- package/dist/plugins/last-login-method/index.d.mts +52 -0
- package/dist/plugins/last-login-method/index.mjs +77 -0
- package/dist/plugins/last-login-method/index.mjs.map +1 -0
- package/dist/plugins/magic-link/client.d.mts +5 -0
- package/dist/plugins/magic-link/client.mjs +11 -0
- package/dist/plugins/magic-link/client.mjs.map +1 -0
- package/dist/plugins/magic-link/index.d.mts +61 -0
- package/dist/plugins/magic-link/index.mjs +167 -0
- package/dist/plugins/magic-link/index.mjs.map +1 -0
- package/dist/plugins/magic-link/utils.mjs +12 -0
- package/dist/plugins/magic-link/utils.mjs.map +1 -0
- package/dist/plugins/mcp/authorize.mjs +133 -0
- package/dist/plugins/mcp/authorize.mjs.map +1 -0
- package/dist/plugins/mcp/index.d.mts +46 -0
- package/dist/plugins/mcp/index.mjs +717 -0
- package/dist/plugins/mcp/index.mjs.map +1 -0
- package/dist/plugins/multi-session/client.d.mts +8 -0
- package/dist/plugins/multi-session/client.mjs +20 -0
- package/dist/plugins/multi-session/client.mjs.map +1 -0
- package/dist/plugins/multi-session/error-codes.d.mts +5 -0
- package/dist/plugins/multi-session/error-codes.mjs +8 -0
- package/dist/plugins/multi-session/error-codes.mjs.map +1 -0
- package/dist/plugins/multi-session/index.d.mts +22 -0
- package/dist/plugins/multi-session/index.mjs +172 -0
- package/dist/plugins/multi-session/index.mjs.map +1 -0
- package/dist/plugins/oauth-proxy/index.d.mts +39 -0
- package/dist/plugins/oauth-proxy/index.mjs +305 -0
- package/dist/plugins/oauth-proxy/index.mjs.map +1 -0
- package/dist/plugins/oauth-proxy/utils.mjs +44 -0
- package/dist/plugins/oauth-proxy/utils.mjs.map +1 -0
- package/dist/plugins/oidc-provider/authorize.mjs +194 -0
- package/dist/plugins/oidc-provider/authorize.mjs.map +1 -0
- package/dist/plugins/oidc-provider/client.d.mts +8 -0
- package/dist/plugins/oidc-provider/client.mjs +11 -0
- package/dist/plugins/oidc-provider/client.mjs.map +1 -0
- package/dist/plugins/oidc-provider/error.mjs +17 -0
- package/dist/plugins/oidc-provider/error.mjs.map +1 -0
- package/dist/plugins/oidc-provider/index.d.mts +32 -0
- package/dist/plugins/oidc-provider/index.mjs +1093 -0
- package/dist/plugins/oidc-provider/index.mjs.map +1 -0
- package/dist/plugins/oidc-provider/schema.d.mts +26 -0
- package/dist/plugins/oidc-provider/schema.mjs +132 -0
- package/dist/plugins/oidc-provider/schema.mjs.map +1 -0
- package/dist/plugins/oidc-provider/types.d.mts +517 -0
- package/dist/plugins/oidc-provider/utils/prompt.mjs +19 -0
- package/dist/plugins/oidc-provider/utils/prompt.mjs.map +1 -0
- package/dist/plugins/oidc-provider/utils.mjs +15 -0
- package/dist/plugins/oidc-provider/utils.mjs.map +1 -0
- package/dist/plugins/one-tap/client.d.mts +159 -0
- package/dist/plugins/one-tap/client.mjs +214 -0
- package/dist/plugins/one-tap/client.mjs.map +1 -0
- package/dist/plugins/one-tap/index.d.mts +27 -0
- package/dist/plugins/one-tap/index.mjs +96 -0
- package/dist/plugins/one-tap/index.mjs.map +1 -0
- package/dist/plugins/one-time-token/client.d.mts +7 -0
- package/dist/plugins/one-time-token/client.mjs +11 -0
- package/dist/plugins/one-time-token/client.mjs.map +1 -0
- package/dist/plugins/one-time-token/index.d.mts +53 -0
- package/dist/plugins/one-time-token/index.mjs +82 -0
- package/dist/plugins/one-time-token/index.mjs.map +1 -0
- package/dist/plugins/one-time-token/utils.mjs +12 -0
- package/dist/plugins/one-time-token/utils.mjs.map +1 -0
- package/dist/plugins/open-api/generator.d.mts +115 -0
- package/dist/plugins/open-api/generator.mjs +315 -0
- package/dist/plugins/open-api/generator.mjs.map +1 -0
- package/dist/plugins/open-api/index.d.mts +45 -0
- package/dist/plugins/open-api/index.mjs +67 -0
- package/dist/plugins/open-api/index.mjs.map +1 -0
- package/dist/plugins/open-api/logo.mjs +15 -0
- package/dist/plugins/open-api/logo.mjs.map +1 -0
- package/dist/plugins/organization/access/index.d.mts +2 -0
- package/dist/plugins/organization/access/index.mjs +3 -0
- package/dist/plugins/organization/access/statement.d.mts +249 -0
- package/dist/plugins/organization/access/statement.mjs +81 -0
- package/dist/plugins/organization/access/statement.mjs.map +1 -0
- package/dist/plugins/organization/adapter.d.mts +205 -0
- package/dist/plugins/organization/adapter.mjs +624 -0
- package/dist/plugins/organization/adapter.mjs.map +1 -0
- package/dist/plugins/organization/call.mjs +19 -0
- package/dist/plugins/organization/call.mjs.map +1 -0
- package/dist/plugins/organization/client.d.mts +151 -0
- package/dist/plugins/organization/client.mjs +107 -0
- package/dist/plugins/organization/client.mjs.map +1 -0
- package/dist/plugins/organization/error-codes.d.mts +5 -0
- package/dist/plugins/organization/error-codes.mjs +65 -0
- package/dist/plugins/organization/error-codes.mjs.map +1 -0
- package/dist/plugins/organization/has-permission.mjs +35 -0
- package/dist/plugins/organization/has-permission.mjs.map +1 -0
- package/dist/plugins/organization/index.d.mts +5 -0
- package/dist/plugins/organization/index.mjs +4 -0
- package/dist/plugins/organization/organization.d.mts +252 -0
- package/dist/plugins/organization/organization.mjs +428 -0
- package/dist/plugins/organization/organization.mjs.map +1 -0
- package/dist/plugins/organization/permission.d.mts +26 -0
- package/dist/plugins/organization/permission.mjs +16 -0
- package/dist/plugins/organization/permission.mjs.map +1 -0
- package/dist/plugins/organization/routes/crud-access-control.d.mts +11 -0
- package/dist/plugins/organization/routes/crud-access-control.mjs +656 -0
- package/dist/plugins/organization/routes/crud-access-control.mjs.map +1 -0
- package/dist/plugins/organization/routes/crud-invites.d.mts +16 -0
- package/dist/plugins/organization/routes/crud-invites.mjs +555 -0
- package/dist/plugins/organization/routes/crud-invites.mjs.map +1 -0
- package/dist/plugins/organization/routes/crud-members.d.mts +13 -0
- package/dist/plugins/organization/routes/crud-members.mjs +473 -0
- package/dist/plugins/organization/routes/crud-members.mjs.map +1 -0
- package/dist/plugins/organization/routes/crud-org.d.mts +13 -0
- package/dist/plugins/organization/routes/crud-org.mjs +447 -0
- package/dist/plugins/organization/routes/crud-org.mjs.map +1 -0
- package/dist/plugins/organization/routes/crud-team.d.mts +15 -0
- package/dist/plugins/organization/routes/crud-team.mjs +676 -0
- package/dist/plugins/organization/routes/crud-team.mjs.map +1 -0
- package/dist/plugins/organization/schema.d.mts +376 -0
- package/dist/plugins/organization/schema.mjs +68 -0
- package/dist/plugins/organization/schema.mjs.map +1 -0
- package/dist/plugins/organization/types.d.mts +733 -0
- package/dist/plugins/phone-number/client.d.mts +8 -0
- package/dist/plugins/phone-number/client.mjs +20 -0
- package/dist/plugins/phone-number/client.mjs.map +1 -0
- package/dist/plugins/phone-number/error-codes.d.mts +5 -0
- package/dist/plugins/phone-number/error-codes.mjs +21 -0
- package/dist/plugins/phone-number/error-codes.mjs.map +1 -0
- package/dist/plugins/phone-number/index.d.mts +14 -0
- package/dist/plugins/phone-number/index.mjs +49 -0
- package/dist/plugins/phone-number/index.mjs.map +1 -0
- package/dist/plugins/phone-number/routes.mjs +459 -0
- package/dist/plugins/phone-number/routes.mjs.map +1 -0
- package/dist/plugins/phone-number/schema.d.mts +5 -0
- package/dist/plugins/phone-number/schema.mjs +20 -0
- package/dist/plugins/phone-number/schema.mjs.map +1 -0
- package/dist/plugins/phone-number/types.d.mts +118 -0
- package/dist/plugins/siwe/client.d.mts +5 -0
- package/dist/plugins/siwe/client.mjs +11 -0
- package/dist/plugins/siwe/client.mjs.map +1 -0
- package/dist/plugins/siwe/error-codes.mjs +13 -0
- package/dist/plugins/siwe/error-codes.mjs.map +1 -0
- package/dist/plugins/siwe/index.d.mts +26 -0
- package/dist/plugins/siwe/index.mjs +261 -0
- package/dist/plugins/siwe/index.mjs.map +1 -0
- package/dist/plugins/siwe/schema.d.mts +5 -0
- package/dist/plugins/siwe/schema.mjs +32 -0
- package/dist/plugins/siwe/schema.mjs.map +1 -0
- package/dist/plugins/siwe/types.d.mts +44 -0
- package/dist/plugins/two-factor/backup-codes/index.d.mts +91 -0
- package/dist/plugins/two-factor/backup-codes/index.mjs +277 -0
- package/dist/plugins/two-factor/backup-codes/index.mjs.map +1 -0
- package/dist/plugins/two-factor/client.d.mts +17 -0
- package/dist/plugins/two-factor/client.mjs +37 -0
- package/dist/plugins/two-factor/client.mjs.map +1 -0
- package/dist/plugins/two-factor/constant.mjs +8 -0
- package/dist/plugins/two-factor/constant.mjs.map +1 -0
- package/dist/plugins/two-factor/error-code.d.mts +5 -0
- package/dist/plugins/two-factor/error-code.mjs +18 -0
- package/dist/plugins/two-factor/error-code.mjs.map +1 -0
- package/dist/plugins/two-factor/index.d.mts +19 -0
- package/dist/plugins/two-factor/index.mjs +207 -0
- package/dist/plugins/two-factor/index.mjs.map +1 -0
- package/dist/plugins/two-factor/otp/index.d.mts +96 -0
- package/dist/plugins/two-factor/otp/index.mjs +199 -0
- package/dist/plugins/two-factor/otp/index.mjs.map +1 -0
- package/dist/plugins/two-factor/schema.d.mts +5 -0
- package/dist/plugins/two-factor/schema.mjs +36 -0
- package/dist/plugins/two-factor/schema.mjs.map +1 -0
- package/dist/plugins/two-factor/totp/index.d.mts +81 -0
- package/dist/plugins/two-factor/totp/index.mjs +157 -0
- package/dist/plugins/two-factor/totp/index.mjs.map +1 -0
- package/dist/plugins/two-factor/types.d.mts +65 -0
- package/dist/plugins/two-factor/utils.mjs +12 -0
- package/dist/plugins/two-factor/utils.mjs.map +1 -0
- package/dist/plugins/two-factor/verify-two-factor.mjs +76 -0
- package/dist/plugins/two-factor/verify-two-factor.mjs.map +1 -0
- package/dist/plugins/username/client.d.mts +7 -0
- package/dist/plugins/username/client.mjs +18 -0
- package/dist/plugins/username/client.mjs.map +1 -0
- package/dist/plugins/username/error-codes.d.mts +5 -0
- package/dist/plugins/username/error-codes.mjs +17 -0
- package/dist/plugins/username/error-codes.mjs.map +1 -0
- package/dist/plugins/username/index.d.mts +74 -0
- package/dist/plugins/username/index.mjs +237 -0
- package/dist/plugins/username/index.mjs.map +1 -0
- package/dist/plugins/username/schema.d.mts +9 -0
- package/dist/plugins/username/schema.mjs +26 -0
- package/dist/plugins/username/schema.mjs.map +1 -0
- package/dist/social-providers/index.d.mts +1 -0
- package/dist/social-providers/index.mjs +3 -0
- package/dist/state.d.mts +42 -0
- package/dist/state.mjs +107 -0
- package/dist/state.mjs.map +1 -0
- package/dist/test-utils/headers.d.mts +9 -0
- package/dist/test-utils/headers.mjs +24 -0
- package/dist/test-utils/headers.mjs.map +1 -0
- package/dist/test-utils/index.d.mts +3 -0
- package/dist/test-utils/index.mjs +4 -0
- package/dist/test-utils/test-instance.d.mts +181 -0
- package/dist/test-utils/test-instance.mjs +210 -0
- package/dist/test-utils/test-instance.mjs.map +1 -0
- package/dist/types/adapter.d.mts +24 -0
- package/dist/types/api.d.mts +62 -0
- package/dist/types/auth.d.mts +30 -0
- package/dist/types/helper.d.mts +21 -0
- package/dist/types/index.d.mts +11 -0
- package/dist/types/index.mjs +1 -0
- package/dist/types/models.d.mts +17 -0
- package/dist/types/plugins.d.mts +16 -0
- package/dist/utils/boolean.mjs +8 -0
- package/dist/utils/boolean.mjs.map +1 -0
- package/dist/utils/constants.mjs +6 -0
- package/dist/utils/constants.mjs.map +1 -0
- package/dist/utils/date.mjs +8 -0
- package/dist/utils/date.mjs.map +1 -0
- package/dist/utils/get-request-ip.d.mts +7 -0
- package/dist/utils/get-request-ip.mjs +23 -0
- package/dist/utils/get-request-ip.mjs.map +1 -0
- package/dist/utils/hashing.mjs +21 -0
- package/dist/utils/hashing.mjs.map +1 -0
- package/dist/utils/hide-metadata.d.mts +7 -0
- package/dist/utils/hide-metadata.mjs +6 -0
- package/dist/utils/hide-metadata.mjs.map +1 -0
- package/dist/utils/index.d.mts +3 -0
- package/dist/utils/index.mjs +5 -0
- package/dist/utils/is-api-error.d.mts +7 -0
- package/dist/utils/is-api-error.mjs +11 -0
- package/dist/utils/is-api-error.mjs.map +1 -0
- package/dist/utils/is-atom.mjs +8 -0
- package/dist/utils/is-atom.mjs.map +1 -0
- package/dist/utils/is-promise.mjs +8 -0
- package/dist/utils/is-promise.mjs.map +1 -0
- package/dist/utils/middleware-response.mjs +6 -0
- package/dist/utils/middleware-response.mjs.map +1 -0
- package/dist/utils/password.mjs +26 -0
- package/dist/utils/password.mjs.map +1 -0
- package/dist/utils/plugin-helper.mjs +17 -0
- package/dist/utils/plugin-helper.mjs.map +1 -0
- package/dist/utils/shim.mjs +24 -0
- package/dist/utils/shim.mjs.map +1 -0
- package/dist/utils/time.d.mts +49 -0
- package/dist/utils/time.mjs +100 -0
- package/dist/utils/time.mjs.map +1 -0
- package/dist/utils/url.mjs +92 -0
- package/dist/utils/url.mjs.map +1 -0
- package/dist/utils/wildcard.mjs +108 -0
- package/dist/utils/wildcard.mjs.map +1 -0
- 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 @@
|
|
|
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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"}
|