@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,130 @@
|
|
|
1
|
+
import * as _$_better_auth_core0 from "@better-auth/core";
|
|
2
|
+
import { SecretConfig } from "@better-auth/core";
|
|
3
|
+
import * as _$better_call0 from "better-call";
|
|
4
|
+
import * as z from "zod";
|
|
5
|
+
|
|
6
|
+
//#region src/plugins/oauth-proxy/index.d.ts
|
|
7
|
+
declare module "@better-auth/core" {
|
|
8
|
+
interface BetterAuthPluginRegistry<AuthOptions, Options> {
|
|
9
|
+
"oauth-proxy": {
|
|
10
|
+
creator: typeof oAuthProxy;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
interface OAuthProxyOptions {
|
|
15
|
+
/**
|
|
16
|
+
* The current URL of the application.
|
|
17
|
+
* The plugin will attempt to infer the current URL from your environment
|
|
18
|
+
* by checking the base URL from popular hosting providers,
|
|
19
|
+
* from the request URL if invoked by a client,
|
|
20
|
+
* or as a fallback, from the `baseURL` in your auth config.
|
|
21
|
+
* If the URL is not inferred correctly, you can provide a value here."
|
|
22
|
+
*/
|
|
23
|
+
currentURL?: string | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* If a request in a production url it won't be proxied.
|
|
26
|
+
*
|
|
27
|
+
* default to `BETTER_AUTH_URL`
|
|
28
|
+
*/
|
|
29
|
+
productionURL?: string | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Maximum age in seconds for the encrypted payload.
|
|
32
|
+
* Payloads older than this will be rejected to prevent replay attacks.
|
|
33
|
+
*
|
|
34
|
+
* Keep this value short (e.g., 30-60 seconds) to minimize the window
|
|
35
|
+
* for potential replay attacks while still allowing normal OAuth flows.
|
|
36
|
+
*
|
|
37
|
+
* @default 60 (1 minute)
|
|
38
|
+
*/
|
|
39
|
+
maxAge?: number | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* A dedicated secret used to encrypt and decrypt data passed between
|
|
42
|
+
* servers during the OAuth proxy flow.
|
|
43
|
+
*
|
|
44
|
+
* When set, this secret is used **instead of** the global
|
|
45
|
+
* `BETTER_AUTH_SECRET` for all OAuth proxy encryption operations.
|
|
46
|
+
* This limits the blast radius if the secret is shared across
|
|
47
|
+
* environments (production, preview, development): a leaked proxy
|
|
48
|
+
* secret cannot be used to forge sessions or decrypt other data
|
|
49
|
+
* protected by the main secret.
|
|
50
|
+
*
|
|
51
|
+
* All environments participating in the OAuth proxy flow must share
|
|
52
|
+
* the same `secret` value.
|
|
53
|
+
*/
|
|
54
|
+
secret?: string | SecretConfig | undefined;
|
|
55
|
+
}
|
|
56
|
+
declare const oAuthProxy: <O extends OAuthProxyOptions>(opts?: O) => {
|
|
57
|
+
id: "oauth-proxy";
|
|
58
|
+
version: string;
|
|
59
|
+
options: NoInfer<O>;
|
|
60
|
+
endpoints: {
|
|
61
|
+
/**
|
|
62
|
+
* @deprecated OAuth proxy callbacks now use `/callback/:id/oauth-proxy`.
|
|
63
|
+
* This endpoint will be removed in the next minor release.
|
|
64
|
+
*/
|
|
65
|
+
oAuthProxy: _$better_call0.StrictEndpoint<"/oauth-proxy-callback", {
|
|
66
|
+
method: "GET";
|
|
67
|
+
operationId: string;
|
|
68
|
+
query: z.ZodObject<{
|
|
69
|
+
callbackURL: z.ZodString;
|
|
70
|
+
profile: z.ZodOptional<z.ZodString>;
|
|
71
|
+
}, z.core.$strip>;
|
|
72
|
+
use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<void>>[];
|
|
73
|
+
metadata: {
|
|
74
|
+
openapi: {
|
|
75
|
+
operationId: string;
|
|
76
|
+
deprecated: boolean;
|
|
77
|
+
description: string;
|
|
78
|
+
parameters: ({
|
|
79
|
+
in: "query";
|
|
80
|
+
name: string;
|
|
81
|
+
required: true;
|
|
82
|
+
description: string;
|
|
83
|
+
} | {
|
|
84
|
+
in: "query";
|
|
85
|
+
name: string;
|
|
86
|
+
required: false;
|
|
87
|
+
description: string;
|
|
88
|
+
})[];
|
|
89
|
+
responses: {
|
|
90
|
+
302: {
|
|
91
|
+
description: string;
|
|
92
|
+
headers: {
|
|
93
|
+
Location: {
|
|
94
|
+
description: string;
|
|
95
|
+
schema: {
|
|
96
|
+
type: string;
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
}, never>;
|
|
105
|
+
oAuthProxyCompletion: _$better_call0.StrictEndpoint<"/callback/:id/oauth-proxy", {
|
|
106
|
+
method: "GET";
|
|
107
|
+
operationId: string;
|
|
108
|
+
query: z.ZodObject<{
|
|
109
|
+
callbackURL: z.ZodString;
|
|
110
|
+
profile: z.ZodOptional<z.ZodString>;
|
|
111
|
+
}, z.core.$strip>;
|
|
112
|
+
use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<void>>[];
|
|
113
|
+
metadata: {
|
|
114
|
+
scope: "http";
|
|
115
|
+
};
|
|
116
|
+
}, never>;
|
|
117
|
+
};
|
|
118
|
+
hooks: {
|
|
119
|
+
before: {
|
|
120
|
+
matcher(context: _$_better_auth_core0.HookEndpointContext): boolean;
|
|
121
|
+
handler: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<void>>;
|
|
122
|
+
}[];
|
|
123
|
+
after: {
|
|
124
|
+
matcher(context: _$_better_auth_core0.HookEndpointContext): boolean;
|
|
125
|
+
handler: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<void>>;
|
|
126
|
+
}[];
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
//#endregion
|
|
130
|
+
export { OAuthProxyOptions, oAuthProxy };
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
import { isAPIError } from "../../utils/is-api-error.mjs";
|
|
2
|
+
import { getOrigin } from "../../utils/url.mjs";
|
|
3
|
+
import { originCheck } from "../../api/middlewares/origin-check.mjs";
|
|
4
|
+
import { parseSetCookieHeader } from "../../cookies/cookie-utils.mjs";
|
|
5
|
+
import { symmetricDecrypt, symmetricEncrypt } from "../../crypto/index.mjs";
|
|
6
|
+
import { setSessionCookie } from "../../cookies/index.mjs";
|
|
7
|
+
import { resolveOAuthAccountKey, toOAuthProfileRecord } from "../../oauth2/account-key.mjs";
|
|
8
|
+
import { redirectOnError } from "../../oauth2/errors.mjs";
|
|
9
|
+
import { getOAuthCallbackPath } from "../../oauth2/utils.mjs";
|
|
10
|
+
import { handleOAuthUserInfo } from "../../oauth2/link-account.mjs";
|
|
11
|
+
import { setOAuthState } from "../../api/state/oauth.mjs";
|
|
12
|
+
import { parseGenericState } from "../../state.mjs";
|
|
13
|
+
import { PACKAGE_VERSION } from "../../version.mjs";
|
|
14
|
+
import { parseJSON } from "../../client/parser.mjs";
|
|
15
|
+
import { checkSkipProxy, resolveCurrentURL, stripTrailingSlash } from "./utils.mjs";
|
|
16
|
+
import { accountSchema, userSchema } from "@better-auth/core/db";
|
|
17
|
+
import { safeJSONParse } from "@better-auth/core/utils/json";
|
|
18
|
+
import { defu } from "defu";
|
|
19
|
+
import { createAuthEndpoint, createAuthMiddleware } from "@better-auth/core/api";
|
|
20
|
+
import * as z from "zod";
|
|
21
|
+
//#region src/plugins/oauth-proxy/index.ts
|
|
22
|
+
/**
|
|
23
|
+
* Passthrough payload containing OAuth profile data.
|
|
24
|
+
* Used to transfer OAuth credentials from production to preview
|
|
25
|
+
* without creating user/session on production.
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
28
|
+
const passthroughPayloadSchema = z.looseObject({
|
|
29
|
+
userInfo: z.looseObject(userSchema.omit({
|
|
30
|
+
createdAt: true,
|
|
31
|
+
updatedAt: true
|
|
32
|
+
}).shape),
|
|
33
|
+
account: z.looseObject(accountSchema.omit({
|
|
34
|
+
id: true,
|
|
35
|
+
userId: true,
|
|
36
|
+
createdAt: true,
|
|
37
|
+
updatedAt: true
|
|
38
|
+
}).shape),
|
|
39
|
+
profile: z.record(z.string(), z.unknown()).optional(),
|
|
40
|
+
state: z.string().min(1),
|
|
41
|
+
callbackURL: z.string().min(1),
|
|
42
|
+
newUserURL: z.string().optional(),
|
|
43
|
+
errorURL: z.string().optional(),
|
|
44
|
+
disableSignUp: z.boolean().optional(),
|
|
45
|
+
timestamp: z.number()
|
|
46
|
+
});
|
|
47
|
+
const restoreOAuthProxyState = async (ctx, state) => {
|
|
48
|
+
try {
|
|
49
|
+
const stateData = await parseGenericState(ctx, state, { skipStateCookieCheck: true });
|
|
50
|
+
await setOAuthState(stateData);
|
|
51
|
+
return stateData;
|
|
52
|
+
} catch (e) {
|
|
53
|
+
ctx.context.logger.warn("OAuth proxy state missing or invalid", e);
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const oauthProxyQuerySchema = z.object({
|
|
58
|
+
callbackURL: z.string().meta({ description: "The URL to redirect to after the proxy" }),
|
|
59
|
+
profile: z.string().optional().meta({ description: "Encrypted OAuth profile data" })
|
|
60
|
+
});
|
|
61
|
+
const oauthCallbackQuerySchema = z.object({
|
|
62
|
+
code: z.string().optional(),
|
|
63
|
+
error: z.string().optional(),
|
|
64
|
+
user: z.string().optional()
|
|
65
|
+
});
|
|
66
|
+
const oAuthProxy = (opts) => {
|
|
67
|
+
const maxAge = opts?.maxAge ?? 60;
|
|
68
|
+
const getEncryptionKey = (ctx) => opts?.secret ?? ctx.context.secretConfig;
|
|
69
|
+
const oauthProxyCompletion = createAuthEndpoint("/callback/:id/oauth-proxy", {
|
|
70
|
+
method: "GET",
|
|
71
|
+
operationId: "oauthProxyCompletion",
|
|
72
|
+
query: oauthProxyQuerySchema,
|
|
73
|
+
use: [originCheck((ctx) => ctx.query.callbackURL)],
|
|
74
|
+
metadata: { scope: "http" }
|
|
75
|
+
}, async (ctx) => {
|
|
76
|
+
const baseURLStr = typeof ctx.context.options.baseURL === "string" ? ctx.context.options.baseURL : getOrigin(ctx.context.baseURL) || "";
|
|
77
|
+
const defaultErrorURL = ctx.context.options.onAPIError?.errorURL || `${stripTrailingSlash(baseURLStr)}/api/auth/error`;
|
|
78
|
+
const encryptedProfile = ctx.query.profile;
|
|
79
|
+
if (!encryptedProfile) {
|
|
80
|
+
ctx.context.logger.error("OAuth proxy callback missing profile data");
|
|
81
|
+
throw redirectOnError(ctx, defaultErrorURL, "missing_profile");
|
|
82
|
+
}
|
|
83
|
+
let decryptedPayload;
|
|
84
|
+
try {
|
|
85
|
+
decryptedPayload = await symmetricDecrypt({
|
|
86
|
+
key: getEncryptionKey(ctx),
|
|
87
|
+
data: encryptedProfile
|
|
88
|
+
});
|
|
89
|
+
} catch (e) {
|
|
90
|
+
ctx.context.logger.error("Failed to decrypt OAuth proxy profile", e);
|
|
91
|
+
throw redirectOnError(ctx, defaultErrorURL, "invalid_profile");
|
|
92
|
+
}
|
|
93
|
+
let payload;
|
|
94
|
+
try {
|
|
95
|
+
payload = passthroughPayloadSchema.parse(parseJSON(decryptedPayload));
|
|
96
|
+
} catch (e) {
|
|
97
|
+
ctx.context.logger.error("Failed to parse OAuth proxy payload", e);
|
|
98
|
+
throw redirectOnError(ctx, defaultErrorURL, "invalid_payload");
|
|
99
|
+
}
|
|
100
|
+
const errorURL = payload.errorURL || defaultErrorURL;
|
|
101
|
+
if (ctx.path?.startsWith("/callback/") && ctx.params.id !== payload.account.providerId) {
|
|
102
|
+
ctx.context.logger.warn("OAuth proxy callback provider mismatch");
|
|
103
|
+
throw redirectOnError(ctx, errorURL, "provider_mismatch");
|
|
104
|
+
}
|
|
105
|
+
const age = (Date.now() - payload.timestamp) / 1e3;
|
|
106
|
+
if (age > maxAge || age < -10) {
|
|
107
|
+
ctx.context.logger.error(`OAuth proxy payload expired or invalid (age: ${age}s, maxAge: ${maxAge}s)`);
|
|
108
|
+
throw redirectOnError(ctx, errorURL, "payload_expired");
|
|
109
|
+
}
|
|
110
|
+
if (!await restoreOAuthProxyState(ctx, payload.state)) throw redirectOnError(ctx, errorURL, "state_mismatch");
|
|
111
|
+
let result;
|
|
112
|
+
try {
|
|
113
|
+
result = await handleOAuthUserInfo(ctx, {
|
|
114
|
+
userInfo: payload.userInfo,
|
|
115
|
+
account: payload.account,
|
|
116
|
+
callbackURL: payload.callbackURL,
|
|
117
|
+
disableSignUp: payload.disableSignUp,
|
|
118
|
+
source: {
|
|
119
|
+
method: "oauth",
|
|
120
|
+
oauth: {
|
|
121
|
+
providerId: payload.account.providerId,
|
|
122
|
+
profile: payload.profile
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
} catch (e) {
|
|
127
|
+
if (isAPIError(e) && e.body?.code) throw redirectOnError(ctx, errorURL, e.body.code, e.body.message);
|
|
128
|
+
throw e;
|
|
129
|
+
}
|
|
130
|
+
if (result.error) {
|
|
131
|
+
ctx.context.logger.error("OAuth proxy callback error", result.error);
|
|
132
|
+
throw redirectOnError(ctx, errorURL, result.error.split(" ").join("_"));
|
|
133
|
+
}
|
|
134
|
+
if (!result.data) {
|
|
135
|
+
ctx.context.logger.error("OAuth proxy callback missing session data");
|
|
136
|
+
throw redirectOnError(ctx, errorURL, "user_creation_failed");
|
|
137
|
+
}
|
|
138
|
+
await setSessionCookie(ctx, result.data);
|
|
139
|
+
const finalURL = result.isRegister ? payload.newUserURL || payload.callbackURL : payload.callbackURL;
|
|
140
|
+
throw ctx.redirect(finalURL);
|
|
141
|
+
});
|
|
142
|
+
return {
|
|
143
|
+
id: "oauth-proxy",
|
|
144
|
+
version: PACKAGE_VERSION,
|
|
145
|
+
options: opts,
|
|
146
|
+
endpoints: {
|
|
147
|
+
/**
|
|
148
|
+
* @deprecated OAuth proxy callbacks now use `/callback/:id/oauth-proxy`.
|
|
149
|
+
* This endpoint will be removed in the next minor release.
|
|
150
|
+
*/
|
|
151
|
+
oAuthProxy: createAuthEndpoint("/oauth-proxy-callback", {
|
|
152
|
+
method: "GET",
|
|
153
|
+
operationId: "oauthProxyCallback",
|
|
154
|
+
query: oauthProxyQuerySchema,
|
|
155
|
+
use: [originCheck((ctx) => ctx.query.callbackURL)],
|
|
156
|
+
metadata: { openapi: {
|
|
157
|
+
operationId: "oauthProxyCallback",
|
|
158
|
+
deprecated: true,
|
|
159
|
+
description: "OAuth Proxy Callback",
|
|
160
|
+
parameters: [{
|
|
161
|
+
in: "query",
|
|
162
|
+
name: "callbackURL",
|
|
163
|
+
required: true,
|
|
164
|
+
description: "The URL to redirect to after the proxy"
|
|
165
|
+
}, {
|
|
166
|
+
in: "query",
|
|
167
|
+
name: "profile",
|
|
168
|
+
required: false,
|
|
169
|
+
description: "Encrypted OAuth profile data"
|
|
170
|
+
}],
|
|
171
|
+
responses: { 302: {
|
|
172
|
+
description: "Redirect",
|
|
173
|
+
headers: { Location: {
|
|
174
|
+
description: "The URL to redirect to",
|
|
175
|
+
schema: { type: "string" }
|
|
176
|
+
} }
|
|
177
|
+
} }
|
|
178
|
+
} }
|
|
179
|
+
}, async (ctx) => oauthProxyCompletion({
|
|
180
|
+
...ctx,
|
|
181
|
+
params: { id: "oauth-proxy" }
|
|
182
|
+
})),
|
|
183
|
+
oAuthProxyCompletion: oauthProxyCompletion
|
|
184
|
+
},
|
|
185
|
+
hooks: {
|
|
186
|
+
before: [{
|
|
187
|
+
matcher(context) {
|
|
188
|
+
return !!context.path?.startsWith("/sign-in/social");
|
|
189
|
+
},
|
|
190
|
+
handler: createAuthMiddleware(async (ctx) => {
|
|
191
|
+
if (checkSkipProxy(ctx, opts)) return;
|
|
192
|
+
const providerId = ctx.body?.provider;
|
|
193
|
+
if (!providerId) return;
|
|
194
|
+
const currentURL = resolveCurrentURL(ctx, opts);
|
|
195
|
+
const productionURL = opts?.productionURL;
|
|
196
|
+
const originalCallbackURL = ctx.body?.callbackURL || ctx.context.baseURL;
|
|
197
|
+
if (productionURL) {
|
|
198
|
+
const productionBaseURL = `${stripTrailingSlash(productionURL)}${ctx.context.options.basePath || "/api/auth"}`;
|
|
199
|
+
ctx.context.baseURL = productionBaseURL;
|
|
200
|
+
}
|
|
201
|
+
const newCallbackURL = `${stripTrailingSlash(currentURL.origin)}${ctx.context.options.basePath || "/api/auth"}/callback/${providerId}/oauth-proxy?callbackURL=${encodeURIComponent(originalCallbackURL)}`;
|
|
202
|
+
ctx.body.callbackURL = newCallbackURL;
|
|
203
|
+
})
|
|
204
|
+
}, {
|
|
205
|
+
matcher(context) {
|
|
206
|
+
return context.path === "/callback/:id";
|
|
207
|
+
},
|
|
208
|
+
handler: createAuthMiddleware(async (ctx) => {
|
|
209
|
+
const callbackParams = defu(ctx.query, ctx.body);
|
|
210
|
+
const state = callbackParams.state;
|
|
211
|
+
if (!state || typeof state !== "string") return;
|
|
212
|
+
let statePackage;
|
|
213
|
+
try {
|
|
214
|
+
statePackage = parseJSON(await symmetricDecrypt({
|
|
215
|
+
key: getEncryptionKey(ctx),
|
|
216
|
+
data: state
|
|
217
|
+
}));
|
|
218
|
+
} catch {
|
|
219
|
+
ctx.context.logger.debug("OAuth proxy: could not decrypt state package, falling back to regular callback");
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (!statePackage.isOAuthProxy || !statePackage.state || !statePackage.stateCookie) {
|
|
223
|
+
ctx.context.logger.warn("Invalid OAuth proxy state package");
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const query = oauthCallbackQuerySchema.safeParse(callbackParams);
|
|
227
|
+
if (!query.success) {
|
|
228
|
+
ctx.context.logger.warn("Invalid OAuth callback query", query.error);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const { code, error, user: userData } = query.data;
|
|
232
|
+
let stateData;
|
|
233
|
+
try {
|
|
234
|
+
stateData = parseJSON(await symmetricDecrypt({
|
|
235
|
+
key: getEncryptionKey(ctx),
|
|
236
|
+
data: statePackage.stateCookie
|
|
237
|
+
}));
|
|
238
|
+
} catch (e) {
|
|
239
|
+
ctx.context.logger.error("Failed to decrypt OAuth proxy state cookie:", e);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const errorURL = stateData.errorURL || ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`;
|
|
243
|
+
if (stateData.oauthState !== void 0 && stateData.oauthState !== statePackage.state) {
|
|
244
|
+
ctx.context.logger.error("OAuth proxy state binding mismatch");
|
|
245
|
+
throw redirectOnError(ctx, errorURL, "state_mismatch");
|
|
246
|
+
}
|
|
247
|
+
if (error) throw redirectOnError(ctx, errorURL, error);
|
|
248
|
+
if (!code) {
|
|
249
|
+
ctx.context.logger.warn("OAuth callback missing authorization code");
|
|
250
|
+
throw redirectOnError(ctx, errorURL, "no_code");
|
|
251
|
+
}
|
|
252
|
+
const providerId = ctx.params?.id;
|
|
253
|
+
const provider = ctx.context.socialProviders.find((p) => p.id === providerId);
|
|
254
|
+
if (!provider) {
|
|
255
|
+
ctx.context.logger.warn("OAuth provider not found", { providerId });
|
|
256
|
+
throw redirectOnError(ctx, errorURL, "oauth_provider_not_found");
|
|
257
|
+
}
|
|
258
|
+
let tokens;
|
|
259
|
+
try {
|
|
260
|
+
tokens = await provider.validateAuthorizationCode({
|
|
261
|
+
code,
|
|
262
|
+
codeVerifier: stateData.codeVerifier,
|
|
263
|
+
redirectURI: `${ctx.context.baseURL}${getOAuthCallbackPath(provider)}`
|
|
264
|
+
});
|
|
265
|
+
} catch (e) {
|
|
266
|
+
ctx.context.logger.error("Failed to validate authorization code", e);
|
|
267
|
+
throw redirectOnError(ctx, errorURL, "invalid_code");
|
|
268
|
+
}
|
|
269
|
+
if (!tokens) throw redirectOnError(ctx, errorURL, "invalid_code");
|
|
270
|
+
const parsedUserData = userData ? safeJSONParse(userData) : null;
|
|
271
|
+
const userInfoResult = await provider.getUserInfo({
|
|
272
|
+
...tokens,
|
|
273
|
+
/**
|
|
274
|
+
* The user object from the provider
|
|
275
|
+
* This is only available for some providers like Apple
|
|
276
|
+
*/
|
|
277
|
+
user: parsedUserData ?? void 0
|
|
278
|
+
});
|
|
279
|
+
const userInfo = userInfoResult?.user;
|
|
280
|
+
if (!userInfo) {
|
|
281
|
+
ctx.context.logger.error("Unable to get user info from provider");
|
|
282
|
+
throw redirectOnError(ctx, errorURL, "unable_to_get_user_info");
|
|
283
|
+
}
|
|
284
|
+
if (!userInfo.email) {
|
|
285
|
+
ctx.context.logger.error("Provider did not return email");
|
|
286
|
+
throw redirectOnError(ctx, errorURL, "email_not_found");
|
|
287
|
+
}
|
|
288
|
+
let accountKey;
|
|
289
|
+
try {
|
|
290
|
+
accountKey = await resolveOAuthAccountKey(provider, tokens, userInfoResult.data);
|
|
291
|
+
} catch (error) {
|
|
292
|
+
ctx.context.logger.error("Unable to derive provider account identity", {
|
|
293
|
+
providerId: provider.id,
|
|
294
|
+
error
|
|
295
|
+
});
|
|
296
|
+
throw redirectOnError(ctx, errorURL, "unable_to_get_user_info");
|
|
297
|
+
}
|
|
298
|
+
const providerProfile = toOAuthProfileRecord(userInfoResult.data);
|
|
299
|
+
const proxyCallbackURL = new URL(stateData.callbackURL);
|
|
300
|
+
const finalCallbackURL = proxyCallbackURL.searchParams.get("callbackURL") || stateData.callbackURL;
|
|
301
|
+
const payload = {
|
|
302
|
+
userInfo: {
|
|
303
|
+
id: accountKey.accountId,
|
|
304
|
+
email: userInfo.email,
|
|
305
|
+
name: userInfo.name || "",
|
|
306
|
+
image: userInfo.image,
|
|
307
|
+
emailVerified: userInfo.emailVerified
|
|
308
|
+
},
|
|
309
|
+
profile: providerProfile,
|
|
310
|
+
account: {
|
|
311
|
+
...accountKey,
|
|
312
|
+
accessToken: tokens.accessToken,
|
|
313
|
+
refreshToken: tokens.refreshToken,
|
|
314
|
+
idToken: tokens.idToken,
|
|
315
|
+
accessTokenExpiresAt: tokens.accessTokenExpiresAt,
|
|
316
|
+
refreshTokenExpiresAt: tokens.refreshTokenExpiresAt,
|
|
317
|
+
scope: tokens.scopes?.join(",")
|
|
318
|
+
},
|
|
319
|
+
state: statePackage.state,
|
|
320
|
+
callbackURL: finalCallbackURL,
|
|
321
|
+
newUserURL: stateData.newUserURL,
|
|
322
|
+
errorURL: stateData.errorURL,
|
|
323
|
+
disableSignUp: provider.disableImplicitSignUp && !stateData.requestSignUp || provider.options?.disableSignUp,
|
|
324
|
+
timestamp: Date.now()
|
|
325
|
+
};
|
|
326
|
+
const encryptedPayload = await symmetricEncrypt({
|
|
327
|
+
key: getEncryptionKey(ctx),
|
|
328
|
+
data: JSON.stringify(payload)
|
|
329
|
+
});
|
|
330
|
+
proxyCallbackURL.searchParams.set("profile", encryptedPayload);
|
|
331
|
+
throw ctx.redirect(proxyCallbackURL.toString());
|
|
332
|
+
})
|
|
333
|
+
}],
|
|
334
|
+
after: [{
|
|
335
|
+
matcher(context) {
|
|
336
|
+
return !!context.path?.startsWith("/sign-in/social");
|
|
337
|
+
},
|
|
338
|
+
handler: createAuthMiddleware(async (ctx) => {
|
|
339
|
+
if (checkSkipProxy(ctx, opts)) return;
|
|
340
|
+
const signInResponse = ctx.context.returned;
|
|
341
|
+
if (!signInResponse || typeof signInResponse !== "object" || !("url" in signInResponse)) return;
|
|
342
|
+
const { url: providerURL } = signInResponse;
|
|
343
|
+
if (typeof providerURL !== "string") return;
|
|
344
|
+
const oauthURL = new URL(providerURL);
|
|
345
|
+
const originalState = oauthURL.searchParams.get("state");
|
|
346
|
+
if (!originalState) return;
|
|
347
|
+
try {
|
|
348
|
+
let plaintextState;
|
|
349
|
+
if (ctx.context.oauthConfig.storeStateStrategy === "cookie") {
|
|
350
|
+
const setCookieHeader = ctx.context.responseHeaders?.get("set-cookie");
|
|
351
|
+
if (setCookieHeader) {
|
|
352
|
+
const oauthStateCookie = ctx.context.createAuthCookie("oauth_state");
|
|
353
|
+
const encryptedCookieValue = parseSetCookieHeader(setCookieHeader).get(oauthStateCookie.name)?.value;
|
|
354
|
+
if (encryptedCookieValue) plaintextState = await symmetricDecrypt({
|
|
355
|
+
key: ctx.context.secretConfig,
|
|
356
|
+
data: encryptedCookieValue
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
} else plaintextState = (await ctx.context.internalAdapter.findVerificationValue(originalState))?.value;
|
|
360
|
+
if (!plaintextState) {
|
|
361
|
+
ctx.context.logger.warn("No OAuth state found for proxy");
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const statePackage = {
|
|
365
|
+
state: originalState,
|
|
366
|
+
stateCookie: await symmetricEncrypt({
|
|
367
|
+
key: getEncryptionKey(ctx),
|
|
368
|
+
data: plaintextState
|
|
369
|
+
}),
|
|
370
|
+
isOAuthProxy: true
|
|
371
|
+
};
|
|
372
|
+
const encryptedPackage = await symmetricEncrypt({
|
|
373
|
+
key: getEncryptionKey(ctx),
|
|
374
|
+
data: JSON.stringify(statePackage)
|
|
375
|
+
});
|
|
376
|
+
oauthURL.searchParams.set("state", encryptedPackage);
|
|
377
|
+
ctx.context.returned = {
|
|
378
|
+
...signInResponse,
|
|
379
|
+
url: oauthURL.toString()
|
|
380
|
+
};
|
|
381
|
+
} catch (e) {
|
|
382
|
+
ctx.context.logger.error("Failed to prepare OAuth proxy state:", e);
|
|
383
|
+
}
|
|
384
|
+
})
|
|
385
|
+
}, {
|
|
386
|
+
matcher(context) {
|
|
387
|
+
return context.path === "/callback/:id";
|
|
388
|
+
},
|
|
389
|
+
handler: createAuthMiddleware(async (ctx) => {
|
|
390
|
+
const location = ctx.context.responseHeaders?.get("location");
|
|
391
|
+
if (!location?.includes("/oauth-proxy?callbackURL") && !location?.includes("/oauth-proxy-callback?callbackURL") || !location.startsWith("http")) return;
|
|
392
|
+
const productionOrigin = getOrigin(opts?.productionURL || (typeof ctx.context.options.baseURL === "string" ? ctx.context.options.baseURL : void 0) || ctx.context.baseURL);
|
|
393
|
+
const locationURL = new URL(location);
|
|
394
|
+
if (locationURL.origin === productionOrigin) {
|
|
395
|
+
const newLocation = locationURL.searchParams.get("callbackURL");
|
|
396
|
+
if (!newLocation) return;
|
|
397
|
+
ctx.setHeader("location", newLocation);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
ctx.context.logger.warn("OAuth proxy: cross-origin callback reached after hook unexpectedly");
|
|
401
|
+
})
|
|
402
|
+
}]
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
};
|
|
406
|
+
//#endregion
|
|
407
|
+
export { oAuthProxy };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { getOrigin, trimTrailingSlashes } from "../../utils/url.mjs";
|
|
2
|
+
import { env } from "@better-auth/core/env";
|
|
3
|
+
//#region src/plugins/oauth-proxy/utils.ts
|
|
4
|
+
/**
|
|
5
|
+
* Strip trailing slashes from URL to prevent double slashes
|
|
6
|
+
*/
|
|
7
|
+
function stripTrailingSlash(url) {
|
|
8
|
+
if (!url) return "";
|
|
9
|
+
return trimTrailingSlashes(url);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Get base URL from vendor-specific environment variables
|
|
13
|
+
*/
|
|
14
|
+
function getVendorBaseURL() {
|
|
15
|
+
const vercel = env.VERCEL_URL ? `https://${env.VERCEL_URL}` : void 0;
|
|
16
|
+
const netlify = env.NETLIFY_URL;
|
|
17
|
+
const render = env.RENDER_URL;
|
|
18
|
+
const aws = env.AWS_LAMBDA_FUNCTION_NAME;
|
|
19
|
+
const google = env.GOOGLE_CLOUD_FUNCTION_NAME;
|
|
20
|
+
const azure = env.AZURE_FUNCTION_NAME;
|
|
21
|
+
return vercel || netlify || render || aws || google || azure;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolve the current URL from various sources.
|
|
25
|
+
*
|
|
26
|
+
* The request URL host can come from an untrusted source (`Host` / forwarded host),
|
|
27
|
+
* and this origin becomes the receiver for the encrypted OAuth profile replay.
|
|
28
|
+
* So a request-derived origin is only honored when it is an explicitly trusted
|
|
29
|
+
* origin; otherwise resolution falls back to the configured platform/base URL,
|
|
30
|
+
* never the raw request host. An explicit `opts.currentURL` and the vendor/base
|
|
31
|
+
* URLs are configured by the developer and trusted as-is.
|
|
32
|
+
*/
|
|
33
|
+
function resolveCurrentURL(ctx, opts) {
|
|
34
|
+
if (opts?.currentURL) return new URL(opts.currentURL);
|
|
35
|
+
const requestURL = ctx.request?.url;
|
|
36
|
+
if (requestURL) {
|
|
37
|
+
const origin = getOrigin(requestURL);
|
|
38
|
+
if (origin && ctx.context.isTrustedOrigin(origin)) return new URL(requestURL);
|
|
39
|
+
}
|
|
40
|
+
const vendorBaseURL = getVendorBaseURL();
|
|
41
|
+
return new URL(vendorBaseURL && getOrigin(vendorBaseURL) ? vendorBaseURL : ctx.context.baseURL);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Check if the proxy should be skipped for this request
|
|
45
|
+
*/
|
|
46
|
+
function checkSkipProxy(ctx, opts) {
|
|
47
|
+
if (ctx.request?.headers.get("x-skip-oauth-proxy")) return true;
|
|
48
|
+
const productionURL = opts?.productionURL || env.BETTER_AUTH_URL || ctx.context.baseURL;
|
|
49
|
+
if (!productionURL) return false;
|
|
50
|
+
const currentURL = opts?.currentURL || ctx.request?.url || getVendorBaseURL();
|
|
51
|
+
if (!currentURL) return false;
|
|
52
|
+
return getOrigin(productionURL) === getOrigin(currentURL);
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { checkSkipProxy, resolveCurrentURL, stripTrailingSlash };
|