@masheev/better-auth 0.0.0-stage → 1.7.5
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/LICENSE.md +20 -0
- package/README.md +31 -2
- package/TYPE-PATCH-NOTICE.md +9 -0
- package/TYPE-PATCH-PROVENANCE.json +267 -0
- package/dist/_virtual/_rolldown/runtime.mjs +27 -0
- package/dist/adapters/drizzle-adapter/index.d.mts +1 -0
- package/dist/adapters/drizzle-adapter/index.mjs +2 -0
- package/dist/adapters/index.d.mts +26 -0
- package/dist/adapters/index.mjs +9 -0
- package/dist/adapters/kysely-adapter/index.d.mts +1 -0
- package/dist/adapters/kysely-adapter/index.mjs +2 -0
- package/dist/adapters/memory-adapter/index.d.mts +1 -0
- package/dist/adapters/memory-adapter/index.mjs +2 -0
- package/dist/adapters/mongodb-adapter/index.d.mts +1 -0
- package/dist/adapters/mongodb-adapter/index.mjs +2 -0
- package/dist/adapters/prisma-adapter/index.d.mts +1 -0
- package/dist/adapters/prisma-adapter/index.mjs +2 -0
- package/dist/api/dispatch.d.mts +34 -0
- package/dist/api/dispatch.mjs +275 -0
- package/dist/api/index.d.mts +4053 -0
- package/dist/api/index.mjs +220 -0
- package/dist/api/middlewares/authorization.d.mts +69 -0
- package/dist/api/middlewares/authorization.mjs +78 -0
- package/dist/api/middlewares/index.d.mts +2 -0
- package/dist/api/middlewares/origin-check.d.mts +17 -0
- package/dist/api/middlewares/origin-check.mjs +155 -0
- package/dist/api/rate-limiter/index.mjs +318 -0
- package/dist/api/routes/account.d.mts +413 -0
- package/dist/api/routes/account.mjs +619 -0
- package/dist/api/routes/callback.d.mts +32 -0
- package/dist/api/routes/callback.mjs +261 -0
- package/dist/api/routes/email-verification.d.mts +160 -0
- package/dist/api/routes/email-verification.mjs +324 -0
- package/dist/api/routes/error.d.mts +27 -0
- package/dist/api/routes/error.mjs +387 -0
- package/dist/api/routes/index.d.mts +12 -0
- package/dist/api/routes/ok.d.mts +35 -0
- package/dist/api/routes/ok.mjs +27 -0
- package/dist/api/routes/password.d.mts +182 -0
- package/dist/api/routes/password.mjs +206 -0
- package/dist/api/routes/session.d.mts +450 -0
- package/dist/api/routes/session.mjs +481 -0
- package/dist/api/routes/sign-in.d.mts +186 -0
- package/dist/api/routes/sign-in.mjs +368 -0
- package/dist/api/routes/sign-out.d.mts +51 -0
- package/dist/api/routes/sign-out.mjs +96 -0
- package/dist/api/routes/sign-up.d.mts +159 -0
- package/dist/api/routes/sign-up.mjs +275 -0
- package/dist/api/routes/update-session.d.mts +74 -0
- package/dist/api/routes/update-session.mjs +57 -0
- package/dist/api/routes/update-user.d.mts +428 -0
- package/dist/api/routes/update-user.mjs +522 -0
- package/dist/api/state/oauth.d.mts +53 -0
- package/dist/api/state/oauth.mjs +38 -0
- package/dist/api/state/should-session-refresh.d.mts +12 -0
- package/dist/api/state/should-session-refresh.mjs +13 -0
- package/dist/api/to-auth-endpoints.mjs +60 -0
- package/dist/auth/base.mjs +66 -0
- package/dist/auth/full.d.mts +28 -0
- package/dist/auth/full.mjs +29 -0
- package/dist/auth/minimal.d.mts +10 -0
- package/dist/auth/minimal.mjs +11 -0
- package/dist/auth/trusted-origins.mjs +106 -0
- package/dist/client/broadcast-channel.d.mts +19 -0
- package/dist/client/broadcast-channel.mjs +44 -0
- package/dist/client/config.d.mts +90 -0
- package/dist/client/config.mjs +113 -0
- package/dist/client/equality.d.mts +19 -0
- package/dist/client/equality.mjs +42 -0
- package/dist/client/fetch-plugins.mjs +17 -0
- package/dist/client/focus-manager.d.mts +10 -0
- package/dist/client/focus-manager.mjs +30 -0
- package/dist/client/index.d.mts +35 -0
- package/dist/client/index.mjs +22 -0
- package/dist/client/lynx/index.d.mts +43 -0
- package/dist/client/lynx/index.mjs +22 -0
- package/dist/client/lynx/lynx-store.d.mts +46 -0
- package/dist/client/lynx/lynx-store.mjs +44 -0
- package/dist/client/online-manager.d.mts +11 -0
- package/dist/client/online-manager.mjs +33 -0
- package/dist/client/parser.d.mts +10 -0
- package/dist/client/parser.mjs +70 -0
- package/dist/client/path-to-object.d.mts +113 -0
- package/dist/client/plugins/index.d.mts +44 -0
- package/dist/client/plugins/index.mjs +30 -0
- package/dist/client/plugins/infer-plugin.d.mts +16 -0
- package/dist/client/plugins/infer-plugin.mjs +11 -0
- package/dist/client/proxy.mjs +78 -0
- package/dist/client/query.d.mts +23 -0
- package/dist/client/query.mjs +124 -0
- package/dist/client/react/index.d.mts +44 -0
- package/dist/client/react/index.mjs +22 -0
- package/dist/client/react/react-store.d.mts +46 -0
- package/dist/client/react/react-store.mjs +44 -0
- package/dist/client/session-atom.d.mts +11 -0
- package/dist/client/session-atom.mjs +178 -0
- package/dist/client/session-refresh.d.mts +20 -0
- package/dist/client/session-refresh.mjs +131 -0
- package/dist/client/solid/index.d.mts +44 -0
- package/dist/client/solid/index.mjs +22 -0
- package/dist/client/solid/solid-store.mjs +21 -0
- package/dist/client/svelte/index.d.mts +44 -0
- package/dist/client/svelte/index.mjs +18 -0
- package/dist/client/types.d.mts +51 -0
- package/dist/client/vanilla.d.mts +42 -0
- package/dist/client/vanilla.mjs +18 -0
- package/dist/client/vue/index.d.mts +67 -0
- package/dist/client/vue/index.mjs +54 -0
- package/dist/client/vue/vue-store.mjs +23 -0
- package/dist/context/create-context.mjs +235 -0
- package/dist/context/helpers.mjs +158 -0
- package/dist/context/init-minimal.mjs +17 -0
- package/dist/context/init.mjs +19 -0
- package/dist/context/secret-utils.mjs +53 -0
- package/dist/context/store-capabilities.mjs +12 -0
- package/dist/cookies/cache.mjs +33 -0
- package/dist/cookies/cookie-utils.d.mts +72 -0
- package/dist/cookies/cookie-utils.mjs +203 -0
- package/dist/cookies/index.d.mts +124 -0
- package/dist/cookies/index.mjs +350 -0
- package/dist/cookies/jwt.mjs +44 -0
- package/dist/cookies/session-store.d.mts +32 -0
- package/dist/cookies/session-store.mjs +183 -0
- package/dist/crypto/buffer.d.mts +7 -0
- package/dist/crypto/buffer.mjs +16 -0
- package/dist/crypto/index.d.mts +32 -0
- package/dist/crypto/index.mjs +69 -0
- package/dist/crypto/jwt.d.mts +9 -0
- package/dist/crypto/jwt.mjs +141 -0
- package/dist/crypto/password.d.mts +13 -0
- package/dist/crypto/password.mjs +14 -0
- package/dist/crypto/random.d.mts +4 -0
- package/dist/crypto/random.mjs +5 -0
- package/dist/db/adapter-base.d.mts +7 -0
- package/dist/db/adapter-base.mjs +25 -0
- package/dist/db/adapter-kysely.d.mts +7 -0
- package/dist/db/adapter-kysely.mjs +17 -0
- package/dist/db/field-converter.d.mts +7 -0
- package/dist/db/field-converter.mjs +19 -0
- package/dist/db/field.d.mts +41 -0
- package/dist/db/get-migration.d.mts +56 -0
- package/dist/db/get-migration.mjs +685 -0
- package/dist/db/get-schema.d.mts +13 -0
- package/dist/db/get-schema.mjs +39 -0
- package/dist/db/index.d.mts +10 -0
- package/dist/db/index.mjs +35 -0
- package/dist/db/internal-adapter.d.mts +14 -0
- package/dist/db/internal-adapter.mjs +951 -0
- package/dist/db/revoke-unproven-account-access.d.mts +21 -0
- package/dist/db/revoke-unproven-account-access.mjs +58 -0
- package/dist/db/schema.d.mts +62 -0
- package/dist/db/schema.mjs +161 -0
- package/dist/db/to-zod.d.mts +35 -0
- package/dist/db/to-zod.mjs +23 -0
- package/dist/db/verification-token-storage.mjs +25 -0
- package/dist/db/with-hooks.d.mts +37 -0
- package/dist/db/with-hooks.mjs +255 -0
- package/dist/index.d.mts +30 -0
- package/dist/index.mjs +17 -0
- package/dist/integrations/cookie-plugin-guard.mjs +18 -0
- package/dist/integrations/next-js.d.mts +29 -0
- package/dist/integrations/next-js.mjs +105 -0
- package/dist/integrations/node.d.mts +11 -0
- package/dist/integrations/node.mjs +13 -0
- package/dist/integrations/solid-start.d.mts +22 -0
- package/dist/integrations/solid-start.mjs +15 -0
- package/dist/integrations/svelte-kit.d.mts +38 -0
- package/dist/integrations/svelte-kit.mjs +57 -0
- package/dist/integrations/tanstack-start-solid.d.mts +33 -0
- package/dist/integrations/tanstack-start-solid.mjs +57 -0
- package/dist/integrations/tanstack-start.d.mts +33 -0
- package/dist/integrations/tanstack-start.mjs +57 -0
- package/dist/oauth2/account-key.mjs +43 -0
- package/dist/oauth2/errors.mjs +49 -0
- package/dist/oauth2/index.d.mts +5 -0
- package/dist/oauth2/index.mjs +5 -0
- package/dist/oauth2/link-account.d.mts +96 -0
- package/dist/oauth2/link-account.mjs +329 -0
- package/dist/oauth2/state.d.mts +54 -0
- package/dist/oauth2/state.mjs +67 -0
- package/dist/oauth2/utils.d.mts +11 -0
- package/dist/oauth2/utils.mjs +33 -0
- package/dist/package.mjs +4 -0
- package/dist/plugins/access/access.d.mts +17 -0
- package/dist/plugins/access/access.mjs +78 -0
- package/dist/plugins/access/index.d.mts +3 -0
- package/dist/plugins/access/index.mjs +2 -0
- package/dist/plugins/access/types.d.mts +24 -0
- package/dist/plugins/additional-fields/client.d.mts +100 -0
- package/dist/plugins/additional-fields/client.mjs +11 -0
- package/dist/plugins/admin/access/index.d.mts +2 -0
- package/dist/plugins/admin/access/index.mjs +2 -0
- package/dist/plugins/admin/access/statement.d.mts +51 -0
- package/dist/plugins/admin/access/statement.mjs +52 -0
- package/dist/plugins/admin/admin.d.mts +911 -0
- package/dist/plugins/admin/admin.mjs +89 -0
- package/dist/plugins/admin/client.d.mts +81 -0
- package/dist/plugins/admin/client.mjs +39 -0
- package/dist/plugins/admin/error-codes.d.mts +30 -0
- package/dist/plugins/admin/error-codes.mjs +29 -0
- package/dist/plugins/admin/has-permission.mjs +12 -0
- package/dist/plugins/admin/index.d.mts +3 -0
- package/dist/plugins/admin/index.mjs +2 -0
- package/dist/plugins/admin/routes.mjs +919 -0
- package/dist/plugins/admin/schema.d.mts +40 -0
- package/dist/plugins/admin/schema.mjs +33 -0
- package/dist/plugins/admin/types.d.mts +88 -0
- package/dist/plugins/anonymous/client.d.mts +32 -0
- package/dist/plugins/anonymous/client.mjs +21 -0
- package/dist/plugins/anonymous/error-codes.d.mts +15 -0
- package/dist/plugins/anonymous/error-codes.mjs +14 -0
- package/dist/plugins/anonymous/index.d.mts +175 -0
- package/dist/plugins/anonymous/index.mjs +219 -0
- package/dist/plugins/anonymous/schema.d.mts +15 -0
- package/dist/plugins/anonymous/schema.mjs +9 -0
- package/dist/plugins/anonymous/types.d.mts +65 -0
- package/dist/plugins/bearer/index.d.mts +45 -0
- package/dist/plugins/bearer/index.mjs +74 -0
- package/dist/plugins/captcha/constants.d.mts +9 -0
- package/dist/plugins/captcha/constants.mjs +27 -0
- package/dist/plugins/captcha/error-codes.mjs +13 -0
- package/dist/plugins/captcha/index.d.mts +27 -0
- package/dist/plugins/captcha/index.mjs +79 -0
- package/dist/plugins/captcha/types.d.mts +52 -0
- package/dist/plugins/captcha/utils.mjs +9 -0
- package/dist/plugins/captcha/verify-handlers/captchafox.mjs +27 -0
- package/dist/plugins/captcha/verify-handlers/cloudflare-turnstile.mjs +47 -0
- package/dist/plugins/captcha/verify-handlers/google-recaptcha.mjs +32 -0
- package/dist/plugins/captcha/verify-handlers/h-captcha.mjs +27 -0
- package/dist/plugins/custom-session/client.d.mts +17 -0
- package/dist/plugins/custom-session/client.mjs +7 -0
- package/dist/plugins/custom-session/index.d.mts +73 -0
- package/dist/plugins/custom-session/index.mjs +65 -0
- package/dist/plugins/device-authorization/client.d.mts +17 -0
- package/dist/plugins/device-authorization/client.mjs +18 -0
- package/dist/plugins/device-authorization/error-codes.mjs +19 -0
- package/dist/plugins/device-authorization/index.d.mts +558 -0
- package/dist/plugins/device-authorization/index.mjs +87 -0
- package/dist/plugins/device-authorization/routes.d.mts +32 -0
- package/dist/plugins/device-authorization/routes.mjs +725 -0
- package/dist/plugins/device-authorization/schema.d.mts +18 -0
- package/dist/plugins/device-authorization/schema.mjs +63 -0
- package/dist/plugins/email-otp/client.d.mts +21 -0
- package/dist/plugins/email-otp/client.mjs +17 -0
- package/dist/plugins/email-otp/error-codes.d.mts +10 -0
- package/dist/plugins/email-otp/error-codes.mjs +9 -0
- package/dist/plugins/email-otp/index.d.mts +551 -0
- package/dist/plugins/email-otp/index.mjs +145 -0
- package/dist/plugins/email-otp/otp-token.mjs +55 -0
- package/dist/plugins/email-otp/routes.mjs +784 -0
- package/dist/plugins/email-otp/types.d.mts +109 -0
- package/dist/plugins/email-otp/utils.mjs +17 -0
- package/dist/plugins/generic-oauth/error-codes.mjs +8 -0
- package/dist/plugins/generic-oauth/index.d.mts +52 -0
- package/dist/plugins/generic-oauth/index.mjs +279 -0
- package/dist/plugins/generic-oauth/providers/auth0.d.mts +36 -0
- package/dist/plugins/generic-oauth/providers/auth0.mjs +49 -0
- package/dist/plugins/generic-oauth/providers/gumroad.d.mts +31 -0
- package/dist/plugins/generic-oauth/providers/gumroad.mjs +62 -0
- package/dist/plugins/generic-oauth/providers/hubspot.d.mts +36 -0
- package/dist/plugins/generic-oauth/providers/hubspot.mjs +62 -0
- package/dist/plugins/generic-oauth/providers/index.d.mts +10 -0
- package/dist/plugins/generic-oauth/providers/keycloak.d.mts +36 -0
- package/dist/plugins/generic-oauth/providers/keycloak.mjs +47 -0
- package/dist/plugins/generic-oauth/providers/line.d.mts +54 -0
- package/dist/plugins/generic-oauth/providers/line.mjs +93 -0
- package/dist/plugins/generic-oauth/providers/microsoft-entra-id.d.mts +39 -0
- package/dist/plugins/generic-oauth/providers/microsoft-entra-id.mjs +104 -0
- package/dist/plugins/generic-oauth/providers/okta.d.mts +36 -0
- package/dist/plugins/generic-oauth/providers/okta.mjs +47 -0
- package/dist/plugins/generic-oauth/providers/patreon.d.mts +29 -0
- package/dist/plugins/generic-oauth/providers/patreon.mjs +61 -0
- package/dist/plugins/generic-oauth/providers/slack.d.mts +29 -0
- package/dist/plugins/generic-oauth/providers/slack.mjs +63 -0
- package/dist/plugins/generic-oauth/providers/yandex.d.mts +29 -0
- package/dist/plugins/generic-oauth/providers/yandex.mjs +67 -0
- package/dist/plugins/generic-oauth/types.d.mts +268 -0
- package/dist/plugins/haveibeenpwned/index.d.mts +63 -0
- package/dist/plugins/haveibeenpwned/index.mjs +81 -0
- package/dist/plugins/index.d.mts +69 -0
- package/dist/plugins/index.mjs +49 -0
- package/dist/plugins/jwt/adapter.mjs +68 -0
- package/dist/plugins/jwt/client.d.mts +41 -0
- package/dist/plugins/jwt/client.mjs +19 -0
- package/dist/plugins/jwt/cookie-cache.mjs +77 -0
- package/dist/plugins/jwt/index.d.mts +246 -0
- package/dist/plugins/jwt/index.mjs +214 -0
- package/dist/plugins/jwt/schema.d.mts +33 -0
- package/dist/plugins/jwt/schema.mjs +29 -0
- package/dist/plugins/jwt/sign.d.mts +128 -0
- package/dist/plugins/jwt/sign.mjs +130 -0
- package/dist/plugins/jwt/types.d.mts +256 -0
- package/dist/plugins/jwt/utils.d.mts +41 -0
- package/dist/plugins/jwt/utils.mjs +64 -0
- package/dist/plugins/jwt/verify.d.mts +11 -0
- package/dist/plugins/jwt/verify.mjs +45 -0
- package/dist/plugins/last-login-method/client.d.mts +48 -0
- package/dist/plugins/last-login-method/client.mjs +48 -0
- package/dist/plugins/last-login-method/index.d.mts +127 -0
- package/dist/plugins/last-login-method/index.mjs +98 -0
- package/dist/plugins/magic-link/client.d.mts +10 -0
- package/dist/plugins/magic-link/client.mjs +11 -0
- package/dist/plugins/magic-link/index.d.mts +213 -0
- package/dist/plugins/magic-link/index.mjs +208 -0
- package/dist/plugins/magic-link/utils.mjs +9 -0
- package/dist/plugins/multi-session/client.d.mts +19 -0
- package/dist/plugins/multi-session/client.mjs +19 -0
- package/dist/plugins/multi-session/error-codes.d.mts +8 -0
- package/dist/plugins/multi-session/error-codes.mjs +5 -0
- package/dist/plugins/multi-session/index.d.mts +212 -0
- package/dist/plugins/multi-session/index.mjs +217 -0
- package/dist/plugins/oauth-popup/client.d.mts +82 -0
- package/dist/plugins/oauth-popup/client.mjs +203 -0
- package/dist/plugins/oauth-popup/constants.d.mts +11 -0
- package/dist/plugins/oauth-popup/constants.mjs +11 -0
- package/dist/plugins/oauth-popup/error-codes.d.mts +11 -0
- package/dist/plugins/oauth-popup/error-codes.mjs +10 -0
- package/dist/plugins/oauth-popup/index.d.mts +67 -0
- package/dist/plugins/oauth-popup/index.mjs +232 -0
- package/dist/plugins/oauth-popup/types.d.mts +30 -0
- package/dist/plugins/oauth-proxy/index.d.mts +130 -0
- package/dist/plugins/oauth-proxy/index.mjs +407 -0
- package/dist/plugins/oauth-proxy/utils.mjs +55 -0
- package/dist/plugins/one-tap/client.d.mts +174 -0
- package/dist/plugins/one-tap/client.mjs +208 -0
- package/dist/plugins/one-tap/index.d.mts +82 -0
- package/dist/plugins/one-tap/index.mjs +100 -0
- package/dist/plugins/one-time-token/client.d.mts +10 -0
- package/dist/plugins/one-time-token/client.mjs +11 -0
- package/dist/plugins/one-time-token/index.d.mts +132 -0
- package/dist/plugins/one-time-token/index.mjs +107 -0
- package/dist/plugins/one-time-token/utils.mjs +9 -0
- package/dist/plugins/open-api/generator.d.mts +126 -0
- package/dist/plugins/open-api/generator.mjs +557 -0
- package/dist/plugins/open-api/index.d.mts +97 -0
- package/dist/plugins/open-api/index.mjs +65 -0
- package/dist/plugins/open-api/logo.mjs +13 -0
- package/dist/plugins/organization/access/index.d.mts +2 -0
- package/dist/plugins/organization/access/index.mjs +2 -0
- package/dist/plugins/organization/access/statement.d.mts +113 -0
- package/dist/plugins/organization/access/statement.mjs +77 -0
- package/dist/plugins/organization/adapter.d.mts +815 -0
- package/dist/plugins/organization/adapter.mjs +813 -0
- package/dist/plugins/organization/call.mjs +15 -0
- package/dist/plugins/organization/client.d.mts +375 -0
- package/dist/plugins/organization/client.mjs +104 -0
- package/dist/plugins/organization/error-codes.d.mts +66 -0
- package/dist/plugins/organization/error-codes.mjs +65 -0
- package/dist/plugins/organization/has-permission.d.mts +17 -0
- package/dist/plugins/organization/has-permission.mjs +34 -0
- package/dist/plugins/organization/index.d.mts +6 -0
- package/dist/plugins/organization/index.mjs +4 -0
- package/dist/plugins/organization/organization.d.mts +420 -0
- package/dist/plugins/organization/organization.mjs +886 -0
- package/dist/plugins/organization/permission.d.mts +15 -0
- package/dist/plugins/organization/permission.mjs +14 -0
- package/dist/plugins/organization/routes/crud-access-control.d.mts +511 -0
- package/dist/plugins/organization/routes/crud-access-control.mjs +674 -0
- package/dist/plugins/organization/routes/crud-invites.d.mts +1154 -0
- package/dist/plugins/organization/routes/crud-invites.mjs +602 -0
- package/dist/plugins/organization/routes/crud-members.d.mts +1057 -0
- package/dist/plugins/organization/routes/crud-members.mjs +518 -0
- package/dist/plugins/organization/routes/crud-org.d.mts +918 -0
- package/dist/plugins/organization/routes/crud-org.mjs +455 -0
- package/dist/plugins/organization/routes/crud-team.d.mts +1238 -0
- package/dist/plugins/organization/routes/crud-team.mjs +766 -0
- package/dist/plugins/organization/schema.d.mts +390 -0
- package/dist/plugins/organization/schema.mjs +65 -0
- package/dist/plugins/organization/types.d.mts +691 -0
- package/dist/plugins/phone-number/client.d.mts +31 -0
- package/dist/plugins/phone-number/client.mjs +19 -0
- package/dist/plugins/phone-number/error-codes.d.mts +19 -0
- package/dist/plugins/phone-number/error-codes.mjs +18 -0
- package/dist/plugins/phone-number/index.d.mts +360 -0
- package/dist/plugins/phone-number/index.mjs +57 -0
- package/dist/plugins/phone-number/routes.mjs +529 -0
- package/dist/plugins/phone-number/schema.d.mts +22 -0
- package/dist/plugins/phone-number/schema.mjs +18 -0
- package/dist/plugins/phone-number/types.d.mts +116 -0
- package/dist/plugins/siwe/client.d.mts +14 -0
- package/dist/plugins/siwe/client.mjs +15 -0
- package/dist/plugins/siwe/index.d.mts +62 -0
- package/dist/plugins/siwe/index.mjs +272 -0
- package/dist/plugins/siwe/parse-message.mjs +60 -0
- package/dist/plugins/siwe/schema.d.mts +35 -0
- package/dist/plugins/siwe/schema.mjs +30 -0
- package/dist/plugins/siwe/types.d.mts +43 -0
- package/dist/plugins/test-utils/auth-helpers.mjs +33 -0
- package/dist/plugins/test-utils/cookie-builder.mjs +55 -0
- package/dist/plugins/test-utils/db-helpers.mjs +65 -0
- package/dist/plugins/test-utils/factories.mjs +38 -0
- package/dist/plugins/test-utils/index.d.mts +73 -0
- package/dist/plugins/test-utils/index.mjs +97 -0
- package/dist/plugins/test-utils/otp-sink.mjs +21 -0
- package/dist/plugins/test-utils/types.d.mts +51 -0
- package/dist/plugins/two-factor/backup-codes/index.d.mts +291 -0
- package/dist/plugins/two-factor/backup-codes/index.mjs +341 -0
- package/dist/plugins/two-factor/client.d.mts +76 -0
- package/dist/plugins/two-factor/client.mjs +41 -0
- package/dist/plugins/two-factor/constant.mjs +6 -0
- package/dist/plugins/two-factor/error-code.d.mts +20 -0
- package/dist/plugins/two-factor/error-code.mjs +19 -0
- package/dist/plugins/two-factor/index.d.mts +720 -0
- package/dist/plugins/two-factor/index.mjs +349 -0
- package/dist/plugins/two-factor/otp/index.d.mts +216 -0
- package/dist/plugins/two-factor/otp/index.mjs +252 -0
- package/dist/plugins/two-factor/schema.d.mts +59 -0
- package/dist/plugins/two-factor/schema.mjs +53 -0
- package/dist/plugins/two-factor/totp/index.d.mts +219 -0
- package/dist/plugins/two-factor/totp/index.mjs +230 -0
- package/dist/plugins/two-factor/types.d.mts +111 -0
- package/dist/plugins/two-factor/utils.mjs +9 -0
- package/dist/plugins/two-factor/verify-two-factor.mjs +205 -0
- package/dist/plugins/username/client.d.mts +38 -0
- package/dist/plugins/username/client.mjs +17 -0
- package/dist/plugins/username/error-codes.d.mts +16 -0
- package/dist/plugins/username/error-codes.mjs +15 -0
- package/dist/plugins/username/index.d.mts +326 -0
- package/dist/plugins/username/index.mjs +312 -0
- package/dist/plugins/username/schema.d.mts +50 -0
- package/dist/plugins/username/schema.mjs +25 -0
- package/dist/social-providers/index.d.mts +1 -0
- package/dist/social-providers/index.mjs +2 -0
- package/dist/state.d.mts +48 -0
- package/dist/state.mjs +149 -0
- package/dist/test-utils/headers.d.mts +8 -0
- package/dist/test-utils/headers.mjs +17 -0
- package/dist/test-utils/http-test-instance.d.mts +413 -0
- package/dist/test-utils/http-test-instance.mjs +107 -0
- package/dist/test-utils/index.d.mts +4 -0
- package/dist/test-utils/index.mjs +4 -0
- package/dist/test-utils/test-instance.d.mts +56 -0
- package/dist/test-utils/test-instance.mjs +242 -0
- package/dist/types/adapter.d.mts +2 -0
- package/dist/types/api.d.mts +28 -0
- package/dist/types/auth.d.mts +32 -0
- package/dist/types/helper.d.mts +26 -0
- package/dist/types/index.d.mts +10 -0
- package/dist/types/index.mjs +1 -0
- package/dist/types/models.d.mts +10 -0
- package/dist/types/plugins.d.mts +19 -0
- package/dist/utils/boolean.mjs +6 -0
- package/dist/utils/constants.mjs +4 -0
- package/dist/utils/date.mjs +6 -0
- package/dist/utils/hashing.mjs +18 -0
- package/dist/utils/hide-metadata.d.mts +6 -0
- package/dist/utils/hide-metadata.mjs +4 -0
- package/dist/utils/index.d.mts +4 -0
- package/dist/utils/is-api-error.d.mts +2 -0
- package/dist/utils/is-api-error.mjs +2 -0
- package/dist/utils/is-atom.mjs +6 -0
- package/dist/utils/is-promise.mjs +6 -0
- package/dist/utils/middleware-response.mjs +7 -0
- package/dist/utils/password.mjs +32 -0
- package/dist/utils/plugin-helper.mjs +14 -0
- package/dist/utils/request.mjs +23 -0
- package/dist/utils/shim.mjs +22 -0
- package/dist/utils/time.d.mts +48 -0
- package/dist/utils/time.mjs +98 -0
- package/dist/utils/url.d.mts +78 -0
- package/dist/utils/url.mjs +238 -0
- package/dist/utils/validate-user-info.mjs +44 -0
- package/dist/utils/wildcard.mjs +106 -0
- package/dist/version.mjs +5 -0
- package/package.json +595 -3
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { parseCookieCachePayload } from "./cache.mjs";
|
|
2
|
+
import { decodeProtectedHeader, importJWK, jwtVerify } from "jose";
|
|
3
|
+
//#region src/cookies/jwt.ts
|
|
4
|
+
const SESSION_COOKIE_JWT_TYPE = "better-auth.session-cache+jwt";
|
|
5
|
+
const SESSION_COOKIE_JWT_AUDIENCE = "better-auth:session-cache";
|
|
6
|
+
const SESSION_COOKIE_JWT_ISSUER = "better-auth:session-cache";
|
|
7
|
+
function getSessionCookieJwtVerifyOptions(options) {
|
|
8
|
+
const verifyOptions = {
|
|
9
|
+
clockTolerance: 15,
|
|
10
|
+
audience: options?.audience ?? "better-auth:session-cache"
|
|
11
|
+
};
|
|
12
|
+
if (options?.issuer) verifyOptions.issuer = options.issuer;
|
|
13
|
+
return verifyOptions;
|
|
14
|
+
}
|
|
15
|
+
function parseSessionCookieJwtPayload(payload) {
|
|
16
|
+
const data = parseCookieCachePayload(payload);
|
|
17
|
+
if (!data || typeof payload.iss !== "string" || !payload.iss) return null;
|
|
18
|
+
if (payload.sub !== data.user.id || payload.sid !== data.session.token) return null;
|
|
19
|
+
return {
|
|
20
|
+
...payload,
|
|
21
|
+
...data
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
async function verifySessionCookieJwtWithJwks(token, jwks, options) {
|
|
25
|
+
try {
|
|
26
|
+
const header = decodeProtectedHeader(token);
|
|
27
|
+
if (header.typ !== "better-auth.session-cache+jwt") return null;
|
|
28
|
+
const kid = header.kid;
|
|
29
|
+
if (!kid) return null;
|
|
30
|
+
const key = jwks.keys.find((entry) => entry.kid === kid);
|
|
31
|
+
if (!key) return null;
|
|
32
|
+
const alg = key.alg ?? header.alg;
|
|
33
|
+
if (!alg) return null;
|
|
34
|
+
const { payload } = await jwtVerify(token, await importJWK(key, alg), {
|
|
35
|
+
...getSessionCookieJwtVerifyOptions(options),
|
|
36
|
+
algorithms: [alg]
|
|
37
|
+
});
|
|
38
|
+
return parseSessionCookieJwtPayload(payload);
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { SESSION_COOKIE_JWT_AUDIENCE, SESSION_COOKIE_JWT_ISSUER, SESSION_COOKIE_JWT_TYPE, getSessionCookieJwtVerifyOptions, parseSessionCookieJwtPayload, verifySessionCookieJwtWithJwks };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { GenericEndpointContext } from "@better-auth/core";
|
|
2
|
+
import { CookieOptions } from "better-call";
|
|
3
|
+
//#region src/cookies/session-store.d.ts
|
|
4
|
+
interface Cookie {
|
|
5
|
+
name: string;
|
|
6
|
+
value: string;
|
|
7
|
+
attributes: CookieOptions;
|
|
8
|
+
}
|
|
9
|
+
declare const createSessionStore: (cookieName: string, cookieOptions: CookieOptions, ctx: GenericEndpointContext) => {
|
|
10
|
+
chunk(value: string, options?: Partial<CookieOptions>): Cookie[];
|
|
11
|
+
clean(): Cookie[];
|
|
12
|
+
setCookies(cookies: Cookie[]): void;
|
|
13
|
+
};
|
|
14
|
+
declare function getChunkedCookie(ctx: GenericEndpointContext, cookieName: string): string | null;
|
|
15
|
+
declare function setAccountCookie(c: GenericEndpointContext, accountData: Record<string, any>): Promise<void>;
|
|
16
|
+
declare function getAccountCookie(c: GenericEndpointContext): Promise<{
|
|
17
|
+
id: string;
|
|
18
|
+
createdAt: Date;
|
|
19
|
+
updatedAt: Date;
|
|
20
|
+
providerId: string;
|
|
21
|
+
accountId: string;
|
|
22
|
+
userId: string;
|
|
23
|
+
accessToken?: string | null | undefined;
|
|
24
|
+
refreshToken?: string | null | undefined;
|
|
25
|
+
idToken?: string | null | undefined;
|
|
26
|
+
accessTokenExpiresAt?: Date | null | undefined;
|
|
27
|
+
refreshTokenExpiresAt?: Date | null | undefined;
|
|
28
|
+
scope?: string | null | undefined;
|
|
29
|
+
password?: string | null | undefined;
|
|
30
|
+
} | null>;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { createSessionStore, getAccountCookie, getChunkedCookie, setAccountCookie };
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { symmetricDecodeJWT, symmetricEncodeJWT } from "../crypto/jwt.mjs";
|
|
2
|
+
import { parseCookies } from "./cookie-utils.mjs";
|
|
3
|
+
import { safeJSONParse } from "@better-auth/core/utils/json";
|
|
4
|
+
import { serializeCookie } from "better-call";
|
|
5
|
+
import * as z from "zod";
|
|
6
|
+
//#region src/cookies/session-store.ts
|
|
7
|
+
/**
|
|
8
|
+
* Per-cookie byte ceiling.
|
|
9
|
+
* Safari's ~4093 floor is the lowest among browsers.
|
|
10
|
+
* Kept a little under it for attributes added after sizing.
|
|
11
|
+
*
|
|
12
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6265#section-6.1
|
|
13
|
+
* @see https://github.com/dotnet/aspnetcore/blob/aa5493528640932601bb82ef3295e4d8ca7e11c5/src/Shared/ChunkingCookieManager/ChunkingCookieManager.cs#L40
|
|
14
|
+
*/
|
|
15
|
+
const MAX_COOKIE_SIZE = 4050;
|
|
16
|
+
/**
|
|
17
|
+
* Max chunks per cookie.
|
|
18
|
+
* A larger value does not belong in a cookie.
|
|
19
|
+
*/
|
|
20
|
+
const MAX_COOKIE_CHUNKS = 100;
|
|
21
|
+
/**
|
|
22
|
+
* Largest value that keeps the serialized cookie within {@link MAX_COOKIE_SIZE},
|
|
23
|
+
* measured with the real `serializeCookie` writer so it stays in sync with the
|
|
24
|
+
* wire. Non-positive when the name and attributes alone overflow.
|
|
25
|
+
*/
|
|
26
|
+
function getMaxCookieValueSize(name, options) {
|
|
27
|
+
return MAX_COOKIE_SIZE - serializeCookie(name, "", { ...options }).length;
|
|
28
|
+
}
|
|
29
|
+
function parseCookieChunkIndex(cookieName, name) {
|
|
30
|
+
const prefix = `${cookieName}.`;
|
|
31
|
+
if (!name.startsWith(prefix)) return null;
|
|
32
|
+
const suffix = name.slice(prefix.length);
|
|
33
|
+
const index = Number(suffix);
|
|
34
|
+
if (!Number.isSafeInteger(index) || index < 0 || String(index) !== suffix) return null;
|
|
35
|
+
return index;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Read all existing chunks from cookies
|
|
39
|
+
*/
|
|
40
|
+
function readExistingChunks(cookieName, ctx) {
|
|
41
|
+
const chunks = {};
|
|
42
|
+
const cookies = parseCookies(ctx.headers?.get("cookie") || "");
|
|
43
|
+
for (const [name, value] of cookies) {
|
|
44
|
+
if (name !== cookieName && parseCookieChunkIndex(cookieName, name) === null) continue;
|
|
45
|
+
chunks[name] = value;
|
|
46
|
+
}
|
|
47
|
+
return chunks;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Split a cookie value into chunks if needed
|
|
51
|
+
*/
|
|
52
|
+
function chunkCookie(storeName, cookie, chunks, logger) {
|
|
53
|
+
const chunkSize = getMaxCookieValueSize(`${cookie.name}.${MAX_COOKIE_CHUNKS - 1}`, cookie.attributes);
|
|
54
|
+
const chunkCount = chunkSize > 0 ? Math.ceil(cookie.value.length / chunkSize) : Infinity;
|
|
55
|
+
if (chunkCount <= 1) {
|
|
56
|
+
chunks[cookie.name] = cookie.value;
|
|
57
|
+
return [cookie];
|
|
58
|
+
}
|
|
59
|
+
if (chunkCount > MAX_COOKIE_CHUNKS) {
|
|
60
|
+
logger.warn(`${storeName} cookie is too large to store even after chunking, so the cookie cache was skipped. Reduce the cached data size or avoid storing this data in cookies.`);
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
const cookies = [];
|
|
64
|
+
for (let i = 0; i < chunkCount; i++) {
|
|
65
|
+
const name = `${cookie.name}.${i}`;
|
|
66
|
+
const start = i * chunkSize;
|
|
67
|
+
const value = cookie.value.substring(start, start + chunkSize);
|
|
68
|
+
cookies.push({
|
|
69
|
+
...cookie,
|
|
70
|
+
name,
|
|
71
|
+
value
|
|
72
|
+
});
|
|
73
|
+
chunks[name] = value;
|
|
74
|
+
}
|
|
75
|
+
logger.debug(`CHUNKING_${storeName.toUpperCase()}_COOKIE`, {
|
|
76
|
+
message: `${storeName} cookie exceeds the ${MAX_COOKIE_SIZE} byte limit and was split into ${chunkCount} chunks.`,
|
|
77
|
+
valueSize: cookie.value.length,
|
|
78
|
+
chunkCount,
|
|
79
|
+
chunkSizes: cookies.map((c) => c.value.length)
|
|
80
|
+
});
|
|
81
|
+
return cookies;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get all cookies that should be cleaned (removed)
|
|
85
|
+
*/
|
|
86
|
+
function getCleanCookies(chunks, cookieOptions) {
|
|
87
|
+
const cleanedChunks = {};
|
|
88
|
+
for (const name in chunks) cleanedChunks[name] = {
|
|
89
|
+
name,
|
|
90
|
+
value: "",
|
|
91
|
+
attributes: {
|
|
92
|
+
...cookieOptions,
|
|
93
|
+
maxAge: 0
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
return cleanedChunks;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Store that splits a cookie into numbered chunks when its serialized form
|
|
100
|
+
* would exceed the per-cookie byte limit, expiring stale chunks as needed.
|
|
101
|
+
*
|
|
102
|
+
* @see https://github.com/nextauthjs/next-auth/blob/27b2519b84b8eb9cf053775dea29d577d2aa0098/packages/next-auth/src/core/lib/cookie.ts
|
|
103
|
+
*/
|
|
104
|
+
const storeFactory = (storeName) => (cookieName, cookieOptions, ctx) => {
|
|
105
|
+
const chunks = readExistingChunks(cookieName, ctx);
|
|
106
|
+
const logger = ctx.context.logger;
|
|
107
|
+
const expireExistingChunks = () => {
|
|
108
|
+
const expired = getCleanCookies(chunks, cookieOptions);
|
|
109
|
+
for (const name in chunks) delete chunks[name];
|
|
110
|
+
return expired;
|
|
111
|
+
};
|
|
112
|
+
return {
|
|
113
|
+
chunk(value, options) {
|
|
114
|
+
const cookies = expireExistingChunks();
|
|
115
|
+
const chunked = chunkCookie(storeName, {
|
|
116
|
+
name: cookieName,
|
|
117
|
+
value,
|
|
118
|
+
attributes: {
|
|
119
|
+
...cookieOptions,
|
|
120
|
+
...options
|
|
121
|
+
}
|
|
122
|
+
}, chunks, logger);
|
|
123
|
+
for (const chunk of chunked) cookies[chunk.name] = chunk;
|
|
124
|
+
return Object.values(cookies);
|
|
125
|
+
},
|
|
126
|
+
clean() {
|
|
127
|
+
return Object.values(expireExistingChunks());
|
|
128
|
+
},
|
|
129
|
+
setCookies(cookies) {
|
|
130
|
+
for (const cookie of cookies) ctx.setCookie(cookie.name, cookie.value, cookie.attributes);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
const createSessionStore = storeFactory("Session");
|
|
135
|
+
const createAccountStore = storeFactory("Account");
|
|
136
|
+
function getChunkedCookie(ctx, cookieName) {
|
|
137
|
+
const value = ctx.getCookie(cookieName);
|
|
138
|
+
if (value) return value;
|
|
139
|
+
const chunks = [];
|
|
140
|
+
const cookieHeader = ctx.headers?.get("cookie");
|
|
141
|
+
if (!cookieHeader) return null;
|
|
142
|
+
for (const [name, val] of parseCookies(cookieHeader)) {
|
|
143
|
+
const index = parseCookieChunkIndex(cookieName, name);
|
|
144
|
+
if (index === null) continue;
|
|
145
|
+
chunks.push({
|
|
146
|
+
index,
|
|
147
|
+
value: val
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
if (chunks.length > 0) {
|
|
151
|
+
chunks.sort((a, b) => a.index - b.index);
|
|
152
|
+
return chunks.map((c) => c.value).join("");
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
async function setAccountCookie(c, accountData) {
|
|
157
|
+
const accountDataCookie = c.context.authCookies.accountData;
|
|
158
|
+
const options = {
|
|
159
|
+
maxAge: 300,
|
|
160
|
+
...accountDataCookie.attributes
|
|
161
|
+
};
|
|
162
|
+
const data = await symmetricEncodeJWT(accountData, c.context.secretConfig, "better-auth-account", options.maxAge);
|
|
163
|
+
const accountStore = createAccountStore(accountDataCookie.name, options, c);
|
|
164
|
+
accountStore.setCookies(accountStore.chunk(data, options));
|
|
165
|
+
}
|
|
166
|
+
async function getAccountCookie(c) {
|
|
167
|
+
const accountCookie = getChunkedCookie(c, c.context.authCookies.accountData.name);
|
|
168
|
+
if (accountCookie) {
|
|
169
|
+
const accountData = safeJSONParse(await symmetricDecodeJWT(accountCookie, c.context.secretConfig, "better-auth-account"));
|
|
170
|
+
if (accountData) return accountData;
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
const getSessionQuerySchema = z.optional(z.object({
|
|
175
|
+
/**
|
|
176
|
+
* If cookie cache is enabled, it will disable the cache
|
|
177
|
+
* and fetch the session from the database
|
|
178
|
+
*/
|
|
179
|
+
disableCookieCache: z.coerce.boolean().meta({ description: "Disable cookie cache and fetch session from database" }).optional(),
|
|
180
|
+
disableRefresh: z.coerce.boolean().meta({ description: "Disable session refresh. Useful for checking session status, without updating the session" }).optional()
|
|
181
|
+
}));
|
|
182
|
+
//#endregion
|
|
183
|
+
export { createAccountStore, createSessionStore, getAccountCookie, getChunkedCookie, getSessionQuerySchema, setAccountCookie };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/crypto/buffer.ts
|
|
2
|
+
/**
|
|
3
|
+
* Compare two buffers in constant time.
|
|
4
|
+
*/
|
|
5
|
+
function constantTimeEqual(a, b) {
|
|
6
|
+
if (typeof a === "string") a = new TextEncoder().encode(a);
|
|
7
|
+
if (typeof b === "string") b = new TextEncoder().encode(b);
|
|
8
|
+
const aBuffer = new Uint8Array(a);
|
|
9
|
+
const bBuffer = new Uint8Array(b);
|
|
10
|
+
let c = aBuffer.length ^ bBuffer.length;
|
|
11
|
+
const length = Math.max(aBuffer.length, bBuffer.length);
|
|
12
|
+
for (let i = 0; i < length; i++) c |= (i < aBuffer.length ? aBuffer[i] : 0) ^ (i < bBuffer.length ? bBuffer[i] : 0);
|
|
13
|
+
return c === 0;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { constantTimeEqual };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { constantTimeEqual } from "./buffer.mjs";
|
|
2
|
+
import { signJWT, symmetricDecodeJWT, symmetricEncodeJWT, verifyJWT } from "./jwt.mjs";
|
|
3
|
+
import { hashPassword, verifyPassword } from "./password.mjs";
|
|
4
|
+
import { generateRandomString } from "./random.mjs";
|
|
5
|
+
import { SecretConfig } from "@better-auth/core";
|
|
6
|
+
|
|
7
|
+
//#region src/crypto/index.d.ts
|
|
8
|
+
declare function parseEnvelope(data: string): {
|
|
9
|
+
version: number;
|
|
10
|
+
ciphertext: string;
|
|
11
|
+
} | null;
|
|
12
|
+
declare function formatEnvelope(version: number, ciphertext: string): string;
|
|
13
|
+
type SymmetricEncryptOptions = {
|
|
14
|
+
key: string | SecretConfig;
|
|
15
|
+
data: string;
|
|
16
|
+
};
|
|
17
|
+
declare const symmetricEncrypt: ({
|
|
18
|
+
key,
|
|
19
|
+
data
|
|
20
|
+
}: SymmetricEncryptOptions) => Promise<string>;
|
|
21
|
+
type SymmetricDecryptOptions = {
|
|
22
|
+
key: string | SecretConfig;
|
|
23
|
+
data: string;
|
|
24
|
+
};
|
|
25
|
+
declare const symmetricDecrypt: ({
|
|
26
|
+
key,
|
|
27
|
+
data
|
|
28
|
+
}: SymmetricDecryptOptions) => Promise<string>;
|
|
29
|
+
declare const getCryptoKey: (secret: string | BufferSource) => Promise<CryptoKey>;
|
|
30
|
+
declare const makeSignature: (value: string, secret: string | BufferSource) => Promise<string>;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { type SecretConfig, SymmetricDecryptOptions, SymmetricEncryptOptions, constantTimeEqual, formatEnvelope, generateRandomString, getCryptoKey, hashPassword, makeSignature, parseEnvelope, signJWT, symmetricDecodeJWT, symmetricDecrypt, symmetricEncodeJWT, symmetricEncrypt, verifyJWT, verifyPassword };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { signJWT, symmetricDecodeJWT, symmetricEncodeJWT, verifyJWT } from "./jwt.mjs";
|
|
2
|
+
import { constantTimeEqual } from "./buffer.mjs";
|
|
3
|
+
import { hashPassword, verifyPassword } from "./password.mjs";
|
|
4
|
+
import { generateRandomString } from "./random.mjs";
|
|
5
|
+
import { getWebcryptoSubtle } from "@better-auth/utils";
|
|
6
|
+
import { createHash } from "@better-auth/utils/hash";
|
|
7
|
+
import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
|
|
8
|
+
import { bytesToHex, hexToBytes, managedNonce, utf8ToBytes } from "@noble/ciphers/utils.js";
|
|
9
|
+
//#region src/crypto/index.ts
|
|
10
|
+
const algorithm = {
|
|
11
|
+
name: "HMAC",
|
|
12
|
+
hash: "SHA-256"
|
|
13
|
+
};
|
|
14
|
+
const ENVELOPE_PREFIX = "$ba$";
|
|
15
|
+
function parseEnvelope(data) {
|
|
16
|
+
if (!data.startsWith(ENVELOPE_PREFIX)) return null;
|
|
17
|
+
const firstSep = 4;
|
|
18
|
+
const secondSep = data.indexOf("$", firstSep);
|
|
19
|
+
if (secondSep === -1) return null;
|
|
20
|
+
const version = parseInt(data.slice(firstSep, secondSep), 10);
|
|
21
|
+
if (!Number.isInteger(version) || version < 0) return null;
|
|
22
|
+
return {
|
|
23
|
+
version,
|
|
24
|
+
ciphertext: data.slice(secondSep + 1)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function formatEnvelope(version, ciphertext) {
|
|
28
|
+
return `${ENVELOPE_PREFIX}${version}$${ciphertext}`;
|
|
29
|
+
}
|
|
30
|
+
async function rawEncrypt(secret, data) {
|
|
31
|
+
const keyAsBytes = await createHash("SHA-256").digest(secret);
|
|
32
|
+
const dataAsBytes = utf8ToBytes(data);
|
|
33
|
+
return bytesToHex(managedNonce(xchacha20poly1305)(new Uint8Array(keyAsBytes)).encrypt(dataAsBytes));
|
|
34
|
+
}
|
|
35
|
+
async function rawDecrypt(secret, hex) {
|
|
36
|
+
const keyAsBytes = await createHash("SHA-256").digest(secret);
|
|
37
|
+
const dataAsBytes = hexToBytes(hex);
|
|
38
|
+
const chacha = managedNonce(xchacha20poly1305)(new Uint8Array(keyAsBytes));
|
|
39
|
+
return new TextDecoder().decode(chacha.decrypt(dataAsBytes));
|
|
40
|
+
}
|
|
41
|
+
const symmetricEncrypt = async ({ key, data }) => {
|
|
42
|
+
if (typeof key === "string") return rawEncrypt(key, data);
|
|
43
|
+
const secret = key.keys.get(key.currentVersion);
|
|
44
|
+
if (!secret) throw new Error(`Secret version ${key.currentVersion} not found in keys`);
|
|
45
|
+
const ciphertext = await rawEncrypt(secret, data);
|
|
46
|
+
return formatEnvelope(key.currentVersion, ciphertext);
|
|
47
|
+
};
|
|
48
|
+
const symmetricDecrypt = async ({ key, data }) => {
|
|
49
|
+
if (typeof key === "string") return rawDecrypt(key, data);
|
|
50
|
+
const envelope = parseEnvelope(data);
|
|
51
|
+
if (envelope) {
|
|
52
|
+
const secret = key.keys.get(envelope.version);
|
|
53
|
+
if (!secret) throw new Error(`Secret version ${envelope.version} not found in keys (key may have been retired)`);
|
|
54
|
+
return rawDecrypt(secret, envelope.ciphertext);
|
|
55
|
+
}
|
|
56
|
+
if (key.legacySecret) return rawDecrypt(key.legacySecret, data);
|
|
57
|
+
throw new Error("Cannot decrypt legacy bare-hex payload: no legacy secret available. Set BETTER_AUTH_SECRET for backwards compatibility.");
|
|
58
|
+
};
|
|
59
|
+
const getCryptoKey = async (secret) => {
|
|
60
|
+
const secretBuf = typeof secret === "string" ? new TextEncoder().encode(secret) : secret;
|
|
61
|
+
return await getWebcryptoSubtle().importKey("raw", secretBuf, algorithm, false, ["sign", "verify"]);
|
|
62
|
+
};
|
|
63
|
+
const makeSignature = async (value, secret) => {
|
|
64
|
+
const key = await getCryptoKey(secret);
|
|
65
|
+
const signature = await getWebcryptoSubtle().sign(algorithm.name, key, new TextEncoder().encode(value));
|
|
66
|
+
return btoa(String.fromCharCode(...new Uint8Array(signature)));
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
export { constantTimeEqual, formatEnvelope, generateRandomString, getCryptoKey, hashPassword, makeSignature, parseEnvelope, signJWT, symmetricDecodeJWT, symmetricDecrypt, symmetricEncodeJWT, symmetricEncrypt, verifyJWT, verifyPassword };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SecretConfig } from "./index.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/crypto/jwt.d.ts
|
|
4
|
+
declare function signJWT(payload: any, secret: string, expiresIn?: number): Promise<string>;
|
|
5
|
+
declare function verifyJWT<T = any>(token: string, secret: string): Promise<T | null>;
|
|
6
|
+
declare function symmetricEncodeJWT<T extends Record<string, any>>(payload: T, secret: string | SecretConfig, salt: string, expiresIn?: number): Promise<string>;
|
|
7
|
+
declare function symmetricDecodeJWT<T = any>(token: string, secret: string | SecretConfig, salt: string): Promise<T | null>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { signJWT, symmetricDecodeJWT, symmetricEncodeJWT, verifyJWT };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
2
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
3
|
+
import { EncryptJWT, SignJWT, base64url, calculateJwkThumbprint, decodeProtectedHeader, jwtDecrypt, jwtVerify } from "jose";
|
|
4
|
+
//#region src/crypto/jwt.ts
|
|
5
|
+
async function signJWT(payload, secret, expiresIn = 3600) {
|
|
6
|
+
return await new SignJWT(payload).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime(Math.floor(Date.now() / 1e3) + expiresIn).sign(new TextEncoder().encode(secret));
|
|
7
|
+
}
|
|
8
|
+
async function verifyJWT(token, secret) {
|
|
9
|
+
try {
|
|
10
|
+
return (await jwtVerify(token, new TextEncoder().encode(secret))).payload;
|
|
11
|
+
} catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const info = new Uint8Array([
|
|
16
|
+
66,
|
|
17
|
+
101,
|
|
18
|
+
116,
|
|
19
|
+
116,
|
|
20
|
+
101,
|
|
21
|
+
114,
|
|
22
|
+
65,
|
|
23
|
+
117,
|
|
24
|
+
116,
|
|
25
|
+
104,
|
|
26
|
+
46,
|
|
27
|
+
106,
|
|
28
|
+
115,
|
|
29
|
+
32,
|
|
30
|
+
71,
|
|
31
|
+
101,
|
|
32
|
+
110,
|
|
33
|
+
101,
|
|
34
|
+
114,
|
|
35
|
+
97,
|
|
36
|
+
116,
|
|
37
|
+
101,
|
|
38
|
+
100,
|
|
39
|
+
32,
|
|
40
|
+
69,
|
|
41
|
+
110,
|
|
42
|
+
99,
|
|
43
|
+
114,
|
|
44
|
+
121,
|
|
45
|
+
112,
|
|
46
|
+
116,
|
|
47
|
+
105,
|
|
48
|
+
111,
|
|
49
|
+
110,
|
|
50
|
+
32,
|
|
51
|
+
75,
|
|
52
|
+
101,
|
|
53
|
+
121
|
|
54
|
+
]);
|
|
55
|
+
const now = () => Date.now() / 1e3 | 0;
|
|
56
|
+
const alg = "dir";
|
|
57
|
+
const enc = "A256CBC-HS512";
|
|
58
|
+
function deriveEncryptionSecret(secret, salt) {
|
|
59
|
+
return hkdf(sha256, new TextEncoder().encode(secret), new TextEncoder().encode(salt), info, 64);
|
|
60
|
+
}
|
|
61
|
+
function getCurrentSecret(secret) {
|
|
62
|
+
if (typeof secret === "string") return secret;
|
|
63
|
+
const value = secret.keys.get(secret.currentVersion);
|
|
64
|
+
if (!value) throw new Error(`Secret version ${secret.currentVersion} not found in keys`);
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
function getAllSecrets(secret) {
|
|
68
|
+
if (typeof secret === "string") return [{
|
|
69
|
+
version: 0,
|
|
70
|
+
value: secret
|
|
71
|
+
}];
|
|
72
|
+
const result = [];
|
|
73
|
+
for (const [version, value] of secret.keys) result.push({
|
|
74
|
+
version,
|
|
75
|
+
value
|
|
76
|
+
});
|
|
77
|
+
if (secret.legacySecret && !result.some((s) => s.value === secret.legacySecret)) result.push({
|
|
78
|
+
version: -1,
|
|
79
|
+
value: secret.legacySecret
|
|
80
|
+
});
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
async function symmetricEncodeJWT(payload, secret, salt, expiresIn = 3600) {
|
|
84
|
+
const encryptionSecret = deriveEncryptionSecret(getCurrentSecret(secret), salt);
|
|
85
|
+
const thumbprint = await calculateJwkThumbprint({
|
|
86
|
+
kty: "oct",
|
|
87
|
+
k: base64url.encode(encryptionSecret)
|
|
88
|
+
}, "sha256");
|
|
89
|
+
return await new EncryptJWT(payload).setProtectedHeader({
|
|
90
|
+
alg,
|
|
91
|
+
enc,
|
|
92
|
+
kid: thumbprint
|
|
93
|
+
}).setIssuedAt().setExpirationTime(now() + expiresIn).setJti(crypto.randomUUID()).encrypt(encryptionSecret);
|
|
94
|
+
}
|
|
95
|
+
const jwtDecryptOpts = {
|
|
96
|
+
clockTolerance: 15,
|
|
97
|
+
keyManagementAlgorithms: [alg],
|
|
98
|
+
contentEncryptionAlgorithms: [enc, "A256GCM"]
|
|
99
|
+
};
|
|
100
|
+
async function symmetricDecodeJWT(token, secret, salt) {
|
|
101
|
+
if (!token) return null;
|
|
102
|
+
let hasKid = false;
|
|
103
|
+
try {
|
|
104
|
+
hasKid = decodeProtectedHeader(token).kid !== void 0;
|
|
105
|
+
} catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
const secrets = getAllSecrets(secret);
|
|
110
|
+
const { payload } = await jwtDecrypt(token, async (protectedHeader) => {
|
|
111
|
+
const kid = protectedHeader.kid;
|
|
112
|
+
if (kid !== void 0) {
|
|
113
|
+
for (const s of secrets) {
|
|
114
|
+
const encryptionSecret = deriveEncryptionSecret(s.value, salt);
|
|
115
|
+
if (kid === await calculateJwkThumbprint({
|
|
116
|
+
kty: "oct",
|
|
117
|
+
k: base64url.encode(encryptionSecret)
|
|
118
|
+
}, "sha256")) return encryptionSecret;
|
|
119
|
+
}
|
|
120
|
+
throw new Error("no matching decryption secret");
|
|
121
|
+
}
|
|
122
|
+
if (secrets.length === 1) return deriveEncryptionSecret(secrets[0].value, salt);
|
|
123
|
+
return deriveEncryptionSecret(secrets[0].value, salt);
|
|
124
|
+
}, jwtDecryptOpts);
|
|
125
|
+
return payload;
|
|
126
|
+
} catch {
|
|
127
|
+
if (hasKid) return null;
|
|
128
|
+
const secrets = getAllSecrets(secret);
|
|
129
|
+
if (secrets.length <= 1) return null;
|
|
130
|
+
for (let i = 1; i < secrets.length; i++) try {
|
|
131
|
+
const s = secrets[i];
|
|
132
|
+
const { payload } = await jwtDecrypt(token, deriveEncryptionSecret(s.value, salt), jwtDecryptOpts);
|
|
133
|
+
return payload;
|
|
134
|
+
} catch {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//#endregion
|
|
141
|
+
export { signJWT, symmetricDecodeJWT, symmetricEncodeJWT, verifyJWT };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { hashPassword } from "@better-auth/utils/password";
|
|
2
|
+
|
|
3
|
+
//#region src/crypto/password.d.ts
|
|
4
|
+
declare const hashPassword$1: typeof hashPassword;
|
|
5
|
+
declare const verifyPassword$1: ({
|
|
6
|
+
hash,
|
|
7
|
+
password
|
|
8
|
+
}: {
|
|
9
|
+
hash: string;
|
|
10
|
+
password: string;
|
|
11
|
+
}) => Promise<boolean>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { hashPassword$1 as hashPassword, verifyPassword$1 as verifyPassword };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { hashPassword, verifyPassword } from "@better-auth/utils/password";
|
|
2
|
+
//#region src/crypto/password.ts
|
|
3
|
+
/**
|
|
4
|
+
* `@better-auth/utils/password` uses the "node" export condition in package.json
|
|
5
|
+
* to automatically pick the right implementation:
|
|
6
|
+
* - Node.js / Bun / Deno → `node:crypto scrypt` (libuv thread pool, non-blocking)
|
|
7
|
+
* - Unsupported runtimes → `@noble/hashes scrypt` (pure JS fallback)
|
|
8
|
+
*/
|
|
9
|
+
const hashPassword$1 = hashPassword;
|
|
10
|
+
const verifyPassword$1 = async ({ hash, password }) => {
|
|
11
|
+
return verifyPassword(hash, password);
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { hashPassword$1 as hashPassword, verifyPassword$1 as verifyPassword };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { BetterAuthOptions } from "@better-auth/core";
|
|
2
|
+
import { DBAdapter } from "@better-auth/core/db/adapter";
|
|
3
|
+
|
|
4
|
+
//#region src/db/adapter-base.d.ts
|
|
5
|
+
declare function getBaseAdapter(options: BetterAuthOptions, handleDirectDatabase: (options: BetterAuthOptions) => Promise<DBAdapter<BetterAuthOptions>>): Promise<DBAdapter<BetterAuthOptions>>;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { getBaseAdapter };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getAuthTables } from "@better-auth/core/db";
|
|
2
|
+
import { logger } from "@better-auth/core/env";
|
|
3
|
+
//#region src/db/adapter-base.ts
|
|
4
|
+
async function getBaseAdapter(options, handleDirectDatabase) {
|
|
5
|
+
let adapter;
|
|
6
|
+
if (!options.database) {
|
|
7
|
+
const tables = getAuthTables(options);
|
|
8
|
+
const memoryDB = Object.keys(tables).reduce((acc, key) => {
|
|
9
|
+
acc[key] = [];
|
|
10
|
+
return acc;
|
|
11
|
+
}, {});
|
|
12
|
+
const { memoryAdapter } = await import("@better-auth/memory-adapter");
|
|
13
|
+
adapter = memoryAdapter(memoryDB)(options);
|
|
14
|
+
} else if (typeof options.database === "function") adapter = options.database(options);
|
|
15
|
+
else adapter = await handleDirectDatabase(options);
|
|
16
|
+
if (!adapter.transaction) {
|
|
17
|
+
logger.warn("Adapter does not correctly implement transaction function, patching it automatically. Please update your adapter implementation.");
|
|
18
|
+
adapter.transaction = async (cb) => {
|
|
19
|
+
return cb(adapter);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return adapter;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { getBaseAdapter };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { BetterAuthOptions } from "@better-auth/core";
|
|
2
|
+
import { DBAdapter } from "@better-auth/core/db/adapter";
|
|
3
|
+
|
|
4
|
+
//#region src/db/adapter-kysely.d.ts
|
|
5
|
+
declare function getAdapter(options: BetterAuthOptions): Promise<DBAdapter<BetterAuthOptions>>;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { getAdapter };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getBaseAdapter } from "./adapter-base.mjs";
|
|
2
|
+
import { BetterAuthError } from "@better-auth/core/error";
|
|
3
|
+
//#region src/db/adapter-kysely.ts
|
|
4
|
+
async function getAdapter(options) {
|
|
5
|
+
return getBaseAdapter(options, async (opts) => {
|
|
6
|
+
const { createKyselyAdapter, kyselyAdapter } = await import("../adapters/kysely-adapter/index.mjs");
|
|
7
|
+
const { kysely, databaseType, transaction } = await createKyselyAdapter(opts);
|
|
8
|
+
if (!kysely) throw new BetterAuthError("Failed to initialize database adapter");
|
|
9
|
+
return kyselyAdapter(kysely, {
|
|
10
|
+
type: databaseType || "sqlite",
|
|
11
|
+
debugLogs: opts.database && "debugLogs" in opts.database ? opts.database.debugLogs : false,
|
|
12
|
+
transaction
|
|
13
|
+
})(opts);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { getAdapter };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DBFieldAttribute } from "@better-auth/core/db";
|
|
2
|
+
|
|
3
|
+
//#region src/db/field-converter.d.ts
|
|
4
|
+
declare function convertToDB<T extends Record<string, any>>(fields: Record<string, DBFieldAttribute>, values: T): T;
|
|
5
|
+
declare function convertFromDB<T extends Record<string, any>>(fields: Record<string, DBFieldAttribute>, values: T | null): T | null;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { convertFromDB, convertToDB };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/db/field-converter.ts
|
|
2
|
+
function convertToDB(fields, values) {
|
|
3
|
+
const result = values.id ? { id: values.id } : {};
|
|
4
|
+
for (const key in fields) {
|
|
5
|
+
const field = fields[key];
|
|
6
|
+
const value = values[key];
|
|
7
|
+
if (value === void 0) continue;
|
|
8
|
+
result[field.fieldName || key] = value;
|
|
9
|
+
}
|
|
10
|
+
return result;
|
|
11
|
+
}
|
|
12
|
+
function convertFromDB(fields, values) {
|
|
13
|
+
if (!values) return null;
|
|
14
|
+
const result = { id: values.id };
|
|
15
|
+
for (const [key, value] of Object.entries(fields)) result[key] = values[value.fieldName || key];
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { convertFromDB, convertToDB };
|