@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,96 @@
|
|
|
1
|
+
import { Account, User } from "../types/models.mjs";
|
|
2
|
+
import { GenericEndpointContext, UserProvisioningSource } from "@better-auth/core";
|
|
3
|
+
|
|
4
|
+
//#region src/oauth2/link-account.d.ts
|
|
5
|
+
declare function handleOAuthUserInfo(c: GenericEndpointContext, opts: {
|
|
6
|
+
userInfo: Omit<User, "createdAt" | "updatedAt">;
|
|
7
|
+
account: Omit<Account, "id" | "userId" | "createdAt" | "updatedAt">;
|
|
8
|
+
callbackURL?: string | undefined;
|
|
9
|
+
disableSignUp?: boolean | undefined;
|
|
10
|
+
overrideUserInfo?: boolean | undefined;
|
|
11
|
+
isTrustedProvider?: boolean | undefined;
|
|
12
|
+
trustProviderByName?: boolean | undefined;
|
|
13
|
+
source?: UserProvisioningSource | undefined;
|
|
14
|
+
selectedUser?: {
|
|
15
|
+
userId: string;
|
|
16
|
+
profile: "preserve" | "update";
|
|
17
|
+
} | undefined;
|
|
18
|
+
deferNonDatabaseWrites?: boolean | undefined;
|
|
19
|
+
requireExactAccountBinding?: boolean | undefined;
|
|
20
|
+
}): Promise<{
|
|
21
|
+
error: string;
|
|
22
|
+
data: null;
|
|
23
|
+
isRegister: boolean;
|
|
24
|
+
accountCookie?: undefined;
|
|
25
|
+
} | {
|
|
26
|
+
error: string;
|
|
27
|
+
data: null;
|
|
28
|
+
isRegister?: undefined;
|
|
29
|
+
accountCookie?: undefined;
|
|
30
|
+
} | {
|
|
31
|
+
data: {
|
|
32
|
+
session: {
|
|
33
|
+
id: string;
|
|
34
|
+
createdAt: Date;
|
|
35
|
+
updatedAt: Date;
|
|
36
|
+
userId: string;
|
|
37
|
+
expiresAt: Date;
|
|
38
|
+
token: string;
|
|
39
|
+
ipAddress?: string | null | undefined;
|
|
40
|
+
userAgent?: string | null | undefined;
|
|
41
|
+
};
|
|
42
|
+
user: {
|
|
43
|
+
id: string;
|
|
44
|
+
createdAt: Date;
|
|
45
|
+
updatedAt: Date;
|
|
46
|
+
email: string;
|
|
47
|
+
emailVerified: boolean;
|
|
48
|
+
name: string;
|
|
49
|
+
image?: string | null | undefined;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
error: null;
|
|
53
|
+
isRegister: boolean;
|
|
54
|
+
accountCookie: {
|
|
55
|
+
id: string;
|
|
56
|
+
createdAt: Date;
|
|
57
|
+
updatedAt: Date;
|
|
58
|
+
providerId: string;
|
|
59
|
+
accountId: string;
|
|
60
|
+
userId: string;
|
|
61
|
+
accessToken?: string | null | undefined;
|
|
62
|
+
refreshToken?: string | null | undefined;
|
|
63
|
+
idToken?: string | null | undefined;
|
|
64
|
+
accessTokenExpiresAt?: Date | null | undefined;
|
|
65
|
+
refreshTokenExpiresAt?: Date | null | undefined;
|
|
66
|
+
scope?: string | null | undefined;
|
|
67
|
+
password?: string | null | undefined;
|
|
68
|
+
} | null;
|
|
69
|
+
}>;
|
|
70
|
+
/**
|
|
71
|
+
* Provider profile a freshly linked account may copy onto the local user.
|
|
72
|
+
* `email` and `emailVerified` are identity anchors and are stripped before
|
|
73
|
+
* the remaining fields are written. Provider identity is resolved separately
|
|
74
|
+
* from the raw profile through the provider's account-key contract.
|
|
75
|
+
*/
|
|
76
|
+
type LinkedProviderProfile = {
|
|
77
|
+
name?: string | undefined;
|
|
78
|
+
email?: string | null | undefined;
|
|
79
|
+
emailVerified?: boolean | undefined;
|
|
80
|
+
image?: string | null | undefined;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Apply the `account.accountLinking.updateUserInfoOnLink` policy: when enabled,
|
|
84
|
+
* copy the freshly linked provider's profile onto the local user, matching the
|
|
85
|
+
* field set persisted on sign-up. The local `email` and `emailVerified` are
|
|
86
|
+
* never changed, so a link can't rebind the account's identity, and
|
|
87
|
+
* `updateUser` drops `undefined` fields, so a provider that omits one leaves
|
|
88
|
+
* the existing column intact.
|
|
89
|
+
*
|
|
90
|
+
* Returns the updated user so a caller that issues a session can seed the
|
|
91
|
+
* cookie cache with the fresh row. Returns `undefined` when the policy is
|
|
92
|
+
* disabled or the update fails: a failed profile sync must not abort the link.
|
|
93
|
+
*/
|
|
94
|
+
declare function applyUpdateUserInfoOnLink(c: GenericEndpointContext, userId: string, userInfo: LinkedProviderProfile): Promise<User | undefined>;
|
|
95
|
+
//#endregion
|
|
96
|
+
export { applyUpdateUserInfoOnLink, handleOAuthUserInfo };
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { isAPIError } from "../utils/is-api-error.mjs";
|
|
2
|
+
import { parseAdditionalUserInputFromProviderProfile } from "../db/schema.mjs";
|
|
3
|
+
import { setAccountCookie } from "../cookies/session-store.mjs";
|
|
4
|
+
import { assertValidUserInfo } from "../utils/validate-user-info.mjs";
|
|
5
|
+
import { OAUTH_CALLBACK_ERROR_CODES, redirectOnError } from "./errors.mjs";
|
|
6
|
+
import { setTokenUtil } from "./utils.mjs";
|
|
7
|
+
import { createEmailVerificationToken } from "../api/routes/email-verification.mjs";
|
|
8
|
+
import { queueAfterTransactionHook, runWithTransaction } from "@better-auth/core/context";
|
|
9
|
+
import { isDevelopment } from "@better-auth/core/env";
|
|
10
|
+
import { APIError } from "@better-auth/core/error";
|
|
11
|
+
//#region src/oauth2/link-account.ts
|
|
12
|
+
async function handleOAuthUserInfo(c, opts) {
|
|
13
|
+
const { userInfo, account, callbackURL, disableSignUp, overrideUserInfo } = opts;
|
|
14
|
+
const source = opts.source ?? {
|
|
15
|
+
method: "oauth",
|
|
16
|
+
oauth: { providerId: account.providerId }
|
|
17
|
+
};
|
|
18
|
+
const requireExactAccountBinding = !!opts.selectedUser || opts.requireExactAccountBinding === true;
|
|
19
|
+
let pendingAccountCookie = null;
|
|
20
|
+
const accountOwner = await c.context.internalAdapter.findAccountOwnerByKey({
|
|
21
|
+
providerId: account.providerId,
|
|
22
|
+
accountId: account.accountId
|
|
23
|
+
}).catch((e) => {
|
|
24
|
+
c.context.logger.error("Better auth was unable to query your database.\nError: ", e);
|
|
25
|
+
redirectOnError(c, c.context.options.onAPIError?.errorURL || `${c.context.baseURL}/error`, "internal_server_error");
|
|
26
|
+
});
|
|
27
|
+
if (accountOwner?.kind === "orphaned") {
|
|
28
|
+
c.context.logger.error("OAuth account references a missing user. Repair the account before retrying authentication.");
|
|
29
|
+
return {
|
|
30
|
+
error: "unable to link account",
|
|
31
|
+
data: null,
|
|
32
|
+
isRegister: false
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const dbUser = await (async () => {
|
|
36
|
+
if (accountOwner?.kind === "owned") {
|
|
37
|
+
if (opts.selectedUser && accountOwner.user.id !== opts.selectedUser.userId) throw new APIError("CONFLICT", {
|
|
38
|
+
code: "account_ownership_conflict",
|
|
39
|
+
message: "Account is already linked to another user"
|
|
40
|
+
});
|
|
41
|
+
return {
|
|
42
|
+
user: accountOwner.user,
|
|
43
|
+
linkedAccount: accountOwner.account,
|
|
44
|
+
accounts: [accountOwner.account]
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (opts.selectedUser) {
|
|
48
|
+
const selectedUser = await c.context.internalAdapter.findUserById(opts.selectedUser.userId);
|
|
49
|
+
if (!selectedUser) throw new APIError("NOT_FOUND", {
|
|
50
|
+
code: "user_not_found",
|
|
51
|
+
message: "User not found"
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
user: selectedUser,
|
|
55
|
+
linkedAccount: null,
|
|
56
|
+
accounts: []
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const emailMatch = await c.context.internalAdapter.findUserByEmail(userInfo.email.toLowerCase(), { includeAccounts: true });
|
|
60
|
+
if (!emailMatch) return null;
|
|
61
|
+
return {
|
|
62
|
+
user: emailMatch.user,
|
|
63
|
+
linkedAccount: null,
|
|
64
|
+
accounts: emailMatch.accounts
|
|
65
|
+
};
|
|
66
|
+
})().catch((e) => {
|
|
67
|
+
if (isAPIError(e)) throw e;
|
|
68
|
+
c.context.logger.error("Better auth was unable to query your database.\nError: ", e);
|
|
69
|
+
redirectOnError(c, c.context.options.onAPIError?.errorURL || `${c.context.baseURL}/error`, "internal_server_error");
|
|
70
|
+
});
|
|
71
|
+
let user = dbUser?.user;
|
|
72
|
+
const isRegister = !user;
|
|
73
|
+
if (dbUser) {
|
|
74
|
+
const linkedAccount = dbUser.linkedAccount ?? dbUser.accounts.find((acc) => acc.providerId === account.providerId && acc.accountId === account.accountId);
|
|
75
|
+
if (!linkedAccount) {
|
|
76
|
+
const accountLinking = c.context.options.account?.accountLinking;
|
|
77
|
+
const isTrustedProvider = opts.isTrustedProvider || opts.trustProviderByName !== false && c.context.trustedProviders.includes(account.providerId);
|
|
78
|
+
const requireLocalEmailVerified = accountLinking?.requireLocalEmailVerified ?? true;
|
|
79
|
+
if (!opts.selectedUser && (!isTrustedProvider && !userInfo.emailVerified || requireLocalEmailVerified && !dbUser.user.emailVerified || accountLinking?.enabled === false || accountLinking?.disableImplicitLinking === true)) {
|
|
80
|
+
if (isDevelopment()) c.context.logger.warn(`User already exist but account isn't linked to ${account.providerId}. To read more about how account linking works in Better Auth see https://www.better-auth.com/docs/concepts/users-accounts#account-linking.`);
|
|
81
|
+
return {
|
|
82
|
+
error: "account not linked",
|
|
83
|
+
data: null
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
const { id: _accountId, ...providerUserInfo } = userInfo;
|
|
88
|
+
await assertValidUserInfo(c, {
|
|
89
|
+
user: {
|
|
90
|
+
...providerUserInfo,
|
|
91
|
+
id: dbUser.user.id,
|
|
92
|
+
email: userInfo.email.toLowerCase()
|
|
93
|
+
},
|
|
94
|
+
source: {
|
|
95
|
+
...source,
|
|
96
|
+
action: "link-account"
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
const createdAccount = await c.context.internalAdapter.linkAccount({
|
|
100
|
+
providerId: account.providerId,
|
|
101
|
+
accountId: account.accountId,
|
|
102
|
+
userId: dbUser.user.id,
|
|
103
|
+
accessToken: await setTokenUtil(account.accessToken, c.context),
|
|
104
|
+
refreshToken: await setTokenUtil(account.refreshToken, c.context),
|
|
105
|
+
idToken: account.idToken,
|
|
106
|
+
accessTokenExpiresAt: account.accessTokenExpiresAt,
|
|
107
|
+
refreshTokenExpiresAt: account.refreshTokenExpiresAt,
|
|
108
|
+
scope: account.scope
|
|
109
|
+
});
|
|
110
|
+
if (!createdAccount) return {
|
|
111
|
+
error: "unable to link account",
|
|
112
|
+
data: null
|
|
113
|
+
};
|
|
114
|
+
if (requireExactAccountBinding && (createdAccount.accountId !== account.accountId || createdAccount.providerId !== account.providerId || createdAccount.userId !== dbUser.user.id)) throw new APIError("CONFLICT", {
|
|
115
|
+
code: "account_hook_binding_conflict",
|
|
116
|
+
message: "Account hook changed the selected authentication binding"
|
|
117
|
+
});
|
|
118
|
+
if (c.context.options.account?.storeAccountCookie) if (opts.deferNonDatabaseWrites) pendingAccountCookie = createdAccount;
|
|
119
|
+
else await setAccountCookie(c, createdAccount);
|
|
120
|
+
} catch (e) {
|
|
121
|
+
if (isAPIError(e)) throw e;
|
|
122
|
+
c.context.logger.error("Unable to link account", e);
|
|
123
|
+
return {
|
|
124
|
+
error: "unable to link account",
|
|
125
|
+
data: null
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
if (!opts.selectedUser && userInfo.emailVerified && !dbUser.user.emailVerified && userInfo.email.toLowerCase() === dbUser.user.email) await c.context.internalAdapter.updateUser(dbUser.user.id, { emailVerified: true });
|
|
129
|
+
if (!opts.selectedUser) user = await applyUpdateUserInfoOnLink(c, dbUser.user.id, userInfo) ?? user;
|
|
130
|
+
} else {
|
|
131
|
+
const { id: _accountId, ...providerUserInfo } = userInfo;
|
|
132
|
+
await assertValidUserInfo(c, {
|
|
133
|
+
user: {
|
|
134
|
+
...providerUserInfo,
|
|
135
|
+
id: dbUser.user.id,
|
|
136
|
+
email: userInfo.email.toLowerCase()
|
|
137
|
+
},
|
|
138
|
+
source: {
|
|
139
|
+
...source,
|
|
140
|
+
action: "sign-in"
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
/**
|
|
144
|
+
* `scope` intentionally omitted. Updated only via linkSocial.
|
|
145
|
+
*
|
|
146
|
+
* @see {@link Account.scope}
|
|
147
|
+
*/
|
|
148
|
+
const freshTokens = c.context.options.account?.updateAccountOnSignIn !== false ? Object.fromEntries(Object.entries({
|
|
149
|
+
providerId: account.providerId,
|
|
150
|
+
idToken: account.idToken,
|
|
151
|
+
accessToken: await setTokenUtil(account.accessToken, c.context),
|
|
152
|
+
refreshToken: await setTokenUtil(account.refreshToken, c.context),
|
|
153
|
+
accessTokenExpiresAt: account.accessTokenExpiresAt,
|
|
154
|
+
refreshTokenExpiresAt: account.refreshTokenExpiresAt
|
|
155
|
+
}).filter(([_, value]) => value !== void 0)) : {};
|
|
156
|
+
if (c.context.options.account?.storeAccountCookie) {
|
|
157
|
+
const accountCookie = {
|
|
158
|
+
...linkedAccount,
|
|
159
|
+
...freshTokens
|
|
160
|
+
};
|
|
161
|
+
if (opts.deferNonDatabaseWrites) pendingAccountCookie = accountCookie;
|
|
162
|
+
else await setAccountCookie(c, accountCookie);
|
|
163
|
+
}
|
|
164
|
+
if (Object.keys(freshTokens).length > 0) {
|
|
165
|
+
const updatedAccount = await c.context.internalAdapter.updateAccount(linkedAccount.id, freshTokens);
|
|
166
|
+
if (!updatedAccount) return {
|
|
167
|
+
error: "unable to update account",
|
|
168
|
+
data: null
|
|
169
|
+
};
|
|
170
|
+
if (requireExactAccountBinding && (updatedAccount.accountId !== account.accountId || updatedAccount.providerId !== account.providerId || updatedAccount.userId !== dbUser.user.id)) throw new APIError("CONFLICT", {
|
|
171
|
+
code: "account_hook_binding_conflict",
|
|
172
|
+
message: "Account hook changed the selected authentication binding"
|
|
173
|
+
});
|
|
174
|
+
if (opts.deferNonDatabaseWrites && pendingAccountCookie) pendingAccountCookie = updatedAccount;
|
|
175
|
+
}
|
|
176
|
+
if (!opts.selectedUser && userInfo.emailVerified && !dbUser.user.emailVerified && userInfo.email.toLowerCase() === dbUser.user.email) await c.context.internalAdapter.updateUser(dbUser.user.id, { emailVerified: true });
|
|
177
|
+
}
|
|
178
|
+
if (opts.selectedUser ? opts.selectedUser.profile === "update" : overrideUserInfo) {
|
|
179
|
+
const { id: _id, email: _email, emailVerified: _emailVerified, name, image, ...providerProfile } = userInfo;
|
|
180
|
+
const additionalUserFields = parseAdditionalUserInputFromProviderProfile(c.context.options, providerProfile, "update");
|
|
181
|
+
const updatedUser = await c.context.internalAdapter.updateUser(dbUser.user.id, {
|
|
182
|
+
name,
|
|
183
|
+
image,
|
|
184
|
+
...additionalUserFields,
|
|
185
|
+
email: userInfo.email.toLowerCase(),
|
|
186
|
+
emailVerified: userInfo.email.toLowerCase() === dbUser.user.email ? dbUser.user.emailVerified || userInfo.emailVerified : userInfo.emailVerified
|
|
187
|
+
});
|
|
188
|
+
if (updatedUser == null) c.context.logger.warn("Could not update user info during OAuth sign in; preserving existing user for session.");
|
|
189
|
+
if (opts.selectedUser && updatedUser && updatedUser.id !== opts.selectedUser.userId) throw new APIError("CONFLICT", {
|
|
190
|
+
code: "user_hook_selection_conflict",
|
|
191
|
+
message: "User hook changed the selected user"
|
|
192
|
+
});
|
|
193
|
+
user = updatedUser ?? user;
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
if (disableSignUp) return {
|
|
197
|
+
error: "signup disabled",
|
|
198
|
+
data: null,
|
|
199
|
+
isRegister: false
|
|
200
|
+
};
|
|
201
|
+
try {
|
|
202
|
+
const { id: _id, email: _email, emailVerified: _emailVerified, name, image, ...providerProfile } = userInfo;
|
|
203
|
+
const additionalUserFields = parseAdditionalUserInputFromProviderProfile(c.context.options, providerProfile, "create");
|
|
204
|
+
const accountData = {
|
|
205
|
+
accessToken: await setTokenUtil(account.accessToken, c.context),
|
|
206
|
+
refreshToken: await setTokenUtil(account.refreshToken, c.context),
|
|
207
|
+
idToken: account.idToken,
|
|
208
|
+
accessTokenExpiresAt: account.accessTokenExpiresAt,
|
|
209
|
+
refreshTokenExpiresAt: account.refreshTokenExpiresAt,
|
|
210
|
+
scope: account.scope,
|
|
211
|
+
providerId: account.providerId,
|
|
212
|
+
accountId: account.accountId
|
|
213
|
+
};
|
|
214
|
+
const { createdUser, createdAccount } = await runWithTransaction(c.context.adapter, async () => {
|
|
215
|
+
const createdUser = await c.context.internalAdapter.createUser({
|
|
216
|
+
name,
|
|
217
|
+
image,
|
|
218
|
+
...additionalUserFields,
|
|
219
|
+
email: userInfo.email.toLowerCase(),
|
|
220
|
+
emailVerified: userInfo.emailVerified
|
|
221
|
+
}, source);
|
|
222
|
+
return {
|
|
223
|
+
createdUser,
|
|
224
|
+
createdAccount: await c.context.internalAdapter.createAccount({
|
|
225
|
+
...accountData,
|
|
226
|
+
userId: createdUser.id
|
|
227
|
+
})
|
|
228
|
+
};
|
|
229
|
+
});
|
|
230
|
+
if (requireExactAccountBinding && (createdAccount.accountId !== account.accountId || createdAccount.providerId !== account.providerId || createdAccount.userId !== createdUser.id)) throw new APIError("CONFLICT", {
|
|
231
|
+
code: "account_hook_binding_conflict",
|
|
232
|
+
message: "Account hook changed the selected authentication binding"
|
|
233
|
+
});
|
|
234
|
+
user = createdUser;
|
|
235
|
+
if (c.context.options.account?.storeAccountCookie) if (opts.deferNonDatabaseWrites) pendingAccountCookie = createdAccount;
|
|
236
|
+
else await setAccountCookie(c, createdAccount);
|
|
237
|
+
} catch (e) {
|
|
238
|
+
if (isAPIError(e)) throw e;
|
|
239
|
+
c.context.logger.error("Unable to create OAuth user", e);
|
|
240
|
+
return {
|
|
241
|
+
error: "unable to create user",
|
|
242
|
+
data: null,
|
|
243
|
+
isRegister: false
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (!user) return {
|
|
248
|
+
error: "unable to create user",
|
|
249
|
+
data: null,
|
|
250
|
+
isRegister: false
|
|
251
|
+
};
|
|
252
|
+
const requireEmailVerification = c.context.socialProviders.find((p) => p.id === account.providerId)?.options?.requireEmailVerification;
|
|
253
|
+
if (isRegister && !user.emailVerified && (c.context.options.emailVerification?.sendOnSignUp ?? requireEmailVerification)) await dispatchVerificationEmail(c, user, callbackURL, opts.deferNonDatabaseWrites);
|
|
254
|
+
if (requireEmailVerification && !user.emailVerified) {
|
|
255
|
+
if (!isRegister && c.context.options.emailVerification?.sendOnSignIn) await dispatchVerificationEmail(c, user, callbackURL, opts.deferNonDatabaseWrites);
|
|
256
|
+
return {
|
|
257
|
+
error: OAUTH_CALLBACK_ERROR_CODES.EMAIL_NOT_VERIFIED,
|
|
258
|
+
data: null,
|
|
259
|
+
isRegister
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
const session = await c.context.internalAdapter.createSession(user.id, void 0, void 0, void 0, { deferSecondaryStorageWrites: opts.deferNonDatabaseWrites === true });
|
|
263
|
+
if (!session) return {
|
|
264
|
+
error: "unable to create session",
|
|
265
|
+
data: null,
|
|
266
|
+
isRegister: false
|
|
267
|
+
};
|
|
268
|
+
if (requireExactAccountBinding && session.userId !== (opts.selectedUser?.userId ?? user.id)) throw new APIError("CONFLICT", {
|
|
269
|
+
code: "session_hook_user_conflict",
|
|
270
|
+
message: "Session hook changed the selected user"
|
|
271
|
+
});
|
|
272
|
+
return {
|
|
273
|
+
data: {
|
|
274
|
+
session,
|
|
275
|
+
user
|
|
276
|
+
},
|
|
277
|
+
error: null,
|
|
278
|
+
isRegister,
|
|
279
|
+
accountCookie: pendingAccountCookie
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
async function dispatchVerificationEmail(c, user, callbackURL, deferUntilAfterTransaction) {
|
|
283
|
+
const sendVerificationEmail = c.context.options.emailVerification?.sendVerificationEmail;
|
|
284
|
+
if (!sendVerificationEmail) return;
|
|
285
|
+
const send = async () => {
|
|
286
|
+
try {
|
|
287
|
+
const token = await createEmailVerificationToken(c.context.secret, user.email, void 0, c.context.options.emailVerification?.expiresIn);
|
|
288
|
+
const url = `${c.context.baseURL}/verify-email?token=${token}&callbackURL=${encodeURIComponent(callbackURL || "/")}`;
|
|
289
|
+
await c.context.runInBackgroundOrAwait(sendVerificationEmail({
|
|
290
|
+
user,
|
|
291
|
+
url,
|
|
292
|
+
token
|
|
293
|
+
}, c.request));
|
|
294
|
+
} catch (e) {
|
|
295
|
+
c.context.logger.error("Failed to send OAuth verification email", e);
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
if (deferUntilAfterTransaction) await queueAfterTransactionHook(send);
|
|
299
|
+
else await send();
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Apply the `account.accountLinking.updateUserInfoOnLink` policy: when enabled,
|
|
303
|
+
* copy the freshly linked provider's profile onto the local user, matching the
|
|
304
|
+
* field set persisted on sign-up. The local `email` and `emailVerified` are
|
|
305
|
+
* never changed, so a link can't rebind the account's identity, and
|
|
306
|
+
* `updateUser` drops `undefined` fields, so a provider that omits one leaves
|
|
307
|
+
* the existing column intact.
|
|
308
|
+
*
|
|
309
|
+
* Returns the updated user so a caller that issues a session can seed the
|
|
310
|
+
* cookie cache with the fresh row. Returns `undefined` when the policy is
|
|
311
|
+
* disabled or the update fails: a failed profile sync must not abort the link.
|
|
312
|
+
*/
|
|
313
|
+
async function applyUpdateUserInfoOnLink(c, userId, userInfo) {
|
|
314
|
+
if (c.context.options.account?.accountLinking?.updateUserInfoOnLink !== true) return;
|
|
315
|
+
try {
|
|
316
|
+
const { email: _email, emailVerified: _emailVerified, name, image, ...providerProfile } = userInfo;
|
|
317
|
+
const additionalUserFields = parseAdditionalUserInputFromProviderProfile(c.context.options, providerProfile, "update");
|
|
318
|
+
return await c.context.internalAdapter.updateUser(userId, {
|
|
319
|
+
name,
|
|
320
|
+
image,
|
|
321
|
+
...additionalUserFields
|
|
322
|
+
});
|
|
323
|
+
} catch (e) {
|
|
324
|
+
c.context.logger.warn("Could not update user info on account link", e);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
//#endregion
|
|
329
|
+
export { applyUpdateUserInfoOnLink, handleOAuthUserInfo };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { GenericEndpointContext } from "@better-auth/core";
|
|
2
|
+
|
|
3
|
+
//#region src/oauth2/state.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Mint the OIDC `nonce` for the redirect flow, or `undefined` when the provider
|
|
6
|
+
* does not require ID-token nonce binding. Every redirect entrypoint (social
|
|
7
|
+
* sign-in, account linking, IDP-initiated bounce, and the OAuth popup) mints
|
|
8
|
+
* through this helper, so the value sent on the authorization URL and the value
|
|
9
|
+
* persisted in state are produced one way and cannot drift apart.
|
|
10
|
+
*/
|
|
11
|
+
declare function generateIdTokenNonce(provider: {
|
|
12
|
+
requiresIdTokenNonce?: boolean | undefined;
|
|
13
|
+
}): string | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Inputs for {@link generateState}. Grouped into one object so call sites read
|
|
16
|
+
* by name instead of by position.
|
|
17
|
+
*/
|
|
18
|
+
interface GenerateStateOptions {
|
|
19
|
+
/** Link target when this flow links a provider identity to an existing user. */
|
|
20
|
+
link?: {
|
|
21
|
+
email: string;
|
|
22
|
+
userId: string;
|
|
23
|
+
} | undefined;
|
|
24
|
+
/** Extra data to round-trip through state; `false` writes none. */
|
|
25
|
+
additionalData?: Record<string, any> | false | undefined;
|
|
26
|
+
/** The `state` nonce already used to build the authorization URL. Minted when omitted. */
|
|
27
|
+
state?: string | undefined;
|
|
28
|
+
/** The PKCE `codeVerifier` already used to build the authorization URL. Minted when omitted. */
|
|
29
|
+
codeVerifier?: string | undefined;
|
|
30
|
+
/** The OIDC nonce already sent as the authorization URL `nonce` parameter. */
|
|
31
|
+
idTokenNonce?: string | undefined;
|
|
32
|
+
}
|
|
33
|
+
declare function generateState(c: GenericEndpointContext, options?: GenerateStateOptions): Promise<{
|
|
34
|
+
state: string;
|
|
35
|
+
codeVerifier: string;
|
|
36
|
+
}>;
|
|
37
|
+
declare function parseState(c: GenericEndpointContext): Promise<{
|
|
38
|
+
[x: string]: unknown;
|
|
39
|
+
callbackURL: string;
|
|
40
|
+
codeVerifier: string;
|
|
41
|
+
expiresAt: number;
|
|
42
|
+
errorURL?: string | undefined;
|
|
43
|
+
newUserURL?: string | undefined;
|
|
44
|
+
oauthState?: string | undefined;
|
|
45
|
+
link?: {
|
|
46
|
+
email: string;
|
|
47
|
+
userId: string;
|
|
48
|
+
} | undefined;
|
|
49
|
+
requestSignUp?: boolean | undefined;
|
|
50
|
+
idTokenNonce?: string | undefined;
|
|
51
|
+
serverContext?: Record<string, unknown> | undefined;
|
|
52
|
+
}>;
|
|
53
|
+
//#endregion
|
|
54
|
+
export { GenerateStateOptions, generateIdTokenNonce, generateState, parseState };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { generateRandomString } from "../crypto/random.mjs";
|
|
2
|
+
import { redirectOnError } from "./errors.mjs";
|
|
3
|
+
import { getOAuthServerContext, setOAuthState } from "../api/state/oauth.mjs";
|
|
4
|
+
import { StateError, generateGenericState, parseGenericState } from "../state.mjs";
|
|
5
|
+
import { APIError, BASE_ERROR_CODES } from "@better-auth/core/error";
|
|
6
|
+
//#region src/oauth2/state.ts
|
|
7
|
+
/**
|
|
8
|
+
* Mint the OIDC `nonce` for the redirect flow, or `undefined` when the provider
|
|
9
|
+
* does not require ID-token nonce binding. Every redirect entrypoint (social
|
|
10
|
+
* sign-in, account linking, IDP-initiated bounce, and the OAuth popup) mints
|
|
11
|
+
* through this helper, so the value sent on the authorization URL and the value
|
|
12
|
+
* persisted in state are produced one way and cannot drift apart.
|
|
13
|
+
*/
|
|
14
|
+
function generateIdTokenNonce(provider) {
|
|
15
|
+
return provider.requiresIdTokenNonce ? generateRandomString(32) : void 0;
|
|
16
|
+
}
|
|
17
|
+
async function generateState(c, options) {
|
|
18
|
+
const callbackURL = c.body?.callbackURL || c.context.options.baseURL;
|
|
19
|
+
if (!callbackURL) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.CALLBACK_URL_REQUIRED);
|
|
20
|
+
const codeVerifier = options?.codeVerifier ?? generateRandomString(128);
|
|
21
|
+
const pendingServerContext = await getOAuthServerContext();
|
|
22
|
+
const serverContext = pendingServerContext && Object.keys(pendingServerContext).length ? pendingServerContext : void 0;
|
|
23
|
+
const stateData = {
|
|
24
|
+
...options?.additionalData ? options.additionalData : {},
|
|
25
|
+
callbackURL,
|
|
26
|
+
codeVerifier,
|
|
27
|
+
errorURL: c.body?.errorCallbackURL,
|
|
28
|
+
newUserURL: c.body?.newUserCallbackURL,
|
|
29
|
+
link: options?.link,
|
|
30
|
+
serverContext,
|
|
31
|
+
expiresAt: Date.now() + 600 * 1e3,
|
|
32
|
+
requestSignUp: c.body?.requestSignUp,
|
|
33
|
+
idTokenNonce: options?.idTokenNonce
|
|
34
|
+
};
|
|
35
|
+
await setOAuthState(stateData);
|
|
36
|
+
try {
|
|
37
|
+
return generateGenericState(c, stateData);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
c.context.logger.error("Failed to create verification", error);
|
|
40
|
+
throw new APIError("INTERNAL_SERVER_ERROR", {
|
|
41
|
+
message: "Unable to create verification",
|
|
42
|
+
cause: error
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function parseState(c) {
|
|
47
|
+
const state = c.query.state || c.body?.state;
|
|
48
|
+
const errorURL = c.context.options.onAPIError?.errorURL || `${c.context.baseURL}/error`;
|
|
49
|
+
let parsedData;
|
|
50
|
+
try {
|
|
51
|
+
parsedData = await parseGenericState(c, state);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
c.context.logger.error("Failed to parse state", error);
|
|
54
|
+
let code = "internal_server_error";
|
|
55
|
+
let redirectErrorURL = errorURL;
|
|
56
|
+
if (error instanceof StateError) {
|
|
57
|
+
code = error.code === "state_security_mismatch" ? "state_mismatch" : error.code;
|
|
58
|
+
redirectErrorURL = error.errorURL || errorURL;
|
|
59
|
+
}
|
|
60
|
+
redirectOnError(c, redirectErrorURL, code);
|
|
61
|
+
}
|
|
62
|
+
if (!parsedData.errorURL) parsedData.errorURL = errorURL;
|
|
63
|
+
if (parsedData) await setOAuthState(parsedData);
|
|
64
|
+
return parsedData;
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { generateIdTokenNonce, generateState, parseState };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AuthContext, LiteralString } from "@better-auth/core";
|
|
2
|
+
|
|
3
|
+
//#region src/oauth2/utils.d.ts
|
|
4
|
+
declare function decryptOAuthToken(token: string, ctx: AuthContext): string | Promise<string>;
|
|
5
|
+
declare function setTokenUtil(token: string | null | undefined, ctx: AuthContext): string | Promise<string> | null | undefined;
|
|
6
|
+
declare function getOAuthCallbackPath(provider: {
|
|
7
|
+
id: LiteralString;
|
|
8
|
+
callbackPath?: string | undefined;
|
|
9
|
+
}): string;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { decryptOAuthToken, getOAuthCallbackPath, setTokenUtil };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { symmetricDecrypt, symmetricEncrypt } from "../crypto/index.mjs";
|
|
2
|
+
//#region src/oauth2/utils.ts
|
|
3
|
+
/**
|
|
4
|
+
* Check if a string looks like encrypted data
|
|
5
|
+
*/
|
|
6
|
+
function isLikelyEncrypted(token) {
|
|
7
|
+
if (token.startsWith("$ba$")) return true;
|
|
8
|
+
return token.length % 2 === 0 && /^[0-9a-f]+$/i.test(token);
|
|
9
|
+
}
|
|
10
|
+
function decryptOAuthToken(token, ctx) {
|
|
11
|
+
if (!token) return token;
|
|
12
|
+
if (ctx.options.account?.encryptOAuthTokens) {
|
|
13
|
+
if (!isLikelyEncrypted(token)) return token;
|
|
14
|
+
return symmetricDecrypt({
|
|
15
|
+
key: ctx.secretConfig,
|
|
16
|
+
data: token
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return token;
|
|
20
|
+
}
|
|
21
|
+
function setTokenUtil(token, ctx) {
|
|
22
|
+
if (ctx.options.account?.encryptOAuthTokens && token) return symmetricEncrypt({
|
|
23
|
+
key: ctx.secretConfig,
|
|
24
|
+
data: token
|
|
25
|
+
});
|
|
26
|
+
return token;
|
|
27
|
+
}
|
|
28
|
+
function getOAuthCallbackPath(provider) {
|
|
29
|
+
if (!provider.callbackPath) return `/callback/${provider.id}`;
|
|
30
|
+
return provider.callbackPath.startsWith("/") ? provider.callbackPath : `/${provider.callbackPath}`;
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { decryptOAuthToken, getOAuthCallbackPath, setTokenUtil };
|
package/dist/package.mjs
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ExactRoleStatements, Role, RoleInput, Statements } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/plugins/access/access.d.ts
|
|
4
|
+
type AuthorizeResponse = {
|
|
5
|
+
success: false;
|
|
6
|
+
error: string;
|
|
7
|
+
} | {
|
|
8
|
+
success: true;
|
|
9
|
+
error?: never | undefined;
|
|
10
|
+
};
|
|
11
|
+
declare function role<const TRoleStatements extends Statements, TAuthorizeStatements extends Statements = TRoleStatements>(statements: TRoleStatements): Role<ExactRoleStatements<TRoleStatements>, TAuthorizeStatements>;
|
|
12
|
+
declare function createAccessControl<const TStatements extends Statements>(s: TStatements): {
|
|
13
|
+
newRole<const TRoleStatements extends Statements>(statements: RoleInput<TStatements, TRoleStatements>): Role<ExactRoleStatements<TRoleStatements>, TStatements>;
|
|
14
|
+
statements: TStatements;
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
export { AuthorizeResponse, createAccessControl, role };
|