better-auth 1.2.0-beta.16 → 1.2.0-beta.19
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/dist/adapters/drizzle-adapter/drizzle-adapter.d.ts +67 -0
- package/dist/adapters/drizzle-adapter/drizzle-adapter.d.ts.map +1 -0
- package/dist/adapters/drizzle-adapter/index.cjs +285 -0
- package/dist/adapters/drizzle-adapter/index.d.ts +2 -0
- package/dist/adapters/drizzle-adapter/index.d.ts.map +1 -0
- package/dist/adapters/drizzle-adapter/index.mjs +283 -0
- package/dist/adapters/kysely-adapter/dialect.d.ts +8 -0
- package/dist/adapters/kysely-adapter/dialect.d.ts.map +1 -0
- package/dist/adapters/kysely-adapter/index.cjs +29 -0
- package/dist/adapters/kysely-adapter/index.d.ts +4 -0
- package/dist/adapters/kysely-adapter/index.d.ts.map +1 -0
- package/dist/adapters/kysely-adapter/index.mjs +22 -0
- package/dist/adapters/kysely-adapter/kysely-adapter.d.ts +57 -0
- package/dist/adapters/kysely-adapter/kysely-adapter.d.ts.map +1 -0
- package/dist/adapters/kysely-adapter/types.d.ts +2 -0
- package/dist/adapters/kysely-adapter/types.d.ts.map +1 -0
- package/dist/adapters/memory-adapter/index.cjs +28 -0
- package/dist/adapters/memory-adapter/index.d.ts +2 -0
- package/dist/adapters/memory-adapter/index.d.ts.map +1 -0
- package/dist/adapters/memory-adapter/index.mjs +22 -0
- package/dist/adapters/memory-adapter/memory-adapter.d.ts +50 -0
- package/dist/adapters/memory-adapter/memory-adapter.d.ts.map +1 -0
- package/dist/adapters/mongodb-adapter/index.cjs +282 -0
- package/dist/adapters/mongodb-adapter/index.d.ts +2 -0
- package/dist/adapters/mongodb-adapter/index.d.ts.map +1 -0
- package/dist/adapters/mongodb-adapter/index.mjs +280 -0
- package/dist/adapters/mongodb-adapter/mongodb-adapter.d.ts +48 -0
- package/dist/adapters/mongodb-adapter/mongodb-adapter.d.ts.map +1 -0
- package/dist/adapters/prisma-adapter/index.cjs +254 -0
- package/dist/adapters/prisma-adapter/index.d.ts +2 -0
- package/dist/adapters/prisma-adapter/index.d.ts.map +1 -0
- package/dist/adapters/prisma-adapter/index.mjs +252 -0
- package/dist/adapters/prisma-adapter/prisma-adapter.d.ts +57 -0
- package/dist/adapters/prisma-adapter/prisma-adapter.d.ts.map +1 -0
- package/dist/adapters/test.cjs +18 -6
- package/dist/adapters/test.d.ts +4 -12
- package/dist/adapters/test.d.ts.map +1 -0
- package/dist/adapters/test.mjs +439 -0
- package/dist/adapters/utils.d.ts +3 -0
- package/dist/adapters/utils.d.ts.map +1 -0
- package/dist/api/call.d.ts +1143 -0
- package/dist/api/call.d.ts.map +1 -0
- package/dist/api/index.cjs +788 -0
- package/dist/api/index.d.ts +7145 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.mjs +745 -0
- package/dist/api/middlewares/index.d.ts +2 -0
- package/dist/api/middlewares/index.d.ts.map +1 -0
- package/dist/api/middlewares/origin-check.d.ts +24 -0
- package/dist/api/middlewares/origin-check.d.ts.map +1 -0
- package/dist/api/rate-limiter/index.d.ts +7 -0
- package/dist/api/rate-limiter/index.d.ts.map +1 -0
- package/dist/api/routes/account.d.ts +283 -0
- package/dist/api/routes/account.d.ts.map +1 -0
- package/dist/api/routes/callback.d.ts +84 -0
- package/dist/api/routes/callback.d.ts.map +1 -0
- package/dist/api/routes/email-verification.d.ts +205 -0
- package/dist/api/routes/email-verification.d.ts.map +1 -0
- package/dist/api/routes/error.d.ts +46 -0
- package/dist/api/routes/error.d.ts.map +1 -0
- package/dist/api/routes/forget-password.d.ts +221 -0
- package/dist/api/routes/forget-password.d.ts.map +1 -0
- package/dist/api/routes/index.d.ts +12 -0
- package/dist/api/routes/index.d.ts.map +1 -0
- package/dist/api/routes/ok.d.ts +55 -0
- package/dist/api/routes/ok.d.ts.map +1 -0
- package/dist/api/routes/session.d.ts +606 -0
- package/dist/api/routes/session.d.ts.map +1 -0
- package/dist/api/routes/sign-in.d.ts +329 -0
- package/dist/api/routes/sign-in.d.ts.map +1 -0
- package/dist/api/routes/sign-out.d.ts +55 -0
- package/dist/api/routes/sign-out.d.ts.map +1 -0
- package/dist/api/routes/sign-up.d.ts +768 -0
- package/dist/api/routes/sign-up.d.ts.map +1 -0
- package/dist/api/routes/update-user.d.ts +1160 -0
- package/dist/api/routes/update-user.d.ts.map +1 -0
- package/dist/api/to-auth-endpoints.d.ts +4 -0
- package/dist/api/to-auth-endpoints.d.ts.map +1 -0
- package/dist/auth.d.ts +3590 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/client/config.d.ts +74 -0
- package/dist/client/config.d.ts.map +1 -0
- package/dist/client/fetch-plugins.d.ts +8 -0
- package/dist/client/fetch-plugins.d.ts.map +1 -0
- package/dist/client/index.cjs +51 -0
- package/dist/client/index.d.ts +11 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.mjs +47 -0
- package/dist/client/parser.d.ts +13 -0
- package/dist/client/parser.d.ts.map +1 -0
- package/dist/client/path-to-object.d.ts +63 -0
- package/dist/client/path-to-object.d.ts.map +1 -0
- package/dist/client/plugins/index.cjs +569 -0
- package/dist/client/plugins/index.d.ts +21 -0
- package/dist/client/plugins/index.d.ts.map +1 -0
- package/dist/client/plugins/index.mjs +548 -0
- package/dist/client/plugins/infer-plugin.d.ts +12 -0
- package/dist/client/plugins/infer-plugin.d.ts.map +1 -0
- package/dist/client/proxy.d.ts +9 -0
- package/dist/client/proxy.d.ts.map +1 -0
- package/dist/client/query.d.ts +14 -0
- package/dist/client/query.d.ts.map +1 -0
- package/dist/client/react/index.cjs +65 -0
- package/dist/client/react/index.d.ts +113 -0
- package/dist/client/react/index.d.ts.map +1 -0
- package/dist/client/react/index.mjs +61 -0
- package/dist/client/react/react-store.d.ts +21 -0
- package/dist/client/react/react-store.d.ts.map +1 -0
- package/dist/client/session-atom.d.ts +16 -0
- package/dist/client/session-atom.d.ts.map +1 -0
- package/dist/client/solid/index.cjs +58 -0
- package/dist/client/solid/index.d.ts +106 -0
- package/dist/client/solid/index.d.ts.map +1 -0
- package/dist/client/solid/index.mjs +56 -0
- package/dist/client/solid/solid-store.d.ts +10 -0
- package/dist/client/solid/solid-store.d.ts.map +1 -0
- package/dist/client/svelte/index.cjs +42 -0
- package/dist/client/svelte/index.d.ts +111 -0
- package/dist/client/svelte/index.d.ts.map +1 -0
- package/dist/client/svelte/index.mjs +40 -0
- package/dist/client/test-plugin.d.ts +130 -0
- package/dist/client/test-plugin.d.ts.map +1 -0
- package/dist/client/types.d.ts +79 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/vanilla.d.ts +110 -0
- package/dist/client/vanilla.d.ts.map +1 -0
- package/dist/client/vue/index.cjs +87 -0
- package/dist/client/vue/index.d.ts +134 -0
- package/dist/client/vue/index.d.ts.map +1 -0
- package/dist/client/vue/index.mjs +85 -0
- package/dist/client/vue/vue-store.d.ts +5 -0
- package/dist/client/vue/vue-store.d.ts.map +1 -0
- package/dist/cookies/check-cookies.d.ts +5 -0
- package/dist/cookies/check-cookies.d.ts.map +1 -0
- package/dist/cookies/cookie-utils.d.ts +17 -0
- package/dist/cookies/cookie-utils.d.ts.map +1 -0
- package/dist/cookies/index.cjs +392 -0
- package/dist/cookies/index.d.ts +51 -0
- package/dist/cookies/index.d.ts.map +1 -0
- package/dist/cookies/index.mjs +381 -0
- package/dist/crypto/buffer.d.ts +5 -0
- package/dist/crypto/buffer.d.ts.map +1 -0
- package/dist/crypto/hash.d.ts +3 -0
- package/dist/crypto/hash.d.ts.map +1 -0
- package/dist/crypto/index.cjs +57 -0
- package/dist/crypto/index.d.ts +16 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.mjs +48 -0
- package/dist/crypto/jwt.d.ts +2 -0
- package/dist/crypto/jwt.d.ts.map +1 -0
- package/dist/crypto/password.d.ts +6 -0
- package/dist/crypto/password.d.ts.map +1 -0
- package/dist/crypto/random.d.ts +2 -0
- package/dist/crypto/random.d.ts.map +1 -0
- package/dist/db/field.d.ts +148 -0
- package/dist/db/field.d.ts.map +1 -0
- package/dist/db/get-migration.d.ts +19 -0
- package/dist/db/get-migration.d.ts.map +1 -0
- package/dist/db/get-schema.d.ts +7 -0
- package/dist/db/get-schema.d.ts.map +1 -0
- package/dist/db/get-tables.d.ts +23 -0
- package/dist/db/get-tables.d.ts.map +1 -0
- package/dist/db/index.cjs +99 -0
- package/dist/db/index.d.ts +10 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.mjs +72 -0
- package/dist/db/internal-adapter.d.ts +219 -0
- package/dist/db/internal-adapter.d.ts.map +1 -0
- package/dist/db/schema.d.ts +216 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/to-zod.d.ts +4 -0
- package/dist/db/to-zod.d.ts.map +1 -0
- package/dist/db/utils.d.ts +6 -0
- package/dist/db/utils.d.ts.map +1 -0
- package/dist/db/with-hooks.d.ts +19 -0
- package/dist/db/with-hooks.d.ts.map +1 -0
- package/dist/error/codes.d.ts +26 -0
- package/dist/error/codes.d.ts.map +1 -0
- package/dist/error/index.d.ts +7 -0
- package/dist/error/index.d.ts.map +1 -0
- package/dist/index.cjs +98 -101
- package/dist/index.d.ts +7 -26
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +249 -0
- package/dist/init.d.ts +71 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/integrations/next-js.cjs +101 -0
- package/dist/integrations/next-js.d.ts +24 -0
- package/dist/integrations/next-js.d.ts.map +1 -0
- package/dist/integrations/next-js.mjs +98 -0
- package/dist/integrations/node.cjs +23 -0
- package/dist/integrations/node.d.ts +7 -0
- package/dist/integrations/node.d.ts.map +1 -0
- package/dist/integrations/node.mjs +20 -0
- package/dist/integrations/solid-start.cjs +13 -0
- package/dist/integrations/solid-start.d.ts +11 -0
- package/dist/integrations/solid-start.d.ts.map +1 -0
- package/dist/integrations/solid-start.mjs +11 -0
- package/dist/integrations/svelte-kit.cjs +37 -0
- package/dist/integrations/svelte-kit.d.ts +20 -0
- package/dist/integrations/svelte-kit.d.ts.map +1 -0
- package/dist/integrations/svelte-kit.mjs +33 -0
- package/dist/oauth2/create-authorization-url.d.ts +14 -0
- package/dist/oauth2/create-authorization-url.d.ts.map +1 -0
- package/dist/oauth2/index.cjs +30 -0
- package/dist/oauth2/index.d.ts +6 -0
- package/dist/oauth2/index.d.ts.map +1 -0
- package/dist/oauth2/index.mjs +18 -0
- package/dist/oauth2/link-account.d.ts +40 -0
- package/dist/oauth2/link-account.d.ts.map +1 -0
- package/dist/oauth2/state.d.ts +20 -0
- package/dist/oauth2/state.d.ts.map +1 -0
- package/dist/oauth2/types.d.ts +112 -0
- package/dist/oauth2/types.d.ts.map +1 -0
- package/dist/oauth2/utils.d.ts +4 -0
- package/dist/oauth2/utils.d.ts.map +1 -0
- package/dist/oauth2/validate-authorization-code.d.ts +12 -0
- package/dist/oauth2/validate-authorization-code.d.ts.map +1 -0
- package/dist/plugins/access/access.d.ts +26 -0
- package/dist/plugins/access/access.d.ts.map +1 -0
- package/dist/plugins/access/index.cjs +72 -0
- package/dist/plugins/access/index.d.ts +3 -0
- package/dist/plugins/access/index.d.ts.map +1 -0
- package/dist/plugins/access/index.mjs +69 -0
- package/dist/plugins/access/types.d.ts +15 -0
- package/dist/plugins/access/types.d.ts.map +1 -0
- package/dist/plugins/additional-fields/client.d.ts +93 -0
- package/dist/plugins/additional-fields/client.d.ts.map +1 -0
- package/dist/plugins/admin/access/index.cjs +28 -0
- package/dist/plugins/admin/access/index.d.ts +2 -0
- package/dist/plugins/admin/access/index.d.ts.map +1 -0
- package/dist/plugins/admin/access/index.mjs +22 -0
- package/dist/plugins/admin/access/statement.d.ts +111 -0
- package/dist/plugins/admin/access/statement.d.ts.map +1 -0
- package/dist/plugins/admin/admin.d.ts +1390 -0
- package/dist/plugins/admin/admin.d.ts.map +1 -0
- package/dist/plugins/admin/call.d.ts +23 -0
- package/dist/plugins/admin/call.d.ts.map +1 -0
- package/dist/plugins/admin/client.d.ts +43 -0
- package/dist/plugins/admin/client.d.ts.map +1 -0
- package/dist/plugins/admin/error-codes.d.ts +14 -0
- package/dist/plugins/admin/error-codes.d.ts.map +1 -0
- package/dist/plugins/admin/has-permission.d.ts +10 -0
- package/dist/plugins/admin/has-permission.d.ts.map +1 -0
- package/dist/plugins/admin/index.cjs +44 -0
- package/dist/plugins/admin/index.d.ts +2 -0
- package/dist/plugins/admin/index.d.ts.map +1 -0
- package/dist/plugins/admin/index.mjs +38 -0
- package/dist/plugins/anonymous/client.d.ts +9 -0
- package/dist/plugins/anonymous/client.d.ts.map +1 -0
- package/dist/plugins/anonymous/index.cjs +186 -0
- package/dist/plugins/anonymous/index.d.ts +152 -0
- package/dist/plugins/anonymous/index.d.ts.map +1 -0
- package/dist/plugins/anonymous/index.mjs +184 -0
- package/dist/plugins/api-key/client.d.ts +9 -0
- package/dist/plugins/api-key/client.d.ts.map +1 -0
- package/dist/plugins/api-key/index.d.ts +873 -0
- package/dist/plugins/api-key/index.d.ts.map +1 -0
- package/dist/plugins/api-key/rate-limit.d.ts +21 -0
- package/dist/plugins/api-key/rate-limit.d.ts.map +1 -0
- package/dist/plugins/api-key/routes/create-api-key.d.ts +137 -0
- package/dist/plugins/api-key/routes/create-api-key.d.ts.map +1 -0
- package/dist/plugins/api-key/routes/delete-all-expired-api-keys.d.ts +40 -0
- package/dist/plugins/api-key/routes/delete-all-expired-api-keys.d.ts.map +1 -0
- package/dist/plugins/api-key/routes/delete-api-key.d.ts +80 -0
- package/dist/plugins/api-key/routes/delete-api-key.d.ts.map +1 -0
- package/dist/plugins/api-key/routes/get-api-key.d.ts +118 -0
- package/dist/plugins/api-key/routes/get-api-key.d.ts.map +1 -0
- package/dist/plugins/api-key/routes/index.d.ts +709 -0
- package/dist/plugins/api-key/routes/index.d.ts.map +1 -0
- package/dist/plugins/api-key/routes/list-api-keys.d.ts +108 -0
- package/dist/plugins/api-key/routes/list-api-keys.d.ts.map +1 -0
- package/dist/plugins/api-key/routes/update-api-key.d.ts +135 -0
- package/dist/plugins/api-key/routes/update-api-key.d.ts.map +1 -0
- package/dist/plugins/api-key/routes/verify-api-key.d.ts +137 -0
- package/dist/plugins/api-key/routes/verify-api-key.d.ts.map +1 -0
- package/dist/plugins/api-key/schema.d.ts +189 -0
- package/dist/plugins/api-key/schema.d.ts.map +1 -0
- package/dist/plugins/api-key/types.d.ts +267 -0
- package/dist/plugins/api-key/types.d.ts.map +1 -0
- package/dist/plugins/bearer/index.cjs +120 -0
- package/dist/plugins/bearer/index.d.ts +48 -0
- package/dist/plugins/bearer/index.d.ts.map +1 -0
- package/dist/plugins/bearer/index.mjs +118 -0
- package/dist/plugins/captcha/constants.d.ts +8 -0
- package/dist/plugins/captcha/constants.d.ts.map +1 -0
- package/dist/plugins/captcha/error-codes.d.ts +7 -0
- package/dist/plugins/captcha/error-codes.d.ts.map +1 -0
- package/dist/plugins/captcha/index.cjs +134 -0
- package/dist/plugins/captcha/index.d.ts +14 -0
- package/dist/plugins/captcha/index.d.ts.map +1 -0
- package/dist/plugins/captcha/index.mjs +132 -0
- package/dist/plugins/captcha/types.d.ts +21 -0
- package/dist/plugins/captcha/types.d.ts.map +1 -0
- package/dist/plugins/captcha/verify-handlers/cloudflare-turnstile.d.ts +10 -0
- package/dist/plugins/captcha/verify-handlers/cloudflare-turnstile.d.ts.map +1 -0
- package/dist/plugins/captcha/verify-handlers/google-recaptcha.d.ts +10 -0
- package/dist/plugins/captcha/verify-handlers/google-recaptcha.d.ts.map +1 -0
- package/dist/plugins/captcha/verify-handlers/index.d.ts +3 -0
- package/dist/plugins/captcha/verify-handlers/index.d.ts.map +1 -0
- package/dist/plugins/custom-session/client.d.ts +12 -0
- package/dist/plugins/custom-session/client.d.ts.map +1 -0
- package/dist/plugins/custom-session/index.cjs +76 -0
- package/dist/plugins/custom-session/index.d.ts +58 -0
- package/dist/plugins/custom-session/index.d.ts.map +1 -0
- package/dist/plugins/custom-session/index.mjs +74 -0
- package/dist/plugins/email-otp/client.d.ts +6 -0
- package/dist/plugins/email-otp/client.d.ts.map +1 -0
- package/dist/plugins/email-otp/index.cjs +707 -0
- package/dist/plugins/email-otp/index.d.ts +606 -0
- package/dist/plugins/email-otp/index.d.ts.map +1 -0
- package/dist/plugins/email-otp/index.mjs +705 -0
- package/dist/plugins/generic-oauth/client.d.ts +6 -0
- package/dist/plugins/generic-oauth/client.d.ts.map +1 -0
- package/dist/plugins/generic-oauth/index.cjs +542 -0
- package/dist/plugins/generic-oauth/index.d.ts +354 -0
- package/dist/plugins/generic-oauth/index.d.ts.map +1 -0
- package/dist/plugins/generic-oauth/index.mjs +540 -0
- package/dist/plugins/index.cjs +1396 -0
- package/dist/plugins/index.d.ts +23 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.mjs +1371 -0
- package/dist/plugins/jwt/adapter.d.ts +23 -0
- package/dist/plugins/jwt/adapter.d.ts.map +1 -0
- package/dist/plugins/jwt/client.d.ts +6 -0
- package/dist/plugins/jwt/client.d.ts.map +1 -0
- package/dist/plugins/jwt/index.cjs +282 -0
- package/dist/plugins/jwt/index.d.ts +277 -0
- package/dist/plugins/jwt/index.d.ts.map +1 -0
- package/dist/plugins/jwt/index.mjs +280 -0
- package/dist/plugins/jwt/schema.d.ts +37 -0
- package/dist/plugins/jwt/schema.d.ts.map +1 -0
- package/dist/plugins/jwt/utils.d.ts +11 -0
- package/dist/plugins/jwt/utils.d.ts.map +1 -0
- package/dist/plugins/magic-link/client.d.ts +6 -0
- package/dist/plugins/magic-link/client.d.ts.map +1 -0
- package/dist/plugins/magic-link/index.cjs +242 -0
- package/dist/plugins/magic-link/index.d.ts +218 -0
- package/dist/plugins/magic-link/index.d.ts.map +1 -0
- package/dist/plugins/magic-link/index.mjs +240 -0
- package/dist/plugins/multi-session/client.d.ts +10 -0
- package/dist/plugins/multi-session/client.d.ts.map +1 -0
- package/dist/plugins/multi-session/index.cjs +271 -0
- package/dist/plugins/multi-session/index.d.ts +257 -0
- package/dist/plugins/multi-session/index.d.ts.map +1 -0
- package/dist/plugins/multi-session/index.mjs +269 -0
- package/dist/plugins/oauth-proxy/index.cjs +174 -0
- package/dist/plugins/oauth-proxy/index.d.ts +134 -0
- package/dist/plugins/oauth-proxy/index.d.ts.map +1 -0
- package/dist/plugins/oauth-proxy/index.mjs +172 -0
- package/dist/plugins/oidc-provider/authorize.d.ts +4 -0
- package/dist/plugins/oidc-provider/authorize.d.ts.map +1 -0
- package/dist/plugins/oidc-provider/client.d.ts +6 -0
- package/dist/plugins/oidc-provider/client.d.ts.map +1 -0
- package/dist/plugins/oidc-provider/index.cjs +1039 -0
- package/dist/plugins/oidc-provider/index.d.ts +483 -0
- package/dist/plugins/oidc-provider/index.d.ts.map +1 -0
- package/dist/plugins/oidc-provider/index.mjs +1037 -0
- package/dist/plugins/oidc-provider/schema.d.ts +105 -0
- package/dist/plugins/oidc-provider/schema.d.ts.map +1 -0
- package/dist/plugins/oidc-provider/types.d.ts +496 -0
- package/dist/plugins/oidc-provider/types.d.ts.map +1 -0
- package/dist/plugins/oidc-provider/ui.d.ts +9 -0
- package/dist/plugins/oidc-provider/ui.d.ts.map +1 -0
- package/dist/plugins/one-tap/client.d.ts +82 -0
- package/dist/plugins/one-tap/client.d.ts.map +1 -0
- package/dist/plugins/one-tap/index.cjs +197 -0
- package/dist/plugins/one-tap/index.d.ts +114 -0
- package/dist/plugins/one-tap/index.d.ts.map +1 -0
- package/dist/plugins/one-tap/index.mjs +195 -0
- package/dist/plugins/open-api/generator.d.ts +101 -0
- package/dist/plugins/open-api/generator.d.ts.map +1 -0
- package/dist/plugins/open-api/index.cjs +480 -0
- package/dist/plugins/open-api/index.d.ts +152 -0
- package/dist/plugins/open-api/index.d.ts.map +1 -0
- package/dist/plugins/open-api/index.mjs +478 -0
- package/dist/plugins/open-api/logo.d.ts +2 -0
- package/dist/plugins/open-api/logo.d.ts.map +1 -0
- package/dist/plugins/organization/access/index.d.ts +2 -0
- package/dist/plugins/organization/access/index.d.ts.map +1 -0
- package/dist/plugins/organization/access/statement.d.ts +180 -0
- package/dist/plugins/organization/access/statement.d.ts.map +1 -0
- package/dist/plugins/organization/adapter.d.ts +291 -0
- package/dist/plugins/organization/adapter.d.ts.map +1 -0
- package/dist/plugins/organization/call.d.ts +41 -0
- package/dist/plugins/organization/call.d.ts.map +1 -0
- package/dist/plugins/organization/client.d.ts +334 -0
- package/dist/plugins/organization/client.d.ts.map +1 -0
- package/dist/plugins/organization/error-codes.d.ts +31 -0
- package/dist/plugins/organization/error-codes.d.ts.map +1 -0
- package/dist/plugins/organization/has-permission.d.ts +9 -0
- package/dist/plugins/organization/has-permission.d.ts.map +1 -0
- package/dist/plugins/organization/index.cjs +44 -0
- package/dist/plugins/organization/index.d.ts +2 -0
- package/dist/plugins/organization/index.d.ts.map +1 -0
- package/dist/plugins/organization/index.mjs +38 -0
- package/dist/plugins/organization/organization.d.ts +6764 -0
- package/dist/plugins/organization/organization.d.ts.map +1 -0
- package/dist/plugins/organization/routes/crud-invites.d.ts +2382 -0
- package/dist/plugins/organization/routes/crud-invites.d.ts.map +1 -0
- package/dist/plugins/organization/routes/crud-members.d.ts +578 -0
- package/dist/plugins/organization/routes/crud-members.d.ts.map +1 -0
- package/dist/plugins/organization/routes/crud-org.d.ts +789 -0
- package/dist/plugins/organization/routes/crud-org.d.ts.map +1 -0
- package/dist/plugins/organization/routes/crud-team.d.ts +348 -0
- package/dist/plugins/organization/routes/crud-team.d.ts.map +1 -0
- package/dist/plugins/organization/schema.d.ts +159 -0
- package/dist/plugins/organization/schema.d.ts.map +1 -0
- package/dist/plugins/passkey/client.d.ts +140 -0
- package/dist/plugins/passkey/client.d.ts.map +1 -0
- package/dist/plugins/passkey/index.cjs +831 -0
- package/dist/plugins/passkey/index.d.ts +847 -0
- package/dist/plugins/passkey/index.d.ts.map +1 -0
- package/dist/plugins/passkey/index.mjs +829 -0
- package/dist/plugins/phone-number/client.d.ts +10 -0
- package/dist/plugins/phone-number/client.d.ts.map +1 -0
- package/dist/plugins/phone-number/index.cjs +605 -0
- package/dist/plugins/phone-number/index.d.ts +477 -0
- package/dist/plugins/phone-number/index.d.ts.map +1 -0
- package/dist/plugins/phone-number/index.mjs +603 -0
- package/dist/plugins/sso/client.d.ts +6 -0
- package/dist/plugins/sso/client.d.ts.map +1 -0
- package/dist/plugins/sso/index.cjs +582 -0
- package/dist/plugins/sso/index.d.ts +490 -0
- package/dist/plugins/sso/index.d.ts.map +1 -0
- package/dist/plugins/sso/index.mjs +580 -0
- package/dist/plugins/two-factor/backup-codes/index.d.ts +348 -0
- package/dist/plugins/two-factor/backup-codes/index.d.ts.map +1 -0
- package/dist/plugins/two-factor/client.d.ts +29 -0
- package/dist/plugins/two-factor/client.d.ts.map +1 -0
- package/dist/plugins/two-factor/constant.d.ts +3 -0
- package/dist/plugins/two-factor/constant.d.ts.map +1 -0
- package/dist/plugins/two-factor/error-code.d.ts +9 -0
- package/dist/plugins/two-factor/error-code.d.ts.map +1 -0
- package/dist/plugins/two-factor/index.cjs +982 -0
- package/dist/plugins/two-factor/index.d.ts +1199 -0
- package/dist/plugins/two-factor/index.d.ts.map +1 -0
- package/dist/plugins/two-factor/index.mjs +979 -0
- package/dist/plugins/two-factor/otp/index.d.ts +352 -0
- package/dist/plugins/two-factor/otp/index.d.ts.map +1 -0
- package/dist/plugins/two-factor/schema.d.ts +36 -0
- package/dist/plugins/two-factor/schema.d.ts.map +1 -0
- package/dist/plugins/two-factor/totp/index.d.ts +367 -0
- package/dist/plugins/two-factor/totp/index.d.ts.map +1 -0
- package/dist/plugins/two-factor/types.d.ts +52 -0
- package/dist/plugins/two-factor/types.d.ts.map +1 -0
- package/dist/plugins/two-factor/verify-middleware.d.ts +76 -0
- package/dist/plugins/two-factor/verify-middleware.d.ts.map +1 -0
- package/dist/plugins/username/client.d.ts +6 -0
- package/dist/plugins/username/client.d.ts.map +1 -0
- package/dist/plugins/username/index.cjs +302 -0
- package/dist/plugins/username/index.d.ts +166 -0
- package/dist/plugins/username/index.d.ts.map +1 -0
- package/dist/plugins/username/index.mjs +300 -0
- package/dist/plugins/username/schema.d.ts +21 -0
- package/dist/plugins/username/schema.d.ts.map +1 -0
- package/dist/shared/better-auth.0TC26uRi.mjs +16 -0
- package/dist/shared/better-auth.0YzTc-oD.mjs +349 -0
- package/dist/shared/better-auth.8zoxzg-F.mjs +40 -0
- package/dist/shared/better-auth.ANpbi45u.cjs +22 -0
- package/dist/shared/better-auth.B4Qoxdgc.mjs +10 -0
- package/dist/shared/better-auth.B5NYxGA3.mjs +1126 -0
- package/dist/shared/better-auth.BBVHlTCJ.mjs +140 -0
- package/dist/shared/better-auth.BEphVDyL.cjs +251 -0
- package/dist/shared/better-auth.BG6vHVNT.cjs +30 -0
- package/dist/shared/better-auth.BIdFil5c.mjs +2966 -0
- package/dist/shared/better-auth.BLDOwz3i.cjs +7 -0
- package/dist/shared/better-auth.BMYo0QR-.cjs +10 -0
- package/dist/shared/better-auth.BUPPRXfK.mjs +7 -0
- package/dist/shared/better-auth.BXzrqpD0.mjs +89 -0
- package/dist/shared/better-auth.BcoSd9tC.mjs +10 -0
- package/dist/shared/better-auth.Bg6iw3ig.cjs +9 -0
- package/dist/shared/better-auth.BgkOX1Ei.cjs +36 -0
- package/dist/shared/better-auth.BopGaOCJ.mjs +1072 -0
- package/dist/shared/better-auth.BsGMIUYy.cjs +144 -0
- package/dist/shared/better-auth.BtJHz7JQ.mjs +21 -0
- package/dist/shared/better-auth.C1-vpKly.cjs +12 -0
- package/dist/shared/better-auth.C1hdVENX.cjs +7 -0
- package/dist/shared/better-auth.C24Bzw4w.mjs +174 -0
- package/dist/shared/better-auth.CDXNofOe.cjs +44 -0
- package/dist/shared/better-auth.CHh0hgk_.cjs +3007 -0
- package/dist/shared/better-auth.CHyZMcYK.cjs +190 -0
- package/dist/shared/better-auth.CKg1f8vU.cjs +1135 -0
- package/dist/shared/better-auth.CQvoVIBD.mjs +81 -0
- package/dist/shared/better-auth.CUdxApHl.cjs +18 -0
- package/dist/shared/better-auth.CW6D9eSx.mjs +5 -0
- package/dist/shared/better-auth.CYeOI8C-.cjs +12 -0
- package/dist/shared/better-auth.CZu6g_Il.cjs +92 -0
- package/dist/shared/better-auth.C_Zl7Etp.cjs +83 -0
- package/dist/shared/better-auth.CuZPmFi8.mjs +30 -0
- package/dist/shared/better-auth.Cytp8fGy.cjs +200 -0
- package/dist/shared/better-auth.D-2CmEwz.mjs +5 -0
- package/dist/shared/better-auth.D3mtHEZg.cjs +23 -0
- package/dist/shared/better-auth.D7syfoJW.mjs +133 -0
- package/dist/shared/better-auth.D8LeJoj0.mjs +173 -0
- package/dist/shared/better-auth.DDEbWX-S.mjs +8 -0
- package/dist/shared/better-auth.DH3YjMQH.mjs +55 -0
- package/dist/shared/better-auth.DMLPzZdQ.cjs +23 -0
- package/dist/shared/better-auth.DNqtHmvg.cjs +22 -0
- package/dist/shared/better-auth.DORkW_Ge.mjs +249 -0
- package/dist/shared/better-auth.DQI8AD7d.mjs +20 -0
- package/dist/shared/better-auth.DQRQ_nOW.cjs +1074 -0
- package/dist/shared/better-auth.DZnoWLte.cjs +175 -0
- package/dist/shared/better-auth.D_yrCdEQ.mjs +59 -0
- package/dist/shared/better-auth.DdjqxOIu.cjs +139 -0
- package/dist/shared/better-auth.Ddw8bVyV.mjs +35 -0
- package/dist/shared/better-auth.DdzSJf-n.mjs +19 -0
- package/dist/shared/better-auth.DhsGZ30Q.cjs +126 -0
- package/dist/shared/better-auth.DiSjtgs9.cjs +45 -0
- package/dist/shared/better-auth.DnER2-iT.cjs +37 -0
- package/dist/shared/better-auth.DssCybTk.cjs +64 -0
- package/dist/shared/better-auth.Duk7IG0N.mjs +34 -0
- package/dist/shared/better-auth.Ffl9CCnn.mjs +2293 -0
- package/dist/shared/better-auth.GpOOav9x.cjs +60 -0
- package/dist/shared/better-auth.HHZU10im.mjs +405 -0
- package/dist/shared/better-auth.OT3XFeFk.mjs +48 -0
- package/dist/shared/better-auth.YUF6P-PB.cjs +52 -0
- package/dist/shared/better-auth.YwDQhoPc.mjs +41 -0
- package/dist/shared/better-auth.am4QbDex.cjs +37 -0
- package/dist/shared/better-auth.cd8Jd_oV.mjs +197 -0
- package/dist/shared/better-auth.ffWeg50w.mjs +124 -0
- package/dist/shared/better-auth.fsvwNeUx.mjs +28 -0
- package/dist/shared/better-auth.lwzD09PV.cjs +408 -0
- package/dist/shared/better-auth.sN5DUs9C.cjs +351 -0
- package/dist/shared/better-auth.tB5eU6EY.mjs +21 -0
- package/dist/shared/better-auth.uUYJdWSr.cjs +2319 -0
- package/dist/social-providers/apple.d.ts +93 -0
- package/dist/social-providers/apple.d.ts.map +1 -0
- package/dist/social-providers/discord.d.ts +101 -0
- package/dist/social-providers/discord.d.ts.map +1 -0
- package/dist/social-providers/dropbox.d.ts +44 -0
- package/dist/social-providers/dropbox.d.ts.map +1 -0
- package/dist/social-providers/facebook.d.ts +52 -0
- package/dist/social-providers/facebook.d.ts.map +1 -0
- package/dist/social-providers/github.d.ts +77 -0
- package/dist/social-providers/github.d.ts.map +1 -0
- package/dist/social-providers/gitlab.d.ts +76 -0
- package/dist/social-providers/gitlab.d.ts.map +1 -0
- package/dist/social-providers/google.d.ts +62 -0
- package/dist/social-providers/google.d.ts.map +1 -0
- package/dist/social-providers/index.cjs +1217 -0
- package/dist/social-providers/index.d.ts +477 -0
- package/dist/social-providers/index.d.ts.map +1 -0
- package/dist/social-providers/index.mjs +1195 -0
- package/dist/social-providers/linkedin.d.ts +55 -0
- package/dist/social-providers/linkedin.d.ts.map +1 -0
- package/dist/social-providers/microsoft-entra-id.d.ts +56 -0
- package/dist/social-providers/microsoft-entra-id.d.ts.map +1 -0
- package/dist/social-providers/reddit.d.ts +40 -0
- package/dist/social-providers/reddit.d.ts.map +1 -0
- package/dist/social-providers/roblox.d.ts +48 -0
- package/dist/social-providers/roblox.d.ts.map +1 -0
- package/dist/social-providers/spotify.d.ts +39 -0
- package/dist/social-providers/spotify.d.ts.map +1 -0
- package/dist/social-providers/tiktok.d.ts +145 -0
- package/dist/social-providers/tiktok.d.ts.map +1 -0
- package/dist/social-providers/twitch.d.ts +50 -0
- package/dist/social-providers/twitch.d.ts.map +1 -0
- package/dist/social-providers/twitter.d.ts +119 -0
- package/dist/social-providers/twitter.d.ts.map +1 -0
- package/dist/social-providers/vk.d.ts +59 -0
- package/dist/social-providers/vk.d.ts.map +1 -0
- package/dist/tsconfig.declarations.tsbuildinfo +1 -0
- package/dist/types/adapter.d.ts +119 -0
- package/dist/types/adapter.d.ts.map +1 -0
- package/dist/types/api.d.ts +28 -0
- package/dist/types/api.d.ts.map +1 -0
- package/dist/types/context.d.ts +13 -0
- package/dist/types/context.d.ts.map +1 -0
- package/dist/types/helper.d.ts +32 -0
- package/dist/types/helper.d.ts.map +1 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/models.d.ts +35 -0
- package/dist/types/models.d.ts.map +1 -0
- package/dist/types/options.d.ts +794 -0
- package/dist/types/options.d.ts.map +1 -0
- package/dist/types/plugins.d.ts +120 -0
- package/dist/types/plugins.d.ts.map +1 -0
- package/dist/utils/boolean.d.ts +2 -0
- package/dist/utils/boolean.d.ts.map +1 -0
- package/dist/utils/callback-url.d.ts +7 -0
- package/dist/utils/callback-url.d.ts.map +1 -0
- package/dist/utils/clone.d.ts +2 -0
- package/dist/utils/clone.d.ts.map +1 -0
- package/dist/utils/constants.d.ts +2 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/date.d.ts +2 -0
- package/dist/utils/date.d.ts.map +1 -0
- package/dist/utils/env.d.ts +10 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/get-request-ip.d.ts +3 -0
- package/dist/utils/get-request-ip.d.ts.map +1 -0
- package/dist/utils/hide-metadata.d.ts +4 -0
- package/dist/utils/hide-metadata.d.ts.map +1 -0
- package/dist/utils/id.d.ts +2 -0
- package/dist/utils/id.d.ts.map +1 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/json.d.ts +2 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +15 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/merger.d.ts +2 -0
- package/dist/utils/merger.d.ts.map +1 -0
- package/dist/utils/middleware-response.d.ts +9 -0
- package/dist/utils/middleware-response.d.ts.map +1 -0
- package/dist/utils/misc.d.ts +2 -0
- package/dist/utils/misc.d.ts.map +1 -0
- package/dist/utils/password.d.ts +7 -0
- package/dist/utils/password.d.ts.map +1 -0
- package/dist/utils/plugin-helper.d.ts +6 -0
- package/dist/utils/plugin-helper.d.ts.map +1 -0
- package/dist/utils/shim.d.ts +4 -0
- package/dist/utils/shim.d.ts.map +1 -0
- package/dist/utils/time.d.ts +29 -0
- package/dist/utils/time.d.ts.map +1 -0
- package/dist/utils/url.d.ts +6 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/dist/utils/wildcard.d.ts +46 -0
- package/dist/utils/wildcard.d.ts.map +1 -0
- package/package.json +220 -218
- package/dist/adapters/drizzle.cjs +0 -274
- package/dist/adapters/drizzle.d.cts +0 -76
- package/dist/adapters/drizzle.d.ts +0 -76
- package/dist/adapters/drizzle.js +0 -272
- package/dist/adapters/kysely.cjs +0 -24
- package/dist/adapters/kysely.d.cts +0 -68
- package/dist/adapters/kysely.d.ts +0 -68
- package/dist/adapters/kysely.js +0 -11
- package/dist/adapters/memory.cjs +0 -20
- package/dist/adapters/memory.d.cts +0 -59
- package/dist/adapters/memory.d.ts +0 -59
- package/dist/adapters/memory.js +0 -11
- package/dist/adapters/mongodb.cjs +0 -273
- package/dist/adapters/mongodb.d.cts +0 -57
- package/dist/adapters/mongodb.d.ts +0 -57
- package/dist/adapters/mongodb.js +0 -271
- package/dist/adapters/prisma.cjs +0 -244
- package/dist/adapters/prisma.d.cts +0 -65
- package/dist/adapters/prisma.d.ts +0 -65
- package/dist/adapters/prisma.js +0 -242
- package/dist/adapters/test.d.cts +0 -16
- package/dist/adapters/test.js +0 -427
- package/dist/api.cjs +0 -179
- package/dist/api.d.cts +0 -8
- package/dist/api.d.ts +0 -8
- package/dist/api.js +0 -14
- package/dist/auth-B79moDlX.d.cts +0 -17513
- package/dist/auth-Kwau5-bb.d.ts +0 -17513
- package/dist/chunk-24JP47BJ.cjs +0 -514
- package/dist/chunk-2HPSCSV7.cjs +0 -8
- package/dist/chunk-2NRCW4MM.cjs +0 -276
- package/dist/chunk-36B4OZI7.cjs +0 -108
- package/dist/chunk-3XTQSPPA.js +0 -6
- package/dist/chunk-3YL6DMDX.cjs +0 -579
- package/dist/chunk-42QFDXM5.js +0 -168
- package/dist/chunk-4O3PNNJ5.js +0 -22
- package/dist/chunk-4YAPAKAB.cjs +0 -73
- package/dist/chunk-53IPO2PJ.js +0 -22
- package/dist/chunk-5ILVRGRP.cjs +0 -1066
- package/dist/chunk-6AFMN526.cjs +0 -45
- package/dist/chunk-6YBMZW4E.js +0 -274
- package/dist/chunk-74IS7WMH.js +0 -89
- package/dist/chunk-7KKMYVNZ.js +0 -42
- package/dist/chunk-7T4E7I7S.cjs +0 -1084
- package/dist/chunk-BAFWUSRZ.cjs +0 -277
- package/dist/chunk-BVPUB4ND.cjs +0 -2225
- package/dist/chunk-CAT6XI46.js +0 -275
- package/dist/chunk-CCKQSGIR.cjs +0 -8
- package/dist/chunk-CDEGAT2X.cjs +0 -38
- package/dist/chunk-CF7NIEGH.cjs +0 -38
- package/dist/chunk-COHCMRZR.cjs +0 -448
- package/dist/chunk-CWVCOYJV.cjs +0 -28
- package/dist/chunk-DINP2XPU.js +0 -677
- package/dist/chunk-DMXPQ4IV.js +0 -98
- package/dist/chunk-EHFDU6IF.cjs +0 -45
- package/dist/chunk-ENJOFIER.js +0 -212
- package/dist/chunk-EORFSCDW.cjs +0 -91
- package/dist/chunk-FDBO3FVG.cjs +0 -1135
- package/dist/chunk-FURNA6HY.js +0 -6
- package/dist/chunk-GBOJH32L.cjs +0 -82
- package/dist/chunk-GEW4G4Y7.cjs +0 -1007
- package/dist/chunk-GYDUPG7X.js +0 -36
- package/dist/chunk-H74YRRNV.cjs +0 -92
- package/dist/chunk-HC2USFT2.cjs +0 -214
- package/dist/chunk-HVHN3Y2L.js +0 -126
- package/dist/chunk-IGDRZOHV.js +0 -134
- package/dist/chunk-IX6WCVID.cjs +0 -1971
- package/dist/chunk-J6F3TU5V.js +0 -1082
- package/dist/chunk-JEYF2ARX.js +0 -21
- package/dist/chunk-JOH6QBAP.cjs +0 -362
- package/dist/chunk-JUPDDQC4.cjs +0 -23
- package/dist/chunk-KEQSKZI2.js +0 -239
- package/dist/chunk-KIQWU6Z4.cjs +0 -278
- package/dist/chunk-KLDFBLYL.js +0 -85
- package/dist/chunk-LJJIONSX.cjs +0 -45
- package/dist/chunk-LKPN4Y5Z.js +0 -31
- package/dist/chunk-M5XMVH2M.js +0 -1114
- package/dist/chunk-NC57F4RJ.cjs +0 -3703
- package/dist/chunk-NSBXOWUM.js +0 -1064
- package/dist/chunk-NTBGYF7H.cjs +0 -241
- package/dist/chunk-OA7Z7IZT.cjs +0 -24
- package/dist/chunk-PEZRSDZS.cjs +0 -23
- package/dist/chunk-Q4E77C7B.js +0 -1005
- package/dist/chunk-Q4XYQ7DC.js +0 -156
- package/dist/chunk-QUVBQTGS.js +0 -274
- package/dist/chunk-R42K7GPF.js +0 -132
- package/dist/chunk-REY76NPL.cjs +0 -136
- package/dist/chunk-RJUH2LYP.js +0 -577
- package/dist/chunk-RXJOBUFI.js +0 -43
- package/dist/chunk-S5UORXJH.cjs +0 -65
- package/dist/chunk-SENLFMI2.js +0 -142
- package/dist/chunk-SVC7H7K4.cjs +0 -138
- package/dist/chunk-TBGNSOTL.js +0 -1955
- package/dist/chunk-THOAPE5K.js +0 -70
- package/dist/chunk-TJWK22XS.js +0 -446
- package/dist/chunk-TOKZL3ZI.js +0 -42
- package/dist/chunk-TOSIKQ2I.cjs +0 -144
- package/dist/chunk-TQQSPPNA.js +0 -41
- package/dist/chunk-U4I57HJ4.cjs +0 -129
- package/dist/chunk-UNWCXKMP.js +0 -20
- package/dist/chunk-UQC2FUXC.cjs +0 -224
- package/dist/chunk-VOUL66AG.js +0 -512
- package/dist/chunk-VXYIYABQ.cjs +0 -46
- package/dist/chunk-WBFH3ZYN.js +0 -352
- package/dist/chunk-WMXBA6LX.js +0 -11
- package/dist/chunk-WVVF7K6P.js +0 -79
- package/dist/chunk-WZ6OIVJK.js +0 -207
- package/dist/chunk-X3J3BWQR.js +0 -2223
- package/dist/chunk-XDMVO6BH.cjs +0 -170
- package/dist/chunk-XFCIANZX.js +0 -60
- package/dist/chunk-XRF73UDB.js +0 -3654
- package/dist/chunk-Y64QYLA4.cjs +0 -158
- package/dist/chunk-Y6QT4U6Z.cjs +0 -679
- package/dist/chunk-ZBKCS3KP.cjs +0 -13
- package/dist/client/plugins.cjs +0 -572
- package/dist/client/plugins.d.cts +0 -758
- package/dist/client/plugins.d.ts +0 -758
- package/dist/client/plugins.js +0 -549
- package/dist/client.cjs +0 -24
- package/dist/client.d.cts +0 -138
- package/dist/client.d.ts +0 -138
- package/dist/client.js +0 -7
- package/dist/cookies.cjs +0 -46
- package/dist/cookies.d.cts +0 -8
- package/dist/cookies.d.ts +0 -8
- package/dist/cookies.js +0 -5
- package/dist/crypto.cjs +0 -42
- package/dist/crypto.d.cts +0 -30
- package/dist/crypto.d.ts +0 -30
- package/dist/crypto.js +0 -1
- package/dist/db.cjs +0 -120
- package/dist/db.d.cts +0 -56
- package/dist/db.d.ts +0 -56
- package/dist/db.js +0 -11
- package/dist/helper-DFk-nDjL.d.cts +0 -29
- package/dist/helper-DFk-nDjL.d.ts +0 -29
- package/dist/hide-metadata-DEHJp1rk.d.cts +0 -5
- package/dist/hide-metadata-DEHJp1rk.d.ts +0 -5
- package/dist/index-BKfxieJM.d.ts +0 -1500
- package/dist/index-Bo3yOPaO.d.cts +0 -1500
- package/dist/index-CpB6VxxI.d.ts +0 -5116
- package/dist/index-UqpJkXzo.d.cts +0 -5116
- package/dist/index.d.cts +0 -26
- package/dist/index.js +0 -217
- package/dist/next-js.cjs +0 -100
- package/dist/next-js.d.cts +0 -34
- package/dist/next-js.d.ts +0 -34
- package/dist/next-js.js +0 -97
- package/dist/node.cjs +0 -24
- package/dist/node.d.cts +0 -17
- package/dist/node.d.ts +0 -17
- package/dist/node.js +0 -21
- package/dist/oauth2.cjs +0 -37
- package/dist/oauth2.d.cts +0 -39
- package/dist/oauth2.d.ts +0 -39
- package/dist/oauth2.js +0 -4
- package/dist/plugins/access.cjs +0 -15
- package/dist/plugins/access.d.cts +0 -42
- package/dist/plugins/access.d.ts +0 -42
- package/dist/plugins/access.js +0 -2
- package/dist/plugins/admin/access.cjs +0 -28
- package/dist/plugins/admin/access.d.cts +0 -116
- package/dist/plugins/admin/access.d.ts +0 -116
- package/dist/plugins/admin/access.js +0 -3
- package/dist/plugins/admin.cjs +0 -28
- package/dist/plugins/admin.d.cts +0 -1398
- package/dist/plugins/admin.d.ts +0 -1398
- package/dist/plugins/admin.js +0 -19
- package/dist/plugins/anonymous.cjs +0 -24
- package/dist/plugins/anonymous.d.cts +0 -160
- package/dist/plugins/anonymous.d.ts +0 -160
- package/dist/plugins/anonymous.js +0 -15
- package/dist/plugins/bearer.cjs +0 -24
- package/dist/plugins/bearer.d.cts +0 -57
- package/dist/plugins/bearer.d.ts +0 -57
- package/dist/plugins/bearer.js +0 -15
- package/dist/plugins/captcha.cjs +0 -10
- package/dist/plugins/captcha.d.cts +0 -21
- package/dist/plugins/captcha.d.ts +0 -21
- package/dist/plugins/captcha.js +0 -1
- package/dist/plugins/custom-session.cjs +0 -24
- package/dist/plugins/custom-session.d.cts +0 -66
- package/dist/plugins/custom-session.d.ts +0 -66
- package/dist/plugins/custom-session.js +0 -15
- package/dist/plugins/email-otp.cjs +0 -25
- package/dist/plugins/email-otp.d.cts +0 -615
- package/dist/plugins/email-otp.d.ts +0 -615
- package/dist/plugins/email-otp.js +0 -16
- package/dist/plugins/generic-oauth.cjs +0 -24
- package/dist/plugins/generic-oauth.d.cts +0 -356
- package/dist/plugins/generic-oauth.d.ts +0 -356
- package/dist/plugins/generic-oauth.js +0 -15
- package/dist/plugins/jwt.cjs +0 -24
- package/dist/plugins/jwt.d.cts +0 -303
- package/dist/plugins/jwt.d.ts +0 -303
- package/dist/plugins/jwt.js +0 -15
- package/dist/plugins/magic-link.cjs +0 -24
- package/dist/plugins/magic-link.d.cts +0 -220
- package/dist/plugins/magic-link.d.ts +0 -220
- package/dist/plugins/magic-link.js +0 -15
- package/dist/plugins/multi-session.cjs +0 -24
- package/dist/plugins/multi-session.d.cts +0 -265
- package/dist/plugins/multi-session.d.ts +0 -265
- package/dist/plugins/multi-session.js +0 -15
- package/dist/plugins/oidc-provider.cjs +0 -24
- package/dist/plugins/oidc-provider.d.cts +0 -977
- package/dist/plugins/oidc-provider.d.ts +0 -977
- package/dist/plugins/oidc-provider.js +0 -15
- package/dist/plugins/one-tap.cjs +0 -24
- package/dist/plugins/one-tap.d.cts +0 -116
- package/dist/plugins/one-tap.d.ts +0 -116
- package/dist/plugins/one-tap.js +0 -15
- package/dist/plugins/open-api.cjs +0 -26
- package/dist/plugins/open-api.d.cts +0 -260
- package/dist/plugins/open-api.d.ts +0 -260
- package/dist/plugins/open-api.js +0 -17
- package/dist/plugins/organization.cjs +0 -27
- package/dist/plugins/organization.d.cts +0 -10
- package/dist/plugins/organization.d.ts +0 -10
- package/dist/plugins/organization.js +0 -18
- package/dist/plugins/passkey.cjs +0 -799
- package/dist/plugins/passkey.d.cts +0 -833
- package/dist/plugins/passkey.d.ts +0 -833
- package/dist/plugins/passkey.js +0 -797
- package/dist/plugins/phone-number.cjs +0 -24
- package/dist/plugins/phone-number.d.cts +0 -483
- package/dist/plugins/phone-number.d.ts +0 -483
- package/dist/plugins/phone-number.js +0 -15
- package/dist/plugins/sso.cjs +0 -566
- package/dist/plugins/sso.d.cts +0 -496
- package/dist/plugins/sso.d.ts +0 -496
- package/dist/plugins/sso.js +0 -564
- package/dist/plugins/two-factor.cjs +0 -31
- package/dist/plugins/two-factor.d.cts +0 -1394
- package/dist/plugins/two-factor.d.ts +0 -1394
- package/dist/plugins/two-factor.js +0 -18
- package/dist/plugins/username.cjs +0 -25
- package/dist/plugins/username.d.cts +0 -194
- package/dist/plugins/username.d.ts +0 -194
- package/dist/plugins/username.js +0 -16
- package/dist/plugins.cjs +0 -139
- package/dist/plugins.d.cts +0 -164
- package/dist/plugins.d.ts +0 -164
- package/dist/plugins.js +0 -42
- package/dist/react.cjs +0 -64
- package/dist/react.d.cts +0 -140
- package/dist/react.d.ts +0 -140
- package/dist/react.js +0 -60
- package/dist/social.cjs +0 -93
- package/dist/social.d.cts +0 -4
- package/dist/social.d.ts +0 -4
- package/dist/social.js +0 -8
- package/dist/solid-start.cjs +0 -14
- package/dist/solid-start.d.cts +0 -12
- package/dist/solid-start.d.ts +0 -12
- package/dist/solid-start.js +0 -12
- package/dist/solid.cjs +0 -56
- package/dist/solid.d.cts +0 -115
- package/dist/solid.d.ts +0 -115
- package/dist/solid.js +0 -54
- package/dist/state-C7IUhB_Z.d.cts +0 -22
- package/dist/state-D32_8TuF.d.ts +0 -22
- package/dist/svelte-kit.cjs +0 -38
- package/dist/svelte-kit.d.cts +0 -29
- package/dist/svelte-kit.d.ts +0 -29
- package/dist/svelte-kit.js +0 -34
- package/dist/svelte.cjs +0 -40
- package/dist/svelte.d.cts +0 -120
- package/dist/svelte.d.ts +0 -120
- package/dist/svelte.js +0 -38
- package/dist/types.cjs +0 -4
- package/dist/types.d.cts +0 -137
- package/dist/types.d.ts +0 -137
- package/dist/types.js +0 -1
- package/dist/vue.cjs +0 -85
- package/dist/vue.d.cts +0 -143
- package/dist/vue.d.ts +0 -143
- package/dist/vue.js +0 -83
- /package/dist/{chunk-NIMYOIVU.cjs → types/index.cjs} +0 -0
- /package/dist/{chunk-SK6Y2YH6.js → types/index.mjs} +0 -0
package/dist/chunk-XRF73UDB.js
DELETED
|
@@ -1,3654 +0,0 @@
|
|
|
1
|
-
import { SocialProviderListEnum, socialProviderList } from './chunk-M5XMVH2M.js';
|
|
2
|
-
import { getHost, getProtocol, getOrigin } from './chunk-XFCIANZX.js';
|
|
3
|
-
import { setSessionCookie, deleteSessionCookie, setCookieCache } from './chunk-WBFH3ZYN.js';
|
|
4
|
-
import { parseUserInput, getIp } from './chunk-WZ6OIVJK.js';
|
|
5
|
-
import { HIDE_METADATA, generateId, logger } from './chunk-KLDFBLYL.js';
|
|
6
|
-
import { generateState, parseState } from './chunk-WVVF7K6P.js';
|
|
7
|
-
import { generateRandomString, signJWT } from './chunk-DMXPQ4IV.js';
|
|
8
|
-
import { safeJSONParse } from './chunk-53IPO2PJ.js';
|
|
9
|
-
import { getDate } from './chunk-FURNA6HY.js';
|
|
10
|
-
import { isDevelopment } from './chunk-TQQSPPNA.js';
|
|
11
|
-
import { createMiddleware, createEndpoint, APIError, createRouter, toResponse } from 'better-call';
|
|
12
|
-
export { APIError } from 'better-call';
|
|
13
|
-
import { z } from 'zod';
|
|
14
|
-
import { createHMAC } from '@better-auth/utils/hmac';
|
|
15
|
-
import { base64 } from '@better-auth/utils/base64';
|
|
16
|
-
import { binary } from '@better-auth/utils/binary';
|
|
17
|
-
import { jwtVerify } from 'jose';
|
|
18
|
-
import { JWTExpired } from 'jose/errors';
|
|
19
|
-
import defu from 'defu';
|
|
20
|
-
|
|
21
|
-
var optionsMiddleware = createMiddleware(async () => {
|
|
22
|
-
return {};
|
|
23
|
-
});
|
|
24
|
-
var createAuthMiddleware = createMiddleware.create({
|
|
25
|
-
use: [
|
|
26
|
-
optionsMiddleware,
|
|
27
|
-
/**
|
|
28
|
-
* Only use for post hooks
|
|
29
|
-
*/
|
|
30
|
-
createMiddleware(async () => {
|
|
31
|
-
return {};
|
|
32
|
-
})
|
|
33
|
-
]
|
|
34
|
-
});
|
|
35
|
-
var createAuthEndpoint = createEndpoint.create({
|
|
36
|
-
use: [optionsMiddleware]
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
// src/utils/wildcard.ts
|
|
40
|
-
function escapeRegExpChar(char) {
|
|
41
|
-
if (char === "-" || char === "^" || char === "$" || char === "+" || char === "." || char === "(" || char === ")" || char === "|" || char === "[" || char === "]" || char === "{" || char === "}" || char === "*" || char === "?" || char === "\\") {
|
|
42
|
-
return `\\${char}`;
|
|
43
|
-
} else {
|
|
44
|
-
return char;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
function escapeRegExpString(str) {
|
|
48
|
-
let result = "";
|
|
49
|
-
for (let i = 0; i < str.length; i++) {
|
|
50
|
-
result += escapeRegExpChar(str[i]);
|
|
51
|
-
}
|
|
52
|
-
return result;
|
|
53
|
-
}
|
|
54
|
-
function transform(pattern, separator = true) {
|
|
55
|
-
if (Array.isArray(pattern)) {
|
|
56
|
-
let regExpPatterns = pattern.map((p) => `^${transform(p, separator)}$`);
|
|
57
|
-
return `(?:${regExpPatterns.join("|")})`;
|
|
58
|
-
}
|
|
59
|
-
let separatorSplitter = "";
|
|
60
|
-
let separatorMatcher = "";
|
|
61
|
-
let wildcard = ".";
|
|
62
|
-
if (separator === true) {
|
|
63
|
-
separatorSplitter = "/";
|
|
64
|
-
separatorMatcher = "[/\\\\]";
|
|
65
|
-
wildcard = "[^/\\\\]";
|
|
66
|
-
} else if (separator) {
|
|
67
|
-
separatorSplitter = separator;
|
|
68
|
-
separatorMatcher = escapeRegExpString(separatorSplitter);
|
|
69
|
-
if (separatorMatcher.length > 1) {
|
|
70
|
-
separatorMatcher = `(?:${separatorMatcher})`;
|
|
71
|
-
wildcard = `((?!${separatorMatcher}).)`;
|
|
72
|
-
} else {
|
|
73
|
-
wildcard = `[^${separatorMatcher}]`;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
let requiredSeparator = separator ? `${separatorMatcher}+?` : "";
|
|
77
|
-
let optionalSeparator = separator ? `${separatorMatcher}*?` : "";
|
|
78
|
-
let segments = separator ? pattern.split(separatorSplitter) : [pattern];
|
|
79
|
-
let result = "";
|
|
80
|
-
for (let s = 0; s < segments.length; s++) {
|
|
81
|
-
let segment = segments[s];
|
|
82
|
-
let nextSegment = segments[s + 1];
|
|
83
|
-
let currentSeparator = "";
|
|
84
|
-
if (!segment && s > 0) {
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
if (separator) {
|
|
88
|
-
if (s === segments.length - 1) {
|
|
89
|
-
currentSeparator = optionalSeparator;
|
|
90
|
-
} else if (nextSegment !== "**") {
|
|
91
|
-
currentSeparator = requiredSeparator;
|
|
92
|
-
} else {
|
|
93
|
-
currentSeparator = "";
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (separator && segment === "**") {
|
|
97
|
-
if (currentSeparator) {
|
|
98
|
-
result += s === 0 ? "" : currentSeparator;
|
|
99
|
-
result += `(?:${wildcard}*?${currentSeparator})*?`;
|
|
100
|
-
}
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
for (let c = 0; c < segment.length; c++) {
|
|
104
|
-
let char = segment[c];
|
|
105
|
-
if (char === "\\") {
|
|
106
|
-
if (c < segment.length - 1) {
|
|
107
|
-
result += escapeRegExpChar(segment[c + 1]);
|
|
108
|
-
c++;
|
|
109
|
-
}
|
|
110
|
-
} else if (char === "?") {
|
|
111
|
-
result += wildcard;
|
|
112
|
-
} else if (char === "*") {
|
|
113
|
-
result += `${wildcard}*?`;
|
|
114
|
-
} else {
|
|
115
|
-
result += escapeRegExpChar(char);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
result += currentSeparator;
|
|
119
|
-
}
|
|
120
|
-
return result;
|
|
121
|
-
}
|
|
122
|
-
function isMatch(regexp, sample) {
|
|
123
|
-
if (typeof sample !== "string") {
|
|
124
|
-
throw new TypeError(`Sample must be a string, but ${typeof sample} given`);
|
|
125
|
-
}
|
|
126
|
-
return regexp.test(sample);
|
|
127
|
-
}
|
|
128
|
-
function wildcardMatch(pattern, options) {
|
|
129
|
-
if (typeof pattern !== "string" && !Array.isArray(pattern)) {
|
|
130
|
-
throw new TypeError(
|
|
131
|
-
`The first argument must be a single pattern string or an array of patterns, but ${typeof pattern} given`
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
if (typeof options === "string" || typeof options === "boolean") {
|
|
135
|
-
options = { separator: options };
|
|
136
|
-
}
|
|
137
|
-
if (arguments.length === 2 && !(typeof options === "undefined" || typeof options === "object" && options !== null && !Array.isArray(options))) {
|
|
138
|
-
throw new TypeError(
|
|
139
|
-
`The second argument must be an options object or a string/boolean separator, but ${typeof options} given`
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
options = options || {};
|
|
143
|
-
if (options.separator === "\\") {
|
|
144
|
-
throw new Error(
|
|
145
|
-
"\\ is not a valid separator because it is used for escaping. Try setting the separator to `true` instead"
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
let regexpPattern = transform(pattern, options.separator);
|
|
149
|
-
let regexp = new RegExp(`^${regexpPattern}$`, options.flags);
|
|
150
|
-
let fn = isMatch.bind(null, regexp);
|
|
151
|
-
fn.options = options;
|
|
152
|
-
fn.pattern = pattern;
|
|
153
|
-
fn.regexp = regexp;
|
|
154
|
-
return fn;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// src/api/middlewares/origin-check.ts
|
|
158
|
-
var originCheckMiddleware = createAuthMiddleware(async (ctx) => {
|
|
159
|
-
if (ctx.request?.method !== "POST" || !ctx.request) {
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
const { body, query, context } = ctx;
|
|
163
|
-
const originHeader = ctx.headers?.get("origin") || ctx.headers?.get("referer") || "";
|
|
164
|
-
const callbackURL = body?.callbackURL || query?.callbackURL;
|
|
165
|
-
const redirectURL = body?.redirectTo;
|
|
166
|
-
const errorCallbackURL = body?.errorCallbackURL;
|
|
167
|
-
const newUserCallbackURL = body?.newUserCallbackURL;
|
|
168
|
-
const trustedOrigins = Array.isArray(context.options.trustedOrigins) ? context.trustedOrigins : [
|
|
169
|
-
...context.trustedOrigins,
|
|
170
|
-
...context.options.trustedOrigins?.(ctx.request) || []
|
|
171
|
-
];
|
|
172
|
-
const usesCookies = ctx.headers?.has("cookie");
|
|
173
|
-
const matchesPattern = (url, pattern) => {
|
|
174
|
-
if (url.startsWith("/")) {
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
if (pattern.includes("*")) {
|
|
178
|
-
return wildcardMatch(pattern)(getHost(url));
|
|
179
|
-
}
|
|
180
|
-
const protocol = getProtocol(url);
|
|
181
|
-
return protocol === "http:" || protocol === "https:" || !protocol ? pattern === getOrigin(url) : url.startsWith(pattern);
|
|
182
|
-
};
|
|
183
|
-
const validateURL = (url, label) => {
|
|
184
|
-
if (!url) {
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
const isTrustedOrigin = trustedOrigins.some(
|
|
188
|
-
(origin) => matchesPattern(url, origin) || url?.startsWith("/") && label !== "origin" && /^\/(?![\\/%])[\w\-./]*$/.test(url)
|
|
189
|
-
);
|
|
190
|
-
if (!isTrustedOrigin) {
|
|
191
|
-
ctx.context.logger.error(`Invalid ${label}: ${url}`);
|
|
192
|
-
ctx.context.logger.info(
|
|
193
|
-
`If it's a valid URL, please add ${url} to trustedOrigins in your auth config
|
|
194
|
-
`,
|
|
195
|
-
`Current list of trustedOrigins: ${trustedOrigins}`
|
|
196
|
-
);
|
|
197
|
-
throw new APIError("FORBIDDEN", { message: `Invalid ${label}` });
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
if (usesCookies && !ctx.context.options.advanced?.disableCSRFCheck) {
|
|
201
|
-
validateURL(originHeader, "origin");
|
|
202
|
-
}
|
|
203
|
-
callbackURL && validateURL(callbackURL, "callbackURL");
|
|
204
|
-
redirectURL && validateURL(redirectURL, "redirectURL");
|
|
205
|
-
errorCallbackURL && validateURL(errorCallbackURL, "errorCallbackURL");
|
|
206
|
-
newUserCallbackURL && validateURL(newUserCallbackURL, "newUserCallbackURL");
|
|
207
|
-
});
|
|
208
|
-
var originCheck = (getValue) => createAuthMiddleware(async (ctx) => {
|
|
209
|
-
if (!ctx.request) {
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
const { context } = ctx;
|
|
213
|
-
const callbackURL = getValue(ctx);
|
|
214
|
-
const trustedOrigins = Array.isArray(
|
|
215
|
-
context.options.trustedOrigins
|
|
216
|
-
) ? context.trustedOrigins : [
|
|
217
|
-
...context.trustedOrigins,
|
|
218
|
-
...context.options.trustedOrigins?.(ctx.request) || []
|
|
219
|
-
];
|
|
220
|
-
const matchesPattern = (url, pattern) => {
|
|
221
|
-
if (url.startsWith("/")) {
|
|
222
|
-
return false;
|
|
223
|
-
}
|
|
224
|
-
if (pattern.includes("*")) {
|
|
225
|
-
return wildcardMatch(pattern)(getHost(url));
|
|
226
|
-
}
|
|
227
|
-
return url.startsWith(pattern);
|
|
228
|
-
};
|
|
229
|
-
const validateURL = (url, label) => {
|
|
230
|
-
if (!url) {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
const isTrustedOrigin = trustedOrigins.some(
|
|
234
|
-
(origin) => matchesPattern(url, origin) || url?.startsWith("/") && label !== "origin" && /^\/(?![\\/%])[\w\-./]*$/.test(url)
|
|
235
|
-
);
|
|
236
|
-
if (!isTrustedOrigin) {
|
|
237
|
-
ctx.context.logger.error(`Invalid ${label}: ${url}`);
|
|
238
|
-
ctx.context.logger.info(
|
|
239
|
-
`If it's a valid URL, please add ${url} to trustedOrigins in your auth config
|
|
240
|
-
`,
|
|
241
|
-
`Current list of trustedOrigins: ${trustedOrigins}`
|
|
242
|
-
);
|
|
243
|
-
throw new APIError("FORBIDDEN", { message: `Invalid ${label}` });
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
callbackURL && validateURL(callbackURL, "callbackURL");
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
// src/error/codes.ts
|
|
250
|
-
var BASE_ERROR_CODES = {
|
|
251
|
-
USER_NOT_FOUND: "User not found",
|
|
252
|
-
FAILED_TO_CREATE_USER: "Failed to create user",
|
|
253
|
-
FAILED_TO_CREATE_SESSION: "Failed to create session",
|
|
254
|
-
FAILED_TO_UPDATE_USER: "Failed to update user",
|
|
255
|
-
FAILED_TO_GET_SESSION: "Failed to get session",
|
|
256
|
-
INVALID_PASSWORD: "Invalid password",
|
|
257
|
-
INVALID_EMAIL: "Invalid email",
|
|
258
|
-
INVALID_EMAIL_OR_PASSWORD: "Invalid email or password",
|
|
259
|
-
SOCIAL_ACCOUNT_ALREADY_LINKED: "Social account already linked",
|
|
260
|
-
PROVIDER_NOT_FOUND: "Provider not found",
|
|
261
|
-
INVALID_TOKEN: "invalid token",
|
|
262
|
-
ID_TOKEN_NOT_SUPPORTED: "id_token not supported",
|
|
263
|
-
FAILED_TO_GET_USER_INFO: "Failed to get user info",
|
|
264
|
-
USER_EMAIL_NOT_FOUND: "User email not found",
|
|
265
|
-
EMAIL_NOT_VERIFIED: "Email not verified",
|
|
266
|
-
PASSWORD_TOO_SHORT: "Password too short",
|
|
267
|
-
PASSWORD_TOO_LONG: "Password too long",
|
|
268
|
-
USER_ALREADY_EXISTS: "User already exists",
|
|
269
|
-
EMAIL_CAN_NOT_BE_UPDATED: "Email can not be updated",
|
|
270
|
-
CREDENTIAL_ACCOUNT_NOT_FOUND: "Credential account not found",
|
|
271
|
-
SESSION_EXPIRED: "Session expired. Re-authenticate to perform this action.",
|
|
272
|
-
FAILED_TO_UNLINK_LAST_ACCOUNT: "You can't unlink your last account",
|
|
273
|
-
ACCOUNT_NOT_FOUND: "Account not found"
|
|
274
|
-
};
|
|
275
|
-
var getSession = () => createAuthEndpoint(
|
|
276
|
-
"/get-session",
|
|
277
|
-
{
|
|
278
|
-
method: "GET",
|
|
279
|
-
query: z.optional(
|
|
280
|
-
z.object({
|
|
281
|
-
/**
|
|
282
|
-
* If cookie cache is enabled, it will disable the cache
|
|
283
|
-
* and fetch the session from the database
|
|
284
|
-
*/
|
|
285
|
-
disableCookieCache: z.optional(
|
|
286
|
-
z.boolean({
|
|
287
|
-
description: "Disable cookie cache and fetch session from database"
|
|
288
|
-
}).or(z.string().transform((v) => v === "true"))
|
|
289
|
-
).optional(),
|
|
290
|
-
disableRefresh: z.boolean({
|
|
291
|
-
description: "Disable session refresh. Useful for checking session status, without updating the session"
|
|
292
|
-
}).or(z.string().transform((v) => v === "true")).optional()
|
|
293
|
-
})
|
|
294
|
-
),
|
|
295
|
-
requireHeaders: true,
|
|
296
|
-
metadata: {
|
|
297
|
-
openapi: {
|
|
298
|
-
description: "Get the current session",
|
|
299
|
-
responses: {
|
|
300
|
-
"200": {
|
|
301
|
-
description: "Success",
|
|
302
|
-
content: {
|
|
303
|
-
"application/json": {
|
|
304
|
-
schema: {
|
|
305
|
-
type: "object",
|
|
306
|
-
properties: {
|
|
307
|
-
session: {
|
|
308
|
-
type: "object",
|
|
309
|
-
properties: {
|
|
310
|
-
token: {
|
|
311
|
-
type: "string"
|
|
312
|
-
},
|
|
313
|
-
userId: {
|
|
314
|
-
type: "string"
|
|
315
|
-
},
|
|
316
|
-
expiresAt: {
|
|
317
|
-
type: "string"
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
},
|
|
321
|
-
user: {
|
|
322
|
-
type: "object",
|
|
323
|
-
$ref: "#/components/schemas/User"
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
},
|
|
334
|
-
async (ctx) => {
|
|
335
|
-
try {
|
|
336
|
-
const sessionCookieToken = await ctx.getSignedCookie(
|
|
337
|
-
ctx.context.authCookies.sessionToken.name,
|
|
338
|
-
ctx.context.secret
|
|
339
|
-
);
|
|
340
|
-
if (!sessionCookieToken) {
|
|
341
|
-
return null;
|
|
342
|
-
}
|
|
343
|
-
const sessionDataCookie = ctx.getCookie(
|
|
344
|
-
ctx.context.authCookies.sessionData.name
|
|
345
|
-
);
|
|
346
|
-
const sessionDataPayload = sessionDataCookie ? safeJSONParse(binary.decode(base64.decode(sessionDataCookie))) : null;
|
|
347
|
-
if (sessionDataPayload) {
|
|
348
|
-
const isValid = await createHMAC("SHA-256", "base64urlnopad").verify(
|
|
349
|
-
ctx.context.secret,
|
|
350
|
-
JSON.stringify({
|
|
351
|
-
...sessionDataPayload.session,
|
|
352
|
-
expiresAt: sessionDataPayload.expiresAt
|
|
353
|
-
}),
|
|
354
|
-
sessionDataPayload.signature
|
|
355
|
-
);
|
|
356
|
-
if (!isValid) {
|
|
357
|
-
deleteSessionCookie(ctx);
|
|
358
|
-
return ctx.json(null);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
const dontRememberMe = await ctx.getSignedCookie(
|
|
362
|
-
ctx.context.authCookies.dontRememberToken.name,
|
|
363
|
-
ctx.context.secret
|
|
364
|
-
);
|
|
365
|
-
if (sessionDataPayload?.session && ctx.context.options.session?.cookieCache?.enabled && !ctx.query?.disableCookieCache) {
|
|
366
|
-
const session2 = sessionDataPayload.session;
|
|
367
|
-
const hasExpired = sessionDataPayload.expiresAt < Date.now() || session2.session.expiresAt < /* @__PURE__ */ new Date();
|
|
368
|
-
if (!hasExpired) {
|
|
369
|
-
return ctx.json(
|
|
370
|
-
session2
|
|
371
|
-
);
|
|
372
|
-
} else {
|
|
373
|
-
const dataCookie = ctx.context.authCookies.sessionData.name;
|
|
374
|
-
ctx.setCookie(dataCookie, "", {
|
|
375
|
-
maxAge: 0
|
|
376
|
-
});
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
const session = await ctx.context.internalAdapter.findSession(sessionCookieToken);
|
|
380
|
-
ctx.context.session = session;
|
|
381
|
-
if (!session || session.session.expiresAt < /* @__PURE__ */ new Date()) {
|
|
382
|
-
deleteSessionCookie(ctx);
|
|
383
|
-
if (session) {
|
|
384
|
-
await ctx.context.internalAdapter.deleteSession(
|
|
385
|
-
session.session.token
|
|
386
|
-
);
|
|
387
|
-
}
|
|
388
|
-
return ctx.json(null);
|
|
389
|
-
}
|
|
390
|
-
if (dontRememberMe || ctx.query?.disableRefresh) {
|
|
391
|
-
return ctx.json(
|
|
392
|
-
session
|
|
393
|
-
);
|
|
394
|
-
}
|
|
395
|
-
const expiresIn = ctx.context.sessionConfig.expiresIn;
|
|
396
|
-
const updateAge = ctx.context.sessionConfig.updateAge;
|
|
397
|
-
const sessionIsDueToBeUpdatedDate = session.session.expiresAt.valueOf() - expiresIn * 1e3 + updateAge * 1e3;
|
|
398
|
-
const shouldBeUpdated = sessionIsDueToBeUpdatedDate <= Date.now();
|
|
399
|
-
if (shouldBeUpdated) {
|
|
400
|
-
const updatedSession = await ctx.context.internalAdapter.updateSession(
|
|
401
|
-
session.session.token,
|
|
402
|
-
{
|
|
403
|
-
expiresAt: getDate(ctx.context.sessionConfig.expiresIn, "sec")
|
|
404
|
-
}
|
|
405
|
-
);
|
|
406
|
-
if (!updatedSession) {
|
|
407
|
-
deleteSessionCookie(ctx);
|
|
408
|
-
return ctx.json(null, { status: 401 });
|
|
409
|
-
}
|
|
410
|
-
const maxAge = (updatedSession.expiresAt.valueOf() - Date.now()) / 1e3;
|
|
411
|
-
await setSessionCookie(
|
|
412
|
-
ctx,
|
|
413
|
-
{
|
|
414
|
-
session: updatedSession,
|
|
415
|
-
user: session.user
|
|
416
|
-
},
|
|
417
|
-
false,
|
|
418
|
-
{
|
|
419
|
-
maxAge
|
|
420
|
-
}
|
|
421
|
-
);
|
|
422
|
-
return ctx.json({
|
|
423
|
-
session: updatedSession,
|
|
424
|
-
user: session.user
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
await setCookieCache(ctx, session);
|
|
428
|
-
return ctx.json(
|
|
429
|
-
session
|
|
430
|
-
);
|
|
431
|
-
} catch (error2) {
|
|
432
|
-
ctx.context.logger.error("INTERNAL_SERVER_ERROR", error2);
|
|
433
|
-
throw new APIError("INTERNAL_SERVER_ERROR", {
|
|
434
|
-
message: BASE_ERROR_CODES.FAILED_TO_GET_SESSION
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
);
|
|
439
|
-
var getSessionFromCtx = async (ctx, config) => {
|
|
440
|
-
if (ctx.context.session) {
|
|
441
|
-
return ctx.context.session;
|
|
442
|
-
}
|
|
443
|
-
const session = await getSession()({
|
|
444
|
-
...ctx,
|
|
445
|
-
asResponse: false,
|
|
446
|
-
headers: ctx.headers,
|
|
447
|
-
returnHeaders: false,
|
|
448
|
-
query: {
|
|
449
|
-
...config,
|
|
450
|
-
...ctx.query
|
|
451
|
-
}
|
|
452
|
-
}).catch((e) => {
|
|
453
|
-
return null;
|
|
454
|
-
});
|
|
455
|
-
ctx.context.session = session;
|
|
456
|
-
return session;
|
|
457
|
-
};
|
|
458
|
-
var sessionMiddleware = createAuthMiddleware(async (ctx) => {
|
|
459
|
-
const session = await getSessionFromCtx(ctx);
|
|
460
|
-
if (!session?.session) {
|
|
461
|
-
throw new APIError("UNAUTHORIZED");
|
|
462
|
-
}
|
|
463
|
-
return {
|
|
464
|
-
session
|
|
465
|
-
};
|
|
466
|
-
});
|
|
467
|
-
var requestOnlySessionMiddleware = createAuthMiddleware(
|
|
468
|
-
async (ctx) => {
|
|
469
|
-
const session = await getSessionFromCtx(ctx);
|
|
470
|
-
if (!session?.session && (ctx.request || ctx.headers)) {
|
|
471
|
-
throw new APIError("UNAUTHORIZED");
|
|
472
|
-
}
|
|
473
|
-
return { session };
|
|
474
|
-
}
|
|
475
|
-
);
|
|
476
|
-
var freshSessionMiddleware = createAuthMiddleware(async (ctx) => {
|
|
477
|
-
const session = await getSessionFromCtx(ctx);
|
|
478
|
-
if (!session?.session) {
|
|
479
|
-
throw new APIError("UNAUTHORIZED");
|
|
480
|
-
}
|
|
481
|
-
if (ctx.context.sessionConfig.freshAge === 0) {
|
|
482
|
-
return {
|
|
483
|
-
session
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
const freshAge = ctx.context.sessionConfig.freshAge;
|
|
487
|
-
const lastUpdated = session.session.updatedAt?.valueOf() || session.session.createdAt.valueOf();
|
|
488
|
-
const now = Date.now();
|
|
489
|
-
const isFresh = now - lastUpdated < freshAge * 1e3;
|
|
490
|
-
if (!isFresh) {
|
|
491
|
-
throw new APIError("FORBIDDEN", {
|
|
492
|
-
message: "Session is not fresh"
|
|
493
|
-
});
|
|
494
|
-
}
|
|
495
|
-
return {
|
|
496
|
-
session
|
|
497
|
-
};
|
|
498
|
-
});
|
|
499
|
-
var listSessions = () => createAuthEndpoint(
|
|
500
|
-
"/list-sessions",
|
|
501
|
-
{
|
|
502
|
-
method: "GET",
|
|
503
|
-
use: [sessionMiddleware],
|
|
504
|
-
requireHeaders: true,
|
|
505
|
-
metadata: {
|
|
506
|
-
openapi: {
|
|
507
|
-
description: "List all active sessions for the user",
|
|
508
|
-
responses: {
|
|
509
|
-
"200": {
|
|
510
|
-
description: "Success",
|
|
511
|
-
content: {
|
|
512
|
-
"application/json": {
|
|
513
|
-
schema: {
|
|
514
|
-
type: "array",
|
|
515
|
-
items: {
|
|
516
|
-
type: "object",
|
|
517
|
-
properties: {
|
|
518
|
-
token: {
|
|
519
|
-
type: "string"
|
|
520
|
-
},
|
|
521
|
-
userId: {
|
|
522
|
-
type: "string"
|
|
523
|
-
},
|
|
524
|
-
expiresAt: {
|
|
525
|
-
type: "string"
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
},
|
|
537
|
-
async (ctx) => {
|
|
538
|
-
try {
|
|
539
|
-
const sessions = await ctx.context.internalAdapter.listSessions(
|
|
540
|
-
ctx.context.session.user.id
|
|
541
|
-
);
|
|
542
|
-
const activeSessions = sessions.filter((session) => {
|
|
543
|
-
return session.expiresAt > /* @__PURE__ */ new Date();
|
|
544
|
-
});
|
|
545
|
-
return ctx.json(
|
|
546
|
-
activeSessions
|
|
547
|
-
);
|
|
548
|
-
} catch (e) {
|
|
549
|
-
ctx.context.logger.error(e);
|
|
550
|
-
throw ctx.error("INTERNAL_SERVER_ERROR");
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
);
|
|
554
|
-
var revokeSession = createAuthEndpoint(
|
|
555
|
-
"/revoke-session",
|
|
556
|
-
{
|
|
557
|
-
method: "POST",
|
|
558
|
-
body: z.object({
|
|
559
|
-
token: z.string({
|
|
560
|
-
description: "The token to revoke"
|
|
561
|
-
})
|
|
562
|
-
}),
|
|
563
|
-
use: [sessionMiddleware],
|
|
564
|
-
requireHeaders: true,
|
|
565
|
-
metadata: {
|
|
566
|
-
openapi: {
|
|
567
|
-
description: "Revoke a single session",
|
|
568
|
-
requestBody: {
|
|
569
|
-
content: {
|
|
570
|
-
"application/json": {
|
|
571
|
-
schema: {
|
|
572
|
-
type: "object",
|
|
573
|
-
properties: {
|
|
574
|
-
token: {
|
|
575
|
-
type: "string"
|
|
576
|
-
}
|
|
577
|
-
},
|
|
578
|
-
required: ["token"]
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
},
|
|
586
|
-
async (ctx) => {
|
|
587
|
-
const token = ctx.body.token;
|
|
588
|
-
const findSession = await ctx.context.internalAdapter.findSession(token);
|
|
589
|
-
if (!findSession) {
|
|
590
|
-
throw new APIError("BAD_REQUEST", {
|
|
591
|
-
message: "Session not found"
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
if (findSession.session.userId !== ctx.context.session.user.id) {
|
|
595
|
-
throw new APIError("UNAUTHORIZED");
|
|
596
|
-
}
|
|
597
|
-
try {
|
|
598
|
-
await ctx.context.internalAdapter.deleteSession(token);
|
|
599
|
-
} catch (error2) {
|
|
600
|
-
ctx.context.logger.error(
|
|
601
|
-
error2 && typeof error2 === "object" && "name" in error2 ? error2.name : "",
|
|
602
|
-
error2
|
|
603
|
-
);
|
|
604
|
-
throw new APIError("INTERNAL_SERVER_ERROR");
|
|
605
|
-
}
|
|
606
|
-
return ctx.json({
|
|
607
|
-
status: true
|
|
608
|
-
});
|
|
609
|
-
}
|
|
610
|
-
);
|
|
611
|
-
var revokeSessions = createAuthEndpoint(
|
|
612
|
-
"/revoke-sessions",
|
|
613
|
-
{
|
|
614
|
-
method: "POST",
|
|
615
|
-
use: [sessionMiddleware],
|
|
616
|
-
requireHeaders: true,
|
|
617
|
-
metadata: {
|
|
618
|
-
openapi: {
|
|
619
|
-
description: "Revoke all sessions for the user",
|
|
620
|
-
responses: {
|
|
621
|
-
"200": {
|
|
622
|
-
description: "Success",
|
|
623
|
-
content: {
|
|
624
|
-
"application/json": {
|
|
625
|
-
schema: {
|
|
626
|
-
type: "object",
|
|
627
|
-
properties: {
|
|
628
|
-
status: {
|
|
629
|
-
type: "boolean"
|
|
630
|
-
}
|
|
631
|
-
},
|
|
632
|
-
required: ["status"]
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
},
|
|
641
|
-
async (ctx) => {
|
|
642
|
-
try {
|
|
643
|
-
await ctx.context.internalAdapter.deleteSessions(
|
|
644
|
-
ctx.context.session.user.id
|
|
645
|
-
);
|
|
646
|
-
} catch (error2) {
|
|
647
|
-
ctx.context.logger.error(
|
|
648
|
-
error2 && typeof error2 === "object" && "name" in error2 ? error2.name : "",
|
|
649
|
-
error2
|
|
650
|
-
);
|
|
651
|
-
throw new APIError("INTERNAL_SERVER_ERROR");
|
|
652
|
-
}
|
|
653
|
-
return ctx.json({
|
|
654
|
-
status: true
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
);
|
|
658
|
-
var revokeOtherSessions = createAuthEndpoint(
|
|
659
|
-
"/revoke-other-sessions",
|
|
660
|
-
{
|
|
661
|
-
method: "POST",
|
|
662
|
-
requireHeaders: true,
|
|
663
|
-
use: [sessionMiddleware],
|
|
664
|
-
metadata: {
|
|
665
|
-
openapi: {
|
|
666
|
-
description: "Revoke all other sessions for the user except the current one",
|
|
667
|
-
responses: {
|
|
668
|
-
"200": {
|
|
669
|
-
description: "Success",
|
|
670
|
-
content: {
|
|
671
|
-
"application/json": {
|
|
672
|
-
schema: {
|
|
673
|
-
type: "object",
|
|
674
|
-
properties: {
|
|
675
|
-
status: {
|
|
676
|
-
type: "boolean"
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
},
|
|
687
|
-
async (ctx) => {
|
|
688
|
-
const session = ctx.context.session;
|
|
689
|
-
if (!session.user) {
|
|
690
|
-
throw new APIError("UNAUTHORIZED");
|
|
691
|
-
}
|
|
692
|
-
const sessions = await ctx.context.internalAdapter.listSessions(
|
|
693
|
-
session.user.id
|
|
694
|
-
);
|
|
695
|
-
const activeSessions = sessions.filter((session2) => {
|
|
696
|
-
return session2.expiresAt > /* @__PURE__ */ new Date();
|
|
697
|
-
});
|
|
698
|
-
const otherSessions = activeSessions.filter(
|
|
699
|
-
(session2) => session2.token !== ctx.context.session.session.token
|
|
700
|
-
);
|
|
701
|
-
await Promise.all(
|
|
702
|
-
otherSessions.map(
|
|
703
|
-
(session2) => ctx.context.internalAdapter.deleteSession(session2.token)
|
|
704
|
-
)
|
|
705
|
-
);
|
|
706
|
-
return ctx.json({
|
|
707
|
-
status: true
|
|
708
|
-
});
|
|
709
|
-
}
|
|
710
|
-
);
|
|
711
|
-
async function createEmailVerificationToken(secret, email, updateTo, expiresIn = 3600) {
|
|
712
|
-
const token = await signJWT(
|
|
713
|
-
{
|
|
714
|
-
email: email.toLowerCase(),
|
|
715
|
-
updateTo
|
|
716
|
-
},
|
|
717
|
-
secret,
|
|
718
|
-
expiresIn
|
|
719
|
-
);
|
|
720
|
-
return token;
|
|
721
|
-
}
|
|
722
|
-
async function sendVerificationEmailFn(ctx, user) {
|
|
723
|
-
if (!ctx.context.options.emailVerification?.sendVerificationEmail) {
|
|
724
|
-
ctx.context.logger.error("Verification email isn't enabled.");
|
|
725
|
-
throw new APIError("BAD_REQUEST", {
|
|
726
|
-
message: "Verification email isn't enabled"
|
|
727
|
-
});
|
|
728
|
-
}
|
|
729
|
-
const token = await createEmailVerificationToken(
|
|
730
|
-
ctx.context.secret,
|
|
731
|
-
user.email,
|
|
732
|
-
undefined,
|
|
733
|
-
ctx.context.options.emailVerification?.expiresIn
|
|
734
|
-
);
|
|
735
|
-
const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || "/"}`;
|
|
736
|
-
await ctx.context.options.emailVerification.sendVerificationEmail(
|
|
737
|
-
{
|
|
738
|
-
user,
|
|
739
|
-
url,
|
|
740
|
-
token
|
|
741
|
-
},
|
|
742
|
-
ctx.request
|
|
743
|
-
);
|
|
744
|
-
}
|
|
745
|
-
var sendVerificationEmail = createAuthEndpoint(
|
|
746
|
-
"/send-verification-email",
|
|
747
|
-
{
|
|
748
|
-
method: "POST",
|
|
749
|
-
body: z.object({
|
|
750
|
-
email: z.string({
|
|
751
|
-
description: "The email to send the verification email to"
|
|
752
|
-
}).email(),
|
|
753
|
-
callbackURL: z.string({
|
|
754
|
-
description: "The URL to use for email verification callback"
|
|
755
|
-
}).optional()
|
|
756
|
-
}),
|
|
757
|
-
metadata: {
|
|
758
|
-
openapi: {
|
|
759
|
-
description: "Send a verification email to the user",
|
|
760
|
-
requestBody: {
|
|
761
|
-
content: {
|
|
762
|
-
"application/json": {
|
|
763
|
-
schema: {
|
|
764
|
-
type: "object",
|
|
765
|
-
properties: {
|
|
766
|
-
email: {
|
|
767
|
-
type: "string",
|
|
768
|
-
description: "The email to send the verification email to"
|
|
769
|
-
},
|
|
770
|
-
callbackURL: {
|
|
771
|
-
type: "string",
|
|
772
|
-
description: "The URL to use for email verification callback"
|
|
773
|
-
}
|
|
774
|
-
},
|
|
775
|
-
required: ["email"]
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
},
|
|
780
|
-
responses: {
|
|
781
|
-
"200": {
|
|
782
|
-
description: "Success",
|
|
783
|
-
content: {
|
|
784
|
-
"application/json": {
|
|
785
|
-
schema: {
|
|
786
|
-
type: "object",
|
|
787
|
-
properties: {
|
|
788
|
-
status: {
|
|
789
|
-
type: "boolean"
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
},
|
|
800
|
-
async (ctx) => {
|
|
801
|
-
if (!ctx.context.options.emailVerification?.sendVerificationEmail) {
|
|
802
|
-
ctx.context.logger.error("Verification email isn't enabled.");
|
|
803
|
-
throw new APIError("BAD_REQUEST", {
|
|
804
|
-
message: "Verification email isn't enabled"
|
|
805
|
-
});
|
|
806
|
-
}
|
|
807
|
-
const { email } = ctx.body;
|
|
808
|
-
const user = await ctx.context.internalAdapter.findUserByEmail(email);
|
|
809
|
-
if (!user) {
|
|
810
|
-
throw new APIError("BAD_REQUEST", {
|
|
811
|
-
message: BASE_ERROR_CODES.USER_NOT_FOUND
|
|
812
|
-
});
|
|
813
|
-
}
|
|
814
|
-
await sendVerificationEmailFn(ctx, user.user);
|
|
815
|
-
return ctx.json({
|
|
816
|
-
status: true
|
|
817
|
-
});
|
|
818
|
-
}
|
|
819
|
-
);
|
|
820
|
-
var verifyEmail = createAuthEndpoint(
|
|
821
|
-
"/verify-email",
|
|
822
|
-
{
|
|
823
|
-
method: "GET",
|
|
824
|
-
query: z.object({
|
|
825
|
-
token: z.string({
|
|
826
|
-
description: "The token to verify the email"
|
|
827
|
-
}),
|
|
828
|
-
callbackURL: z.string({
|
|
829
|
-
description: "The URL to redirect to after email verification"
|
|
830
|
-
}).optional()
|
|
831
|
-
}),
|
|
832
|
-
use: [originCheck((ctx) => ctx.query.callbackURL)],
|
|
833
|
-
metadata: {
|
|
834
|
-
openapi: {
|
|
835
|
-
description: "Verify the email of the user",
|
|
836
|
-
responses: {
|
|
837
|
-
"200": {
|
|
838
|
-
description: "Success",
|
|
839
|
-
content: {
|
|
840
|
-
"application/json": {
|
|
841
|
-
schema: {
|
|
842
|
-
type: "object",
|
|
843
|
-
properties: {
|
|
844
|
-
user: {
|
|
845
|
-
type: "object"
|
|
846
|
-
},
|
|
847
|
-
status: {
|
|
848
|
-
type: "boolean"
|
|
849
|
-
}
|
|
850
|
-
},
|
|
851
|
-
required: ["user", "status"]
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
},
|
|
860
|
-
async (ctx) => {
|
|
861
|
-
function redirectOnError(error2) {
|
|
862
|
-
if (ctx.query.callbackURL) {
|
|
863
|
-
if (ctx.query.callbackURL.includes("?")) {
|
|
864
|
-
throw ctx.redirect(`${ctx.query.callbackURL}&error=${error2}`);
|
|
865
|
-
}
|
|
866
|
-
throw ctx.redirect(`${ctx.query.callbackURL}?error=${error2}`);
|
|
867
|
-
}
|
|
868
|
-
throw new APIError("UNAUTHORIZED", {
|
|
869
|
-
message: error2
|
|
870
|
-
});
|
|
871
|
-
}
|
|
872
|
-
const { token } = ctx.query;
|
|
873
|
-
let jwt;
|
|
874
|
-
try {
|
|
875
|
-
jwt = await jwtVerify(
|
|
876
|
-
token,
|
|
877
|
-
new TextEncoder().encode(ctx.context.secret),
|
|
878
|
-
{
|
|
879
|
-
algorithms: ["HS256"]
|
|
880
|
-
}
|
|
881
|
-
);
|
|
882
|
-
} catch (e) {
|
|
883
|
-
if (e instanceof JWTExpired) {
|
|
884
|
-
return redirectOnError("token_expired");
|
|
885
|
-
}
|
|
886
|
-
return redirectOnError("invalid_token");
|
|
887
|
-
}
|
|
888
|
-
const schema2 = z.object({
|
|
889
|
-
email: z.string().email(),
|
|
890
|
-
updateTo: z.string().optional()
|
|
891
|
-
});
|
|
892
|
-
const parsed = schema2.parse(jwt.payload);
|
|
893
|
-
const user = await ctx.context.internalAdapter.findUserByEmail(
|
|
894
|
-
parsed.email
|
|
895
|
-
);
|
|
896
|
-
if (!user) {
|
|
897
|
-
return redirectOnError("user_not_found");
|
|
898
|
-
}
|
|
899
|
-
if (parsed.updateTo) {
|
|
900
|
-
const session = await getSessionFromCtx(ctx);
|
|
901
|
-
if (!session) {
|
|
902
|
-
if (ctx.query.callbackURL) {
|
|
903
|
-
throw ctx.redirect(`${ctx.query.callbackURL}?error=unauthorized`);
|
|
904
|
-
}
|
|
905
|
-
return redirectOnError("unauthorized");
|
|
906
|
-
}
|
|
907
|
-
if (session.user.email !== parsed.email) {
|
|
908
|
-
if (ctx.query.callbackURL) {
|
|
909
|
-
throw ctx.redirect(`${ctx.query.callbackURL}?error=unauthorized`);
|
|
910
|
-
}
|
|
911
|
-
return redirectOnError("unauthorized");
|
|
912
|
-
}
|
|
913
|
-
const updatedUser = await ctx.context.internalAdapter.updateUserByEmail(
|
|
914
|
-
parsed.email,
|
|
915
|
-
{
|
|
916
|
-
email: parsed.updateTo,
|
|
917
|
-
emailVerified: false
|
|
918
|
-
},
|
|
919
|
-
ctx
|
|
920
|
-
);
|
|
921
|
-
const newToken = await createEmailVerificationToken(
|
|
922
|
-
ctx.context.secret,
|
|
923
|
-
parsed.updateTo
|
|
924
|
-
);
|
|
925
|
-
await ctx.context.options.emailVerification?.sendVerificationEmail?.(
|
|
926
|
-
{
|
|
927
|
-
user: updatedUser,
|
|
928
|
-
url: `${ctx.context.baseURL}/verify-email?token=${newToken}&callbackURL=${ctx.query.callbackURL || "/"}`,
|
|
929
|
-
token: newToken
|
|
930
|
-
},
|
|
931
|
-
ctx.request
|
|
932
|
-
);
|
|
933
|
-
await setSessionCookie(ctx, {
|
|
934
|
-
session: session.session,
|
|
935
|
-
user: {
|
|
936
|
-
...session.user,
|
|
937
|
-
email: parsed.updateTo,
|
|
938
|
-
emailVerified: false
|
|
939
|
-
}
|
|
940
|
-
});
|
|
941
|
-
if (ctx.query.callbackURL) {
|
|
942
|
-
throw ctx.redirect(ctx.query.callbackURL);
|
|
943
|
-
}
|
|
944
|
-
return ctx.json({
|
|
945
|
-
status: true,
|
|
946
|
-
user: {
|
|
947
|
-
id: updatedUser.id,
|
|
948
|
-
email: updatedUser.email,
|
|
949
|
-
name: updatedUser.name,
|
|
950
|
-
image: updatedUser.image,
|
|
951
|
-
emailVerified: updatedUser.emailVerified,
|
|
952
|
-
createdAt: updatedUser.createdAt,
|
|
953
|
-
updatedAt: updatedUser.updatedAt
|
|
954
|
-
}
|
|
955
|
-
});
|
|
956
|
-
}
|
|
957
|
-
await ctx.context.internalAdapter.updateUserByEmail(
|
|
958
|
-
parsed.email,
|
|
959
|
-
{
|
|
960
|
-
emailVerified: true
|
|
961
|
-
},
|
|
962
|
-
ctx
|
|
963
|
-
);
|
|
964
|
-
if (ctx.context.options.emailVerification?.autoSignInAfterVerification) {
|
|
965
|
-
const currentSession = await getSessionFromCtx(ctx);
|
|
966
|
-
if (!currentSession || currentSession.user.email !== parsed.email) {
|
|
967
|
-
const session = await ctx.context.internalAdapter.createSession(
|
|
968
|
-
user.user.id,
|
|
969
|
-
ctx.request
|
|
970
|
-
);
|
|
971
|
-
if (!session) {
|
|
972
|
-
throw new APIError("INTERNAL_SERVER_ERROR", {
|
|
973
|
-
message: "Failed to create session"
|
|
974
|
-
});
|
|
975
|
-
}
|
|
976
|
-
await setSessionCookie(ctx, {
|
|
977
|
-
session,
|
|
978
|
-
user: {
|
|
979
|
-
...user.user,
|
|
980
|
-
emailVerified: true
|
|
981
|
-
}
|
|
982
|
-
});
|
|
983
|
-
} else {
|
|
984
|
-
await setSessionCookie(ctx, {
|
|
985
|
-
session: currentSession.session,
|
|
986
|
-
user: {
|
|
987
|
-
...currentSession.user,
|
|
988
|
-
emailVerified: true
|
|
989
|
-
}
|
|
990
|
-
});
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
if (ctx.query.callbackURL) {
|
|
994
|
-
throw ctx.redirect(ctx.query.callbackURL);
|
|
995
|
-
}
|
|
996
|
-
return ctx.json({
|
|
997
|
-
status: true,
|
|
998
|
-
user: null
|
|
999
|
-
});
|
|
1000
|
-
}
|
|
1001
|
-
);
|
|
1002
|
-
|
|
1003
|
-
// src/oauth2/link-account.ts
|
|
1004
|
-
async function handleOAuthUserInfo(c, {
|
|
1005
|
-
userInfo,
|
|
1006
|
-
account,
|
|
1007
|
-
callbackURL
|
|
1008
|
-
}) {
|
|
1009
|
-
const dbUser = await c.context.internalAdapter.findOAuthUser(
|
|
1010
|
-
userInfo.email.toLowerCase(),
|
|
1011
|
-
account.accountId,
|
|
1012
|
-
account.providerId
|
|
1013
|
-
).catch((e) => {
|
|
1014
|
-
logger.error(
|
|
1015
|
-
"Better auth was unable to query your database.\nError: ",
|
|
1016
|
-
e
|
|
1017
|
-
);
|
|
1018
|
-
throw c.redirect(
|
|
1019
|
-
`${c.context.baseURL}/error?error=internal_server_error`
|
|
1020
|
-
);
|
|
1021
|
-
});
|
|
1022
|
-
let user = dbUser?.user;
|
|
1023
|
-
let isRegister = !user;
|
|
1024
|
-
if (dbUser) {
|
|
1025
|
-
const hasBeenLinked = dbUser.accounts.find(
|
|
1026
|
-
(a) => a.providerId === account.providerId
|
|
1027
|
-
);
|
|
1028
|
-
if (!hasBeenLinked) {
|
|
1029
|
-
const trustedProviders = c.context.options.account?.accountLinking?.trustedProviders;
|
|
1030
|
-
const isTrustedProvider = trustedProviders?.includes(
|
|
1031
|
-
account.providerId
|
|
1032
|
-
);
|
|
1033
|
-
if (!isTrustedProvider && !userInfo.emailVerified || c.context.options.account?.accountLinking?.enabled === false) {
|
|
1034
|
-
if (isDevelopment) {
|
|
1035
|
-
logger.warn(
|
|
1036
|
-
`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.`
|
|
1037
|
-
);
|
|
1038
|
-
}
|
|
1039
|
-
return {
|
|
1040
|
-
error: "account not linked",
|
|
1041
|
-
data: null
|
|
1042
|
-
};
|
|
1043
|
-
}
|
|
1044
|
-
try {
|
|
1045
|
-
await c.context.internalAdapter.linkAccount(
|
|
1046
|
-
{
|
|
1047
|
-
providerId: account.providerId,
|
|
1048
|
-
accountId: userInfo.id.toString(),
|
|
1049
|
-
userId: dbUser.user.id,
|
|
1050
|
-
accessToken: account.accessToken,
|
|
1051
|
-
idToken: account.idToken,
|
|
1052
|
-
refreshToken: account.refreshToken,
|
|
1053
|
-
accessTokenExpiresAt: account.accessTokenExpiresAt,
|
|
1054
|
-
refreshTokenExpiresAt: account.refreshTokenExpiresAt,
|
|
1055
|
-
scope: account.scope
|
|
1056
|
-
},
|
|
1057
|
-
c
|
|
1058
|
-
);
|
|
1059
|
-
} catch (e) {
|
|
1060
|
-
logger.error("Unable to link account", e);
|
|
1061
|
-
return {
|
|
1062
|
-
error: "unable to link account",
|
|
1063
|
-
data: null
|
|
1064
|
-
};
|
|
1065
|
-
}
|
|
1066
|
-
} else {
|
|
1067
|
-
const updateData = Object.fromEntries(
|
|
1068
|
-
Object.entries({
|
|
1069
|
-
accessToken: account.accessToken,
|
|
1070
|
-
idToken: account.idToken,
|
|
1071
|
-
refreshToken: account.refreshToken,
|
|
1072
|
-
accessTokenExpiresAt: account.accessTokenExpiresAt,
|
|
1073
|
-
refreshTokenExpiresAt: account.refreshTokenExpiresAt,
|
|
1074
|
-
scope: account.scope
|
|
1075
|
-
}).filter(([_, value]) => value !== undefined)
|
|
1076
|
-
);
|
|
1077
|
-
if (Object.keys(updateData).length > 0) {
|
|
1078
|
-
await c.context.internalAdapter.updateAccount(
|
|
1079
|
-
hasBeenLinked.id,
|
|
1080
|
-
updateData,
|
|
1081
|
-
c
|
|
1082
|
-
);
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
} else {
|
|
1086
|
-
try {
|
|
1087
|
-
user = await c.context.internalAdapter.createOAuthUser(
|
|
1088
|
-
{
|
|
1089
|
-
...userInfo,
|
|
1090
|
-
email: userInfo.email.toLowerCase(),
|
|
1091
|
-
id: void 0
|
|
1092
|
-
},
|
|
1093
|
-
{
|
|
1094
|
-
accessToken: account.accessToken,
|
|
1095
|
-
idToken: account.idToken,
|
|
1096
|
-
refreshToken: account.refreshToken,
|
|
1097
|
-
accessTokenExpiresAt: account.accessTokenExpiresAt,
|
|
1098
|
-
refreshTokenExpiresAt: account.refreshTokenExpiresAt,
|
|
1099
|
-
scope: account.scope,
|
|
1100
|
-
providerId: account.providerId,
|
|
1101
|
-
accountId: userInfo.id.toString()
|
|
1102
|
-
},
|
|
1103
|
-
c
|
|
1104
|
-
).then((res) => res?.user);
|
|
1105
|
-
if (!userInfo.emailVerified && user && c.context.options.emailVerification?.sendOnSignUp) {
|
|
1106
|
-
const token = await createEmailVerificationToken(
|
|
1107
|
-
c.context.secret,
|
|
1108
|
-
user.email,
|
|
1109
|
-
void 0,
|
|
1110
|
-
c.context.options.emailVerification?.expiresIn
|
|
1111
|
-
);
|
|
1112
|
-
const url = `${c.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`;
|
|
1113
|
-
await c.context.options.emailVerification?.sendVerificationEmail?.(
|
|
1114
|
-
{
|
|
1115
|
-
user,
|
|
1116
|
-
url,
|
|
1117
|
-
token
|
|
1118
|
-
},
|
|
1119
|
-
c.request
|
|
1120
|
-
);
|
|
1121
|
-
}
|
|
1122
|
-
} catch (e) {
|
|
1123
|
-
logger.error(e);
|
|
1124
|
-
if (e instanceof APIError) {
|
|
1125
|
-
return {
|
|
1126
|
-
error: e.message,
|
|
1127
|
-
data: null,
|
|
1128
|
-
isRegister: false
|
|
1129
|
-
};
|
|
1130
|
-
}
|
|
1131
|
-
return {
|
|
1132
|
-
error: "unable to create user",
|
|
1133
|
-
data: null,
|
|
1134
|
-
isRegister: false
|
|
1135
|
-
};
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
if (!user) {
|
|
1139
|
-
return {
|
|
1140
|
-
error: "unable to create user",
|
|
1141
|
-
data: null,
|
|
1142
|
-
isRegister: false
|
|
1143
|
-
};
|
|
1144
|
-
}
|
|
1145
|
-
const session = await c.context.internalAdapter.createSession(
|
|
1146
|
-
user.id,
|
|
1147
|
-
c.request
|
|
1148
|
-
);
|
|
1149
|
-
if (!session) {
|
|
1150
|
-
return {
|
|
1151
|
-
error: "unable to create session",
|
|
1152
|
-
data: null,
|
|
1153
|
-
isRegister: false
|
|
1154
|
-
};
|
|
1155
|
-
}
|
|
1156
|
-
return {
|
|
1157
|
-
data: {
|
|
1158
|
-
session,
|
|
1159
|
-
user
|
|
1160
|
-
},
|
|
1161
|
-
error: null,
|
|
1162
|
-
isRegister
|
|
1163
|
-
};
|
|
1164
|
-
}
|
|
1165
|
-
|
|
1166
|
-
// src/api/routes/sign-in.ts
|
|
1167
|
-
var signInSocial = createAuthEndpoint(
|
|
1168
|
-
"/sign-in/social",
|
|
1169
|
-
{
|
|
1170
|
-
method: "POST",
|
|
1171
|
-
body: z.object({
|
|
1172
|
-
/**
|
|
1173
|
-
* Callback URL to redirect to after the user
|
|
1174
|
-
* has signed in.
|
|
1175
|
-
*/
|
|
1176
|
-
callbackURL: z.string({
|
|
1177
|
-
description: "Callback URL to redirect to after the user has signed in"
|
|
1178
|
-
}).optional(),
|
|
1179
|
-
/**
|
|
1180
|
-
* callback url to redirect if the user is newly registered.
|
|
1181
|
-
*
|
|
1182
|
-
* useful if you have different routes for existing users and new users
|
|
1183
|
-
*/
|
|
1184
|
-
newUserCallbackURL: z.string().optional(),
|
|
1185
|
-
/**
|
|
1186
|
-
* Callback url to redirect to if an error happens
|
|
1187
|
-
*
|
|
1188
|
-
* If it's initiated from the client sdk this defaults to
|
|
1189
|
-
* the current url.
|
|
1190
|
-
*/
|
|
1191
|
-
errorCallbackURL: z.string({
|
|
1192
|
-
description: "Callback URL to redirect to if an error happens"
|
|
1193
|
-
}).optional(),
|
|
1194
|
-
/**
|
|
1195
|
-
* OAuth2 provider to use`
|
|
1196
|
-
*/
|
|
1197
|
-
provider: SocialProviderListEnum,
|
|
1198
|
-
/**
|
|
1199
|
-
* Disable automatic redirection to the provider
|
|
1200
|
-
*
|
|
1201
|
-
* This is useful if you want to handle the redirection
|
|
1202
|
-
* yourself like in a popup or a different tab.
|
|
1203
|
-
*/
|
|
1204
|
-
disableRedirect: z.boolean({
|
|
1205
|
-
description: "Disable automatic redirection to the provider. Useful for handling the redirection yourself"
|
|
1206
|
-
}).optional(),
|
|
1207
|
-
/**
|
|
1208
|
-
* ID token from the provider
|
|
1209
|
-
*
|
|
1210
|
-
* This is used to sign in the user
|
|
1211
|
-
* if the user is already signed in with the
|
|
1212
|
-
* provider in the frontend.
|
|
1213
|
-
*
|
|
1214
|
-
* Only applicable if the provider supports
|
|
1215
|
-
* it. Currently only `apple` and `google` is
|
|
1216
|
-
* supported out of the box.
|
|
1217
|
-
*/
|
|
1218
|
-
idToken: z.optional(
|
|
1219
|
-
z.object({
|
|
1220
|
-
/**
|
|
1221
|
-
* ID token from the provider
|
|
1222
|
-
*/
|
|
1223
|
-
token: z.string({
|
|
1224
|
-
description: "ID token from the provider"
|
|
1225
|
-
}),
|
|
1226
|
-
/**
|
|
1227
|
-
* The nonce used to generate the token
|
|
1228
|
-
*/
|
|
1229
|
-
nonce: z.string({
|
|
1230
|
-
description: "Nonce used to generate the token"
|
|
1231
|
-
}).optional(),
|
|
1232
|
-
/**
|
|
1233
|
-
* Access token from the provider
|
|
1234
|
-
*/
|
|
1235
|
-
accessToken: z.string({
|
|
1236
|
-
description: "Access token from the provider"
|
|
1237
|
-
}).optional(),
|
|
1238
|
-
/**
|
|
1239
|
-
* Refresh token from the provider
|
|
1240
|
-
*/
|
|
1241
|
-
refreshToken: z.string({
|
|
1242
|
-
description: "Refresh token from the provider"
|
|
1243
|
-
}).optional(),
|
|
1244
|
-
/**
|
|
1245
|
-
* Expiry date of the token
|
|
1246
|
-
*/
|
|
1247
|
-
expiresAt: z.number({
|
|
1248
|
-
description: "Expiry date of the token"
|
|
1249
|
-
}).optional()
|
|
1250
|
-
}),
|
|
1251
|
-
{
|
|
1252
|
-
description: "ID token from the provider to sign in the user with id token"
|
|
1253
|
-
}
|
|
1254
|
-
),
|
|
1255
|
-
scopes: z.array(z.string(), {
|
|
1256
|
-
description: "Array of scopes to request from the provider. This will override the default scopes passed."
|
|
1257
|
-
}).optional()
|
|
1258
|
-
}),
|
|
1259
|
-
metadata: {
|
|
1260
|
-
openapi: {
|
|
1261
|
-
description: "Sign in with a social provider",
|
|
1262
|
-
responses: {
|
|
1263
|
-
"200": {
|
|
1264
|
-
description: "Success",
|
|
1265
|
-
content: {
|
|
1266
|
-
"application/json": {
|
|
1267
|
-
schema: {
|
|
1268
|
-
type: "object",
|
|
1269
|
-
properties: {
|
|
1270
|
-
session: {
|
|
1271
|
-
type: "string"
|
|
1272
|
-
},
|
|
1273
|
-
user: {
|
|
1274
|
-
type: "object"
|
|
1275
|
-
},
|
|
1276
|
-
url: {
|
|
1277
|
-
type: "string"
|
|
1278
|
-
},
|
|
1279
|
-
redirect: {
|
|
1280
|
-
type: "boolean"
|
|
1281
|
-
}
|
|
1282
|
-
},
|
|
1283
|
-
required: ["session", "user", "url", "redirect"]
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
}
|
|
1291
|
-
},
|
|
1292
|
-
async (c) => {
|
|
1293
|
-
const provider = c.context.socialProviders.find(
|
|
1294
|
-
(p) => p.id === c.body.provider
|
|
1295
|
-
);
|
|
1296
|
-
if (!provider) {
|
|
1297
|
-
c.context.logger.error(
|
|
1298
|
-
"Provider not found. Make sure to add the provider in your auth config",
|
|
1299
|
-
{
|
|
1300
|
-
provider: c.body.provider
|
|
1301
|
-
}
|
|
1302
|
-
);
|
|
1303
|
-
throw new APIError("NOT_FOUND", {
|
|
1304
|
-
message: BASE_ERROR_CODES.PROVIDER_NOT_FOUND
|
|
1305
|
-
});
|
|
1306
|
-
}
|
|
1307
|
-
if (c.body.idToken) {
|
|
1308
|
-
if (!provider.verifyIdToken) {
|
|
1309
|
-
c.context.logger.error(
|
|
1310
|
-
"Provider does not support id token verification",
|
|
1311
|
-
{
|
|
1312
|
-
provider: c.body.provider
|
|
1313
|
-
}
|
|
1314
|
-
);
|
|
1315
|
-
throw new APIError("NOT_FOUND", {
|
|
1316
|
-
message: BASE_ERROR_CODES.ID_TOKEN_NOT_SUPPORTED
|
|
1317
|
-
});
|
|
1318
|
-
}
|
|
1319
|
-
const { token, nonce } = c.body.idToken;
|
|
1320
|
-
const valid = await provider.verifyIdToken(token, nonce);
|
|
1321
|
-
if (!valid) {
|
|
1322
|
-
c.context.logger.error("Invalid id token", {
|
|
1323
|
-
provider: c.body.provider
|
|
1324
|
-
});
|
|
1325
|
-
throw new APIError("UNAUTHORIZED", {
|
|
1326
|
-
message: BASE_ERROR_CODES.INVALID_TOKEN
|
|
1327
|
-
});
|
|
1328
|
-
}
|
|
1329
|
-
const userInfo = await provider.getUserInfo({
|
|
1330
|
-
idToken: token,
|
|
1331
|
-
accessToken: c.body.idToken.accessToken,
|
|
1332
|
-
refreshToken: c.body.idToken.refreshToken
|
|
1333
|
-
});
|
|
1334
|
-
if (!userInfo || !userInfo?.user) {
|
|
1335
|
-
c.context.logger.error("Failed to get user info", {
|
|
1336
|
-
provider: c.body.provider
|
|
1337
|
-
});
|
|
1338
|
-
throw new APIError("UNAUTHORIZED", {
|
|
1339
|
-
message: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO
|
|
1340
|
-
});
|
|
1341
|
-
}
|
|
1342
|
-
if (!userInfo.user.email) {
|
|
1343
|
-
c.context.logger.error("User email not found", {
|
|
1344
|
-
provider: c.body.provider
|
|
1345
|
-
});
|
|
1346
|
-
throw new APIError("UNAUTHORIZED", {
|
|
1347
|
-
message: BASE_ERROR_CODES.USER_EMAIL_NOT_FOUND
|
|
1348
|
-
});
|
|
1349
|
-
}
|
|
1350
|
-
const data = await handleOAuthUserInfo(c, {
|
|
1351
|
-
userInfo: {
|
|
1352
|
-
email: userInfo.user.email,
|
|
1353
|
-
id: userInfo.user.id,
|
|
1354
|
-
name: userInfo.user.name || "",
|
|
1355
|
-
image: userInfo.user.image,
|
|
1356
|
-
emailVerified: userInfo.user.emailVerified || false
|
|
1357
|
-
},
|
|
1358
|
-
account: {
|
|
1359
|
-
providerId: provider.id,
|
|
1360
|
-
accountId: userInfo.user.id,
|
|
1361
|
-
accessToken: c.body.idToken.accessToken
|
|
1362
|
-
}
|
|
1363
|
-
});
|
|
1364
|
-
if (data.error) {
|
|
1365
|
-
throw new APIError("UNAUTHORIZED", {
|
|
1366
|
-
message: data.error
|
|
1367
|
-
});
|
|
1368
|
-
}
|
|
1369
|
-
await setSessionCookie(c, data.data);
|
|
1370
|
-
return c.json({
|
|
1371
|
-
redirect: false,
|
|
1372
|
-
token: data.data.session.token,
|
|
1373
|
-
url: undefined,
|
|
1374
|
-
user: {
|
|
1375
|
-
id: data.data.user.id,
|
|
1376
|
-
email: data.data.user.email,
|
|
1377
|
-
name: data.data.user.name,
|
|
1378
|
-
image: data.data.user.image,
|
|
1379
|
-
emailVerified: data.data.user.emailVerified,
|
|
1380
|
-
createdAt: data.data.user.createdAt,
|
|
1381
|
-
updatedAt: data.data.user.updatedAt
|
|
1382
|
-
}
|
|
1383
|
-
});
|
|
1384
|
-
}
|
|
1385
|
-
const { codeVerifier, state } = await generateState(c);
|
|
1386
|
-
const url = await provider.createAuthorizationURL({
|
|
1387
|
-
state,
|
|
1388
|
-
codeVerifier,
|
|
1389
|
-
redirectURI: `${c.context.baseURL}/callback/${provider.id}`,
|
|
1390
|
-
scopes: c.body.scopes
|
|
1391
|
-
});
|
|
1392
|
-
return c.json({
|
|
1393
|
-
url: url.toString(),
|
|
1394
|
-
redirect: !c.body.disableRedirect
|
|
1395
|
-
});
|
|
1396
|
-
}
|
|
1397
|
-
);
|
|
1398
|
-
var signInEmail = createAuthEndpoint(
|
|
1399
|
-
"/sign-in/email",
|
|
1400
|
-
{
|
|
1401
|
-
method: "POST",
|
|
1402
|
-
body: z.object({
|
|
1403
|
-
/**
|
|
1404
|
-
* Email of the user
|
|
1405
|
-
*/
|
|
1406
|
-
email: z.string({
|
|
1407
|
-
description: "Email of the user"
|
|
1408
|
-
}),
|
|
1409
|
-
/**
|
|
1410
|
-
* Password of the user
|
|
1411
|
-
*/
|
|
1412
|
-
password: z.string({
|
|
1413
|
-
description: "Password of the user"
|
|
1414
|
-
}),
|
|
1415
|
-
/**
|
|
1416
|
-
* Callback URL to use as a redirect for email
|
|
1417
|
-
* verification and for possible redirects
|
|
1418
|
-
*/
|
|
1419
|
-
callbackURL: z.string({
|
|
1420
|
-
description: "Callback URL to use as a redirect for email verification"
|
|
1421
|
-
}).optional(),
|
|
1422
|
-
/**
|
|
1423
|
-
* If this is false, the session will not be remembered
|
|
1424
|
-
* @default true
|
|
1425
|
-
*/
|
|
1426
|
-
rememberMe: z.boolean({
|
|
1427
|
-
description: "If this is false, the session will not be remembered. Default is `true`."
|
|
1428
|
-
}).default(true).optional()
|
|
1429
|
-
}),
|
|
1430
|
-
metadata: {
|
|
1431
|
-
openapi: {
|
|
1432
|
-
description: "Sign in with email and password",
|
|
1433
|
-
responses: {
|
|
1434
|
-
"200": {
|
|
1435
|
-
description: "Success",
|
|
1436
|
-
content: {
|
|
1437
|
-
"application/json": {
|
|
1438
|
-
schema: {
|
|
1439
|
-
type: "object",
|
|
1440
|
-
properties: {
|
|
1441
|
-
user: {
|
|
1442
|
-
type: "object"
|
|
1443
|
-
},
|
|
1444
|
-
url: {
|
|
1445
|
-
type: "string"
|
|
1446
|
-
},
|
|
1447
|
-
redirect: {
|
|
1448
|
-
type: "boolean"
|
|
1449
|
-
}
|
|
1450
|
-
},
|
|
1451
|
-
required: ["session", "user", "url", "redirect"]
|
|
1452
|
-
}
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
}
|
|
1459
|
-
},
|
|
1460
|
-
async (ctx) => {
|
|
1461
|
-
if (!ctx.context.options?.emailAndPassword?.enabled) {
|
|
1462
|
-
ctx.context.logger.error(
|
|
1463
|
-
"Email and password is not enabled. Make sure to enable it in the options on you `auth.ts` file. Check `https://better-auth.com/docs/authentication/email-password` for more!"
|
|
1464
|
-
);
|
|
1465
|
-
throw new APIError("BAD_REQUEST", {
|
|
1466
|
-
message: "Email and password is not enabled"
|
|
1467
|
-
});
|
|
1468
|
-
}
|
|
1469
|
-
const { email, password } = ctx.body;
|
|
1470
|
-
const isValidEmail = z.string().email().safeParse(email);
|
|
1471
|
-
if (!isValidEmail.success) {
|
|
1472
|
-
throw new APIError("BAD_REQUEST", {
|
|
1473
|
-
message: BASE_ERROR_CODES.INVALID_EMAIL
|
|
1474
|
-
});
|
|
1475
|
-
}
|
|
1476
|
-
const user = await ctx.context.internalAdapter.findUserByEmail(email, {
|
|
1477
|
-
includeAccounts: true
|
|
1478
|
-
});
|
|
1479
|
-
if (!user) {
|
|
1480
|
-
await ctx.context.password.hash(password);
|
|
1481
|
-
ctx.context.logger.error("User not found", { email });
|
|
1482
|
-
throw new APIError("UNAUTHORIZED", {
|
|
1483
|
-
message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD
|
|
1484
|
-
});
|
|
1485
|
-
}
|
|
1486
|
-
const credentialAccount = user.accounts.find(
|
|
1487
|
-
(a) => a.providerId === "credential"
|
|
1488
|
-
);
|
|
1489
|
-
if (!credentialAccount) {
|
|
1490
|
-
ctx.context.logger.error("Credential account not found", { email });
|
|
1491
|
-
throw new APIError("UNAUTHORIZED", {
|
|
1492
|
-
message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD
|
|
1493
|
-
});
|
|
1494
|
-
}
|
|
1495
|
-
const currentPassword = credentialAccount?.password;
|
|
1496
|
-
if (!currentPassword) {
|
|
1497
|
-
ctx.context.logger.error("Password not found", { email });
|
|
1498
|
-
throw new APIError("UNAUTHORIZED", {
|
|
1499
|
-
message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD
|
|
1500
|
-
});
|
|
1501
|
-
}
|
|
1502
|
-
const validPassword = await ctx.context.password.verify({
|
|
1503
|
-
hash: currentPassword,
|
|
1504
|
-
password
|
|
1505
|
-
});
|
|
1506
|
-
if (!validPassword) {
|
|
1507
|
-
ctx.context.logger.error("Invalid password");
|
|
1508
|
-
throw new APIError("UNAUTHORIZED", {
|
|
1509
|
-
message: BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD
|
|
1510
|
-
});
|
|
1511
|
-
}
|
|
1512
|
-
if (ctx.context.options?.emailAndPassword?.requireEmailVerification && !user.user.emailVerified) {
|
|
1513
|
-
if (!ctx.context.options?.emailVerification?.sendVerificationEmail) {
|
|
1514
|
-
throw new APIError("FORBIDDEN", {
|
|
1515
|
-
message: BASE_ERROR_CODES.EMAIL_NOT_VERIFIED
|
|
1516
|
-
});
|
|
1517
|
-
}
|
|
1518
|
-
const token = await createEmailVerificationToken(
|
|
1519
|
-
ctx.context.secret,
|
|
1520
|
-
user.user.email,
|
|
1521
|
-
undefined,
|
|
1522
|
-
ctx.context.options.emailVerification?.expiresIn
|
|
1523
|
-
);
|
|
1524
|
-
const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || "/"}`;
|
|
1525
|
-
await ctx.context.options.emailVerification.sendVerificationEmail(
|
|
1526
|
-
{
|
|
1527
|
-
user: user.user,
|
|
1528
|
-
url,
|
|
1529
|
-
token
|
|
1530
|
-
},
|
|
1531
|
-
ctx.request
|
|
1532
|
-
);
|
|
1533
|
-
throw new APIError("FORBIDDEN", {
|
|
1534
|
-
message: BASE_ERROR_CODES.EMAIL_NOT_VERIFIED
|
|
1535
|
-
});
|
|
1536
|
-
}
|
|
1537
|
-
const session = await ctx.context.internalAdapter.createSession(
|
|
1538
|
-
user.user.id,
|
|
1539
|
-
ctx.headers,
|
|
1540
|
-
ctx.body.rememberMe === false
|
|
1541
|
-
);
|
|
1542
|
-
if (!session) {
|
|
1543
|
-
ctx.context.logger.error("Failed to create session");
|
|
1544
|
-
throw new APIError("UNAUTHORIZED", {
|
|
1545
|
-
message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION
|
|
1546
|
-
});
|
|
1547
|
-
}
|
|
1548
|
-
await setSessionCookie(
|
|
1549
|
-
ctx,
|
|
1550
|
-
{
|
|
1551
|
-
session,
|
|
1552
|
-
user: user.user
|
|
1553
|
-
},
|
|
1554
|
-
ctx.body.rememberMe === false
|
|
1555
|
-
);
|
|
1556
|
-
return ctx.json({
|
|
1557
|
-
redirect: !!ctx.body.callbackURL,
|
|
1558
|
-
token: session.token,
|
|
1559
|
-
url: ctx.body.callbackURL,
|
|
1560
|
-
user: {
|
|
1561
|
-
id: user.user.id,
|
|
1562
|
-
email: user.user.email,
|
|
1563
|
-
name: user.user.name,
|
|
1564
|
-
image: user.user.image,
|
|
1565
|
-
emailVerified: user.user.emailVerified,
|
|
1566
|
-
createdAt: user.user.createdAt,
|
|
1567
|
-
updatedAt: user.user.updatedAt
|
|
1568
|
-
}
|
|
1569
|
-
});
|
|
1570
|
-
}
|
|
1571
|
-
);
|
|
1572
|
-
var schema = z.object({
|
|
1573
|
-
code: z.string().optional(),
|
|
1574
|
-
error: z.string().optional(),
|
|
1575
|
-
device_id: z.string().optional(),
|
|
1576
|
-
error_description: z.string().optional(),
|
|
1577
|
-
state: z.string().optional()
|
|
1578
|
-
});
|
|
1579
|
-
var callbackOAuth = createAuthEndpoint(
|
|
1580
|
-
"/callback/:id",
|
|
1581
|
-
{
|
|
1582
|
-
method: ["GET", "POST"],
|
|
1583
|
-
body: schema.optional(),
|
|
1584
|
-
query: schema.optional(),
|
|
1585
|
-
metadata: HIDE_METADATA
|
|
1586
|
-
},
|
|
1587
|
-
async (c) => {
|
|
1588
|
-
let queryOrBody;
|
|
1589
|
-
try {
|
|
1590
|
-
if (c.method === "GET") {
|
|
1591
|
-
queryOrBody = schema.parse(c.query);
|
|
1592
|
-
} else if (c.method === "POST") {
|
|
1593
|
-
queryOrBody = schema.parse(c.body);
|
|
1594
|
-
} else {
|
|
1595
|
-
throw new Error("Unsupported method");
|
|
1596
|
-
}
|
|
1597
|
-
} catch (e) {
|
|
1598
|
-
c.context.logger.error("INVALID_CALLBACK_REQUEST", e);
|
|
1599
|
-
throw c.redirect(
|
|
1600
|
-
`${c.context.baseURL}/error?error=invalid_callback_request`
|
|
1601
|
-
);
|
|
1602
|
-
}
|
|
1603
|
-
const { code, error: error2, state, error_description, device_id } = queryOrBody;
|
|
1604
|
-
if (!state) {
|
|
1605
|
-
c.context.logger.error("State not found", error2);
|
|
1606
|
-
throw c.redirect(`${c.context.baseURL}/error?error=state_not_found`);
|
|
1607
|
-
}
|
|
1608
|
-
if (!code) {
|
|
1609
|
-
c.context.logger.error("Code not found");
|
|
1610
|
-
throw c.redirect(
|
|
1611
|
-
`${c.context.baseURL}/error?error=${error2 || "no_code"}&error_description=${error_description}`
|
|
1612
|
-
);
|
|
1613
|
-
}
|
|
1614
|
-
const provider = c.context.socialProviders.find(
|
|
1615
|
-
(p) => p.id === c.params.id
|
|
1616
|
-
);
|
|
1617
|
-
if (!provider) {
|
|
1618
|
-
c.context.logger.error(
|
|
1619
|
-
"Oauth provider with id",
|
|
1620
|
-
c.params.id,
|
|
1621
|
-
"not found"
|
|
1622
|
-
);
|
|
1623
|
-
throw c.redirect(
|
|
1624
|
-
`${c.context.baseURL}/error?error=oauth_provider_not_found`
|
|
1625
|
-
);
|
|
1626
|
-
}
|
|
1627
|
-
const { codeVerifier, callbackURL, link, errorURL, newUserURL } = await parseState(c);
|
|
1628
|
-
let tokens;
|
|
1629
|
-
try {
|
|
1630
|
-
tokens = await provider.validateAuthorizationCode({
|
|
1631
|
-
code,
|
|
1632
|
-
codeVerifier,
|
|
1633
|
-
deviceId: device_id,
|
|
1634
|
-
redirectURI: `${c.context.baseURL}/callback/${provider.id}`
|
|
1635
|
-
});
|
|
1636
|
-
} catch (e) {
|
|
1637
|
-
c.context.logger.error("", e);
|
|
1638
|
-
throw c.redirect(
|
|
1639
|
-
`${c.context.baseURL}/error?error=please_restart_the_process`
|
|
1640
|
-
);
|
|
1641
|
-
}
|
|
1642
|
-
const userInfo = await provider.getUserInfo(tokens).then((res) => res?.user);
|
|
1643
|
-
function redirectOnError(error3) {
|
|
1644
|
-
let url = errorURL || callbackURL || `${c.context.baseURL}/error`;
|
|
1645
|
-
if (url.includes("?")) {
|
|
1646
|
-
url = `${url}&error=${error3}`;
|
|
1647
|
-
} else {
|
|
1648
|
-
url = `${url}?error=${error3}`;
|
|
1649
|
-
}
|
|
1650
|
-
throw c.redirect(url);
|
|
1651
|
-
}
|
|
1652
|
-
if (!userInfo) {
|
|
1653
|
-
c.context.logger.error("Unable to get user info");
|
|
1654
|
-
return redirectOnError("unable_to_get_user_info");
|
|
1655
|
-
}
|
|
1656
|
-
if (!userInfo.email) {
|
|
1657
|
-
c.context.logger.error(
|
|
1658
|
-
"Provider did not return email. This could be due to misconfiguration in the provider settings."
|
|
1659
|
-
);
|
|
1660
|
-
return redirectOnError("email_not_found");
|
|
1661
|
-
}
|
|
1662
|
-
if (!callbackURL) {
|
|
1663
|
-
c.context.logger.error("No callback URL found");
|
|
1664
|
-
throw c.redirect(
|
|
1665
|
-
`${c.context.baseURL}/error?error=please_restart_the_process`
|
|
1666
|
-
);
|
|
1667
|
-
}
|
|
1668
|
-
if (link) {
|
|
1669
|
-
if (c.context.options.account?.accountLinking?.allowDifferentEmails !== true && link.email !== userInfo.email.toLowerCase()) {
|
|
1670
|
-
return redirectOnError("email_doesn't_match");
|
|
1671
|
-
}
|
|
1672
|
-
const existingAccount = await c.context.internalAdapter.findAccount(
|
|
1673
|
-
userInfo.id
|
|
1674
|
-
);
|
|
1675
|
-
if (existingAccount) {
|
|
1676
|
-
if (existingAccount && existingAccount.userId !== link.userId) {
|
|
1677
|
-
return redirectOnError("account_already_linked_to_different_user");
|
|
1678
|
-
}
|
|
1679
|
-
return redirectOnError("account_already_linked");
|
|
1680
|
-
}
|
|
1681
|
-
const newAccount = await c.context.internalAdapter.createAccount(
|
|
1682
|
-
{
|
|
1683
|
-
userId: link.userId,
|
|
1684
|
-
providerId: provider.id,
|
|
1685
|
-
accountId: userInfo.id,
|
|
1686
|
-
...tokens,
|
|
1687
|
-
scope: tokens.scopes?.join(",")
|
|
1688
|
-
},
|
|
1689
|
-
c
|
|
1690
|
-
);
|
|
1691
|
-
if (!newAccount) {
|
|
1692
|
-
return redirectOnError("unable_to_link_account");
|
|
1693
|
-
}
|
|
1694
|
-
let toRedirectTo2;
|
|
1695
|
-
try {
|
|
1696
|
-
const url = callbackURL;
|
|
1697
|
-
toRedirectTo2 = url.toString();
|
|
1698
|
-
} catch {
|
|
1699
|
-
toRedirectTo2 = callbackURL;
|
|
1700
|
-
}
|
|
1701
|
-
throw c.redirect(toRedirectTo2);
|
|
1702
|
-
}
|
|
1703
|
-
const result = await handleOAuthUserInfo(c, {
|
|
1704
|
-
userInfo: {
|
|
1705
|
-
...userInfo,
|
|
1706
|
-
email: userInfo.email,
|
|
1707
|
-
name: userInfo.name || userInfo.email
|
|
1708
|
-
},
|
|
1709
|
-
account: {
|
|
1710
|
-
providerId: provider.id,
|
|
1711
|
-
accountId: userInfo.id,
|
|
1712
|
-
...tokens,
|
|
1713
|
-
scope: tokens.scopes?.join(",")
|
|
1714
|
-
},
|
|
1715
|
-
callbackURL
|
|
1716
|
-
});
|
|
1717
|
-
if (result.error) {
|
|
1718
|
-
c.context.logger.error(result.error.split(" ").join("_"));
|
|
1719
|
-
return redirectOnError(result.error.split(" ").join("_"));
|
|
1720
|
-
}
|
|
1721
|
-
const { session, user } = result.data;
|
|
1722
|
-
await setSessionCookie(c, {
|
|
1723
|
-
session,
|
|
1724
|
-
user
|
|
1725
|
-
});
|
|
1726
|
-
let toRedirectTo;
|
|
1727
|
-
try {
|
|
1728
|
-
const url = result.isRegister ? newUserURL || callbackURL : callbackURL;
|
|
1729
|
-
toRedirectTo = url.toString();
|
|
1730
|
-
} catch {
|
|
1731
|
-
toRedirectTo = result.isRegister ? newUserURL || callbackURL : callbackURL;
|
|
1732
|
-
}
|
|
1733
|
-
throw c.redirect(toRedirectTo);
|
|
1734
|
-
}
|
|
1735
|
-
);
|
|
1736
|
-
var signOut = createAuthEndpoint(
|
|
1737
|
-
"/sign-out",
|
|
1738
|
-
{
|
|
1739
|
-
method: "POST",
|
|
1740
|
-
requireHeaders: true,
|
|
1741
|
-
metadata: {
|
|
1742
|
-
openapi: {
|
|
1743
|
-
description: "Sign out the current user",
|
|
1744
|
-
responses: {
|
|
1745
|
-
"200": {
|
|
1746
|
-
description: "Success",
|
|
1747
|
-
content: {
|
|
1748
|
-
"application/json": {
|
|
1749
|
-
schema: {
|
|
1750
|
-
type: "object",
|
|
1751
|
-
properties: {
|
|
1752
|
-
success: {
|
|
1753
|
-
type: "boolean"
|
|
1754
|
-
}
|
|
1755
|
-
}
|
|
1756
|
-
}
|
|
1757
|
-
}
|
|
1758
|
-
}
|
|
1759
|
-
}
|
|
1760
|
-
}
|
|
1761
|
-
}
|
|
1762
|
-
}
|
|
1763
|
-
},
|
|
1764
|
-
async (ctx) => {
|
|
1765
|
-
const sessionCookieToken = await ctx.getSignedCookie(
|
|
1766
|
-
ctx.context.authCookies.sessionToken.name,
|
|
1767
|
-
ctx.context.secret
|
|
1768
|
-
);
|
|
1769
|
-
if (!sessionCookieToken) {
|
|
1770
|
-
deleteSessionCookie(ctx);
|
|
1771
|
-
throw new APIError("BAD_REQUEST", {
|
|
1772
|
-
message: BASE_ERROR_CODES.FAILED_TO_GET_SESSION
|
|
1773
|
-
});
|
|
1774
|
-
}
|
|
1775
|
-
await ctx.context.internalAdapter.deleteSession(sessionCookieToken);
|
|
1776
|
-
deleteSessionCookie(ctx);
|
|
1777
|
-
return ctx.json({
|
|
1778
|
-
success: true
|
|
1779
|
-
});
|
|
1780
|
-
}
|
|
1781
|
-
);
|
|
1782
|
-
function redirectError(ctx, callbackURL, query) {
|
|
1783
|
-
const url = callbackURL ? new URL(callbackURL, ctx.baseURL) : new URL(`${ctx.baseURL}/error`);
|
|
1784
|
-
if (query)
|
|
1785
|
-
Object.entries(query).forEach(([k, v]) => url.searchParams.set(k, v));
|
|
1786
|
-
return url.href;
|
|
1787
|
-
}
|
|
1788
|
-
function redirectCallback(ctx, callbackURL, query) {
|
|
1789
|
-
const url = new URL(callbackURL, ctx.baseURL);
|
|
1790
|
-
Object.entries(query).forEach(([k, v]) => url.searchParams.set(k, v));
|
|
1791
|
-
return url.href;
|
|
1792
|
-
}
|
|
1793
|
-
var forgetPassword = createAuthEndpoint(
|
|
1794
|
-
"/forget-password",
|
|
1795
|
-
{
|
|
1796
|
-
method: "POST",
|
|
1797
|
-
body: z.object({
|
|
1798
|
-
/**
|
|
1799
|
-
* The email address of the user to send a password reset email to.
|
|
1800
|
-
*/
|
|
1801
|
-
email: z.string({
|
|
1802
|
-
description: "The email address of the user to send a password reset email to"
|
|
1803
|
-
}).email(),
|
|
1804
|
-
/**
|
|
1805
|
-
* The URL to redirect the user to reset their password.
|
|
1806
|
-
* If the token isn't valid or expired, it'll be redirected with a query parameter `?
|
|
1807
|
-
* error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?
|
|
1808
|
-
* token=VALID_TOKEN
|
|
1809
|
-
*/
|
|
1810
|
-
redirectTo: z.string({
|
|
1811
|
-
description: "The URL to redirect the user to reset their password. If the token isn't valid or expired, it'll be redirected with a query parameter `?error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?token=VALID_TOKEN"
|
|
1812
|
-
}).optional()
|
|
1813
|
-
}),
|
|
1814
|
-
metadata: {
|
|
1815
|
-
openapi: {
|
|
1816
|
-
description: "Send a password reset email to the user",
|
|
1817
|
-
responses: {
|
|
1818
|
-
"200": {
|
|
1819
|
-
description: "Success",
|
|
1820
|
-
content: {
|
|
1821
|
-
"application/json": {
|
|
1822
|
-
schema: {
|
|
1823
|
-
type: "object",
|
|
1824
|
-
properties: {
|
|
1825
|
-
status: {
|
|
1826
|
-
type: "boolean"
|
|
1827
|
-
}
|
|
1828
|
-
}
|
|
1829
|
-
}
|
|
1830
|
-
}
|
|
1831
|
-
}
|
|
1832
|
-
}
|
|
1833
|
-
}
|
|
1834
|
-
}
|
|
1835
|
-
}
|
|
1836
|
-
},
|
|
1837
|
-
async (ctx) => {
|
|
1838
|
-
if (!ctx.context.options.emailAndPassword?.sendResetPassword) {
|
|
1839
|
-
ctx.context.logger.error(
|
|
1840
|
-
"Reset password isn't enabled.Please pass an emailAndPassword.sendResetPasswordToken function in your auth config!"
|
|
1841
|
-
);
|
|
1842
|
-
throw new APIError("BAD_REQUEST", {
|
|
1843
|
-
message: "Reset password isn't enabled"
|
|
1844
|
-
});
|
|
1845
|
-
}
|
|
1846
|
-
const { email, redirectTo } = ctx.body;
|
|
1847
|
-
const user = await ctx.context.internalAdapter.findUserByEmail(email, {
|
|
1848
|
-
includeAccounts: true
|
|
1849
|
-
});
|
|
1850
|
-
if (!user) {
|
|
1851
|
-
ctx.context.logger.error("Reset Password: User not found", { email });
|
|
1852
|
-
return ctx.json({
|
|
1853
|
-
status: true
|
|
1854
|
-
});
|
|
1855
|
-
}
|
|
1856
|
-
const defaultExpiresIn = 60 * 60 * 1;
|
|
1857
|
-
const expiresAt = getDate(
|
|
1858
|
-
ctx.context.options.emailAndPassword.resetPasswordTokenExpiresIn || defaultExpiresIn,
|
|
1859
|
-
"sec"
|
|
1860
|
-
);
|
|
1861
|
-
const verificationToken = generateId(24);
|
|
1862
|
-
await ctx.context.internalAdapter.createVerificationValue({
|
|
1863
|
-
value: user.user.id.toString(),
|
|
1864
|
-
identifier: `reset-password:${verificationToken}`,
|
|
1865
|
-
expiresAt
|
|
1866
|
-
});
|
|
1867
|
-
const url = `${ctx.context.baseURL}/reset-password/${verificationToken}?callbackURL=${redirectTo}`;
|
|
1868
|
-
await ctx.context.options.emailAndPassword.sendResetPassword(
|
|
1869
|
-
{
|
|
1870
|
-
user: user.user,
|
|
1871
|
-
url,
|
|
1872
|
-
token: verificationToken
|
|
1873
|
-
},
|
|
1874
|
-
ctx.request
|
|
1875
|
-
);
|
|
1876
|
-
return ctx.json({
|
|
1877
|
-
status: true
|
|
1878
|
-
});
|
|
1879
|
-
}
|
|
1880
|
-
);
|
|
1881
|
-
var forgetPasswordCallback = createAuthEndpoint(
|
|
1882
|
-
"/reset-password/:token",
|
|
1883
|
-
{
|
|
1884
|
-
method: "GET",
|
|
1885
|
-
query: z.object({
|
|
1886
|
-
callbackURL: z.string({
|
|
1887
|
-
description: "The URL to redirect the user to reset their password"
|
|
1888
|
-
})
|
|
1889
|
-
}),
|
|
1890
|
-
use: [originCheck((ctx) => ctx.query.callbackURL)],
|
|
1891
|
-
metadata: {
|
|
1892
|
-
openapi: {
|
|
1893
|
-
description: "Redirects the user to the callback URL with the token",
|
|
1894
|
-
responses: {
|
|
1895
|
-
"200": {
|
|
1896
|
-
description: "Success",
|
|
1897
|
-
content: {
|
|
1898
|
-
"application/json": {
|
|
1899
|
-
schema: {
|
|
1900
|
-
type: "object",
|
|
1901
|
-
properties: {
|
|
1902
|
-
token: {
|
|
1903
|
-
type: "string"
|
|
1904
|
-
}
|
|
1905
|
-
}
|
|
1906
|
-
}
|
|
1907
|
-
}
|
|
1908
|
-
}
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
}
|
|
1913
|
-
},
|
|
1914
|
-
async (ctx) => {
|
|
1915
|
-
const { token } = ctx.params;
|
|
1916
|
-
const { callbackURL } = ctx.query;
|
|
1917
|
-
if (!token || !callbackURL) {
|
|
1918
|
-
throw ctx.redirect(
|
|
1919
|
-
redirectError(ctx.context, callbackURL, { error: "INVALID_TOKEN" })
|
|
1920
|
-
);
|
|
1921
|
-
}
|
|
1922
|
-
const verification = await ctx.context.internalAdapter.findVerificationValue(
|
|
1923
|
-
`reset-password:${token}`
|
|
1924
|
-
);
|
|
1925
|
-
if (!verification || verification.expiresAt < /* @__PURE__ */ new Date()) {
|
|
1926
|
-
throw ctx.redirect(
|
|
1927
|
-
redirectError(ctx.context, callbackURL, { error: "INVALID_TOKEN" })
|
|
1928
|
-
);
|
|
1929
|
-
}
|
|
1930
|
-
throw ctx.redirect(redirectCallback(ctx.context, callbackURL, { token }));
|
|
1931
|
-
}
|
|
1932
|
-
);
|
|
1933
|
-
var resetPassword = createAuthEndpoint(
|
|
1934
|
-
"/reset-password",
|
|
1935
|
-
{
|
|
1936
|
-
method: "POST",
|
|
1937
|
-
query: z.object({
|
|
1938
|
-
token: z.string().optional()
|
|
1939
|
-
}).optional(),
|
|
1940
|
-
body: z.object({
|
|
1941
|
-
newPassword: z.string({
|
|
1942
|
-
description: "The new password to set"
|
|
1943
|
-
}),
|
|
1944
|
-
token: z.string({
|
|
1945
|
-
description: "The token to reset the password"
|
|
1946
|
-
}).optional()
|
|
1947
|
-
}),
|
|
1948
|
-
metadata: {
|
|
1949
|
-
openapi: {
|
|
1950
|
-
description: "Reset the password for a user",
|
|
1951
|
-
responses: {
|
|
1952
|
-
"200": {
|
|
1953
|
-
description: "Success",
|
|
1954
|
-
content: {
|
|
1955
|
-
"application/json": {
|
|
1956
|
-
schema: {
|
|
1957
|
-
type: "object",
|
|
1958
|
-
properties: {
|
|
1959
|
-
status: {
|
|
1960
|
-
type: "boolean"
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
}
|
|
1964
|
-
}
|
|
1965
|
-
}
|
|
1966
|
-
}
|
|
1967
|
-
}
|
|
1968
|
-
}
|
|
1969
|
-
}
|
|
1970
|
-
},
|
|
1971
|
-
async (ctx) => {
|
|
1972
|
-
const token = ctx.body.token || ctx.query?.token;
|
|
1973
|
-
if (!token) {
|
|
1974
|
-
throw new APIError("BAD_REQUEST", {
|
|
1975
|
-
message: BASE_ERROR_CODES.INVALID_TOKEN
|
|
1976
|
-
});
|
|
1977
|
-
}
|
|
1978
|
-
const { newPassword } = ctx.body;
|
|
1979
|
-
const minLength = ctx.context.password?.config.minPasswordLength;
|
|
1980
|
-
const maxLength = ctx.context.password?.config.maxPasswordLength;
|
|
1981
|
-
if (newPassword.length < minLength) {
|
|
1982
|
-
throw new APIError("BAD_REQUEST", {
|
|
1983
|
-
message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT
|
|
1984
|
-
});
|
|
1985
|
-
}
|
|
1986
|
-
if (newPassword.length > maxLength) {
|
|
1987
|
-
throw new APIError("BAD_REQUEST", {
|
|
1988
|
-
message: BASE_ERROR_CODES.PASSWORD_TOO_LONG
|
|
1989
|
-
});
|
|
1990
|
-
}
|
|
1991
|
-
const id = `reset-password:${token}`;
|
|
1992
|
-
const verification = await ctx.context.internalAdapter.findVerificationValue(id);
|
|
1993
|
-
if (!verification || verification.expiresAt < /* @__PURE__ */ new Date()) {
|
|
1994
|
-
throw new APIError("BAD_REQUEST", {
|
|
1995
|
-
message: BASE_ERROR_CODES.INVALID_TOKEN
|
|
1996
|
-
});
|
|
1997
|
-
}
|
|
1998
|
-
await ctx.context.internalAdapter.deleteVerificationValue(verification.id);
|
|
1999
|
-
const userId = verification.value;
|
|
2000
|
-
const hashedPassword = await ctx.context.password.hash(newPassword);
|
|
2001
|
-
const accounts = await ctx.context.internalAdapter.findAccounts(userId);
|
|
2002
|
-
const account = accounts.find((ac) => ac.providerId === "credential");
|
|
2003
|
-
if (!account) {
|
|
2004
|
-
await ctx.context.internalAdapter.createAccount(
|
|
2005
|
-
{
|
|
2006
|
-
userId,
|
|
2007
|
-
providerId: "credential",
|
|
2008
|
-
password: hashedPassword,
|
|
2009
|
-
accountId: userId
|
|
2010
|
-
},
|
|
2011
|
-
ctx
|
|
2012
|
-
);
|
|
2013
|
-
return ctx.json({
|
|
2014
|
-
status: true
|
|
2015
|
-
});
|
|
2016
|
-
}
|
|
2017
|
-
await ctx.context.internalAdapter.updatePassword(
|
|
2018
|
-
userId,
|
|
2019
|
-
hashedPassword,
|
|
2020
|
-
ctx
|
|
2021
|
-
);
|
|
2022
|
-
return ctx.json({
|
|
2023
|
-
status: true
|
|
2024
|
-
});
|
|
2025
|
-
}
|
|
2026
|
-
);
|
|
2027
|
-
var updateUser = () => createAuthEndpoint(
|
|
2028
|
-
"/update-user",
|
|
2029
|
-
{
|
|
2030
|
-
method: "POST",
|
|
2031
|
-
body: z.record(z.string(), z.any()),
|
|
2032
|
-
use: [sessionMiddleware],
|
|
2033
|
-
metadata: {
|
|
2034
|
-
$Infer: {
|
|
2035
|
-
body: {}
|
|
2036
|
-
},
|
|
2037
|
-
openapi: {
|
|
2038
|
-
description: "Update the current user",
|
|
2039
|
-
requestBody: {
|
|
2040
|
-
content: {
|
|
2041
|
-
"application/json": {
|
|
2042
|
-
schema: {
|
|
2043
|
-
type: "object",
|
|
2044
|
-
properties: {
|
|
2045
|
-
name: {
|
|
2046
|
-
type: "string",
|
|
2047
|
-
description: "The name of the user"
|
|
2048
|
-
},
|
|
2049
|
-
image: {
|
|
2050
|
-
type: "string",
|
|
2051
|
-
description: "The image of the user"
|
|
2052
|
-
}
|
|
2053
|
-
}
|
|
2054
|
-
}
|
|
2055
|
-
}
|
|
2056
|
-
}
|
|
2057
|
-
},
|
|
2058
|
-
responses: {
|
|
2059
|
-
"200": {
|
|
2060
|
-
description: "Success",
|
|
2061
|
-
content: {
|
|
2062
|
-
"application/json": {
|
|
2063
|
-
schema: {
|
|
2064
|
-
type: "object",
|
|
2065
|
-
properties: {
|
|
2066
|
-
user: {
|
|
2067
|
-
type: "object"
|
|
2068
|
-
}
|
|
2069
|
-
}
|
|
2070
|
-
}
|
|
2071
|
-
}
|
|
2072
|
-
}
|
|
2073
|
-
}
|
|
2074
|
-
}
|
|
2075
|
-
}
|
|
2076
|
-
}
|
|
2077
|
-
},
|
|
2078
|
-
async (ctx) => {
|
|
2079
|
-
const body = ctx.body;
|
|
2080
|
-
if (body.email) {
|
|
2081
|
-
throw new APIError("BAD_REQUEST", {
|
|
2082
|
-
message: BASE_ERROR_CODES.EMAIL_CAN_NOT_BE_UPDATED
|
|
2083
|
-
});
|
|
2084
|
-
}
|
|
2085
|
-
const { name, image, ...rest } = body;
|
|
2086
|
-
const session = ctx.context.session;
|
|
2087
|
-
if (image === undefined && name === undefined && Object.keys(rest).length === 0) {
|
|
2088
|
-
return ctx.json({
|
|
2089
|
-
status: true
|
|
2090
|
-
});
|
|
2091
|
-
}
|
|
2092
|
-
const additionalFields = parseUserInput(
|
|
2093
|
-
ctx.context.options,
|
|
2094
|
-
rest,
|
|
2095
|
-
"update"
|
|
2096
|
-
);
|
|
2097
|
-
const user = await ctx.context.internalAdapter.updateUser(
|
|
2098
|
-
session.user.id,
|
|
2099
|
-
{
|
|
2100
|
-
name,
|
|
2101
|
-
image,
|
|
2102
|
-
...additionalFields
|
|
2103
|
-
},
|
|
2104
|
-
ctx
|
|
2105
|
-
);
|
|
2106
|
-
await setSessionCookie(ctx, {
|
|
2107
|
-
session: session.session,
|
|
2108
|
-
user
|
|
2109
|
-
});
|
|
2110
|
-
return ctx.json({
|
|
2111
|
-
status: true
|
|
2112
|
-
});
|
|
2113
|
-
}
|
|
2114
|
-
);
|
|
2115
|
-
var changePassword = createAuthEndpoint(
|
|
2116
|
-
"/change-password",
|
|
2117
|
-
{
|
|
2118
|
-
method: "POST",
|
|
2119
|
-
body: z.object({
|
|
2120
|
-
/**
|
|
2121
|
-
* The new password to set
|
|
2122
|
-
*/
|
|
2123
|
-
newPassword: z.string({
|
|
2124
|
-
description: "The new password to set"
|
|
2125
|
-
}),
|
|
2126
|
-
/**
|
|
2127
|
-
* The current password of the user
|
|
2128
|
-
*/
|
|
2129
|
-
currentPassword: z.string({
|
|
2130
|
-
description: "The current password"
|
|
2131
|
-
}),
|
|
2132
|
-
/**
|
|
2133
|
-
* revoke all sessions that are not the
|
|
2134
|
-
* current one logged in by the user
|
|
2135
|
-
*/
|
|
2136
|
-
revokeOtherSessions: z.boolean({
|
|
2137
|
-
description: "Revoke all other sessions"
|
|
2138
|
-
}).optional()
|
|
2139
|
-
}),
|
|
2140
|
-
use: [sessionMiddleware],
|
|
2141
|
-
metadata: {
|
|
2142
|
-
openapi: {
|
|
2143
|
-
description: "Change the password of the user",
|
|
2144
|
-
responses: {
|
|
2145
|
-
"200": {
|
|
2146
|
-
description: "Success",
|
|
2147
|
-
content: {
|
|
2148
|
-
"application/json": {
|
|
2149
|
-
schema: {
|
|
2150
|
-
type: "object",
|
|
2151
|
-
properties: {
|
|
2152
|
-
user: {
|
|
2153
|
-
description: "The user object",
|
|
2154
|
-
$ref: "#/components/schemas/User"
|
|
2155
|
-
}
|
|
2156
|
-
}
|
|
2157
|
-
}
|
|
2158
|
-
}
|
|
2159
|
-
}
|
|
2160
|
-
}
|
|
2161
|
-
}
|
|
2162
|
-
}
|
|
2163
|
-
}
|
|
2164
|
-
},
|
|
2165
|
-
async (ctx) => {
|
|
2166
|
-
const { newPassword, currentPassword, revokeOtherSessions: revokeOtherSessions2 } = ctx.body;
|
|
2167
|
-
const session = ctx.context.session;
|
|
2168
|
-
const minPasswordLength = ctx.context.password.config.minPasswordLength;
|
|
2169
|
-
if (newPassword.length < minPasswordLength) {
|
|
2170
|
-
ctx.context.logger.error("Password is too short");
|
|
2171
|
-
throw new APIError("BAD_REQUEST", {
|
|
2172
|
-
message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT
|
|
2173
|
-
});
|
|
2174
|
-
}
|
|
2175
|
-
const maxPasswordLength = ctx.context.password.config.maxPasswordLength;
|
|
2176
|
-
if (newPassword.length > maxPasswordLength) {
|
|
2177
|
-
ctx.context.logger.error("Password is too long");
|
|
2178
|
-
throw new APIError("BAD_REQUEST", {
|
|
2179
|
-
message: BASE_ERROR_CODES.PASSWORD_TOO_LONG
|
|
2180
|
-
});
|
|
2181
|
-
}
|
|
2182
|
-
const accounts = await ctx.context.internalAdapter.findAccounts(
|
|
2183
|
-
session.user.id
|
|
2184
|
-
);
|
|
2185
|
-
const account = accounts.find(
|
|
2186
|
-
(account2) => account2.providerId === "credential" && account2.password
|
|
2187
|
-
);
|
|
2188
|
-
if (!account || !account.password) {
|
|
2189
|
-
throw new APIError("BAD_REQUEST", {
|
|
2190
|
-
message: BASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND
|
|
2191
|
-
});
|
|
2192
|
-
}
|
|
2193
|
-
const passwordHash = await ctx.context.password.hash(newPassword);
|
|
2194
|
-
const verify = await ctx.context.password.verify({
|
|
2195
|
-
hash: account.password,
|
|
2196
|
-
password: currentPassword
|
|
2197
|
-
});
|
|
2198
|
-
if (!verify) {
|
|
2199
|
-
throw new APIError("BAD_REQUEST", {
|
|
2200
|
-
message: BASE_ERROR_CODES.INVALID_PASSWORD
|
|
2201
|
-
});
|
|
2202
|
-
}
|
|
2203
|
-
await ctx.context.internalAdapter.updateAccount(account.id, {
|
|
2204
|
-
password: passwordHash
|
|
2205
|
-
});
|
|
2206
|
-
let token = null;
|
|
2207
|
-
if (revokeOtherSessions2) {
|
|
2208
|
-
await ctx.context.internalAdapter.deleteSessions(session.user.id);
|
|
2209
|
-
const newSession = await ctx.context.internalAdapter.createSession(
|
|
2210
|
-
session.user.id,
|
|
2211
|
-
ctx.headers
|
|
2212
|
-
);
|
|
2213
|
-
if (!newSession) {
|
|
2214
|
-
throw new APIError("INTERNAL_SERVER_ERROR", {
|
|
2215
|
-
message: BASE_ERROR_CODES.FAILED_TO_GET_SESSION
|
|
2216
|
-
});
|
|
2217
|
-
}
|
|
2218
|
-
await setSessionCookie(ctx, {
|
|
2219
|
-
session: newSession,
|
|
2220
|
-
user: session.user
|
|
2221
|
-
});
|
|
2222
|
-
token = newSession.token;
|
|
2223
|
-
}
|
|
2224
|
-
return ctx.json({
|
|
2225
|
-
token,
|
|
2226
|
-
user: {
|
|
2227
|
-
id: session.user.id,
|
|
2228
|
-
email: session.user.email,
|
|
2229
|
-
name: session.user.name,
|
|
2230
|
-
image: session.user.image,
|
|
2231
|
-
emailVerified: session.user.emailVerified,
|
|
2232
|
-
createdAt: session.user.createdAt,
|
|
2233
|
-
updatedAt: session.user.updatedAt
|
|
2234
|
-
}
|
|
2235
|
-
});
|
|
2236
|
-
}
|
|
2237
|
-
);
|
|
2238
|
-
var setPassword = createAuthEndpoint(
|
|
2239
|
-
"/set-password",
|
|
2240
|
-
{
|
|
2241
|
-
method: "POST",
|
|
2242
|
-
body: z.object({
|
|
2243
|
-
/**
|
|
2244
|
-
* The new password to set
|
|
2245
|
-
*/
|
|
2246
|
-
newPassword: z.string()
|
|
2247
|
-
}),
|
|
2248
|
-
metadata: {
|
|
2249
|
-
SERVER_ONLY: true
|
|
2250
|
-
},
|
|
2251
|
-
use: [sessionMiddleware]
|
|
2252
|
-
},
|
|
2253
|
-
async (ctx) => {
|
|
2254
|
-
const { newPassword } = ctx.body;
|
|
2255
|
-
const session = ctx.context.session;
|
|
2256
|
-
const minPasswordLength = ctx.context.password.config.minPasswordLength;
|
|
2257
|
-
if (newPassword.length < minPasswordLength) {
|
|
2258
|
-
ctx.context.logger.error("Password is too short");
|
|
2259
|
-
throw new APIError("BAD_REQUEST", {
|
|
2260
|
-
message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT
|
|
2261
|
-
});
|
|
2262
|
-
}
|
|
2263
|
-
const maxPasswordLength = ctx.context.password.config.maxPasswordLength;
|
|
2264
|
-
if (newPassword.length > maxPasswordLength) {
|
|
2265
|
-
ctx.context.logger.error("Password is too long");
|
|
2266
|
-
throw new APIError("BAD_REQUEST", {
|
|
2267
|
-
message: BASE_ERROR_CODES.PASSWORD_TOO_LONG
|
|
2268
|
-
});
|
|
2269
|
-
}
|
|
2270
|
-
const accounts = await ctx.context.internalAdapter.findAccounts(
|
|
2271
|
-
session.user.id
|
|
2272
|
-
);
|
|
2273
|
-
const account = accounts.find(
|
|
2274
|
-
(account2) => account2.providerId === "credential" && account2.password
|
|
2275
|
-
);
|
|
2276
|
-
const passwordHash = await ctx.context.password.hash(newPassword);
|
|
2277
|
-
if (!account) {
|
|
2278
|
-
await ctx.context.internalAdapter.linkAccount(
|
|
2279
|
-
{
|
|
2280
|
-
userId: session.user.id,
|
|
2281
|
-
providerId: "credential",
|
|
2282
|
-
accountId: session.user.id,
|
|
2283
|
-
password: passwordHash
|
|
2284
|
-
},
|
|
2285
|
-
ctx
|
|
2286
|
-
);
|
|
2287
|
-
return ctx.json({
|
|
2288
|
-
status: true
|
|
2289
|
-
});
|
|
2290
|
-
}
|
|
2291
|
-
throw new APIError("BAD_REQUEST", {
|
|
2292
|
-
message: "user already has a password"
|
|
2293
|
-
});
|
|
2294
|
-
}
|
|
2295
|
-
);
|
|
2296
|
-
var deleteUser = createAuthEndpoint(
|
|
2297
|
-
"/delete-user",
|
|
2298
|
-
{
|
|
2299
|
-
method: "POST",
|
|
2300
|
-
use: [sessionMiddleware],
|
|
2301
|
-
body: z.object({
|
|
2302
|
-
/**
|
|
2303
|
-
* The callback URL to redirect to after the user is deleted
|
|
2304
|
-
* this is only used on delete user callback
|
|
2305
|
-
*/
|
|
2306
|
-
callbackURL: z.string().optional(),
|
|
2307
|
-
/**
|
|
2308
|
-
* The password of the user. If the password isn't provided, session freshness
|
|
2309
|
-
* will be checked.
|
|
2310
|
-
*/
|
|
2311
|
-
password: z.string().optional(),
|
|
2312
|
-
/**
|
|
2313
|
-
* The token to delete the user. If the token is provided, the user will be deleted
|
|
2314
|
-
*/
|
|
2315
|
-
token: z.string().optional()
|
|
2316
|
-
}),
|
|
2317
|
-
metadata: {
|
|
2318
|
-
openapi: {
|
|
2319
|
-
description: "Delete the user",
|
|
2320
|
-
responses: {
|
|
2321
|
-
"200": {
|
|
2322
|
-
description: "Success",
|
|
2323
|
-
content: {
|
|
2324
|
-
"application/json": {
|
|
2325
|
-
schema: {
|
|
2326
|
-
type: "object"
|
|
2327
|
-
}
|
|
2328
|
-
}
|
|
2329
|
-
}
|
|
2330
|
-
}
|
|
2331
|
-
}
|
|
2332
|
-
}
|
|
2333
|
-
}
|
|
2334
|
-
},
|
|
2335
|
-
async (ctx) => {
|
|
2336
|
-
if (!ctx.context.options.user?.deleteUser?.enabled) {
|
|
2337
|
-
ctx.context.logger.error(
|
|
2338
|
-
"Delete user is disabled. Enable it in the options",
|
|
2339
|
-
{
|
|
2340
|
-
session: ctx.context.session
|
|
2341
|
-
}
|
|
2342
|
-
);
|
|
2343
|
-
throw new APIError("NOT_FOUND");
|
|
2344
|
-
}
|
|
2345
|
-
const session = ctx.context.session;
|
|
2346
|
-
if (ctx.body.password) {
|
|
2347
|
-
const accounts = await ctx.context.internalAdapter.findAccounts(
|
|
2348
|
-
session.user.id
|
|
2349
|
-
);
|
|
2350
|
-
const account = accounts.find(
|
|
2351
|
-
(account2) => account2.providerId === "credential" && account2.password
|
|
2352
|
-
);
|
|
2353
|
-
if (!account || !account.password) {
|
|
2354
|
-
throw new APIError("BAD_REQUEST", {
|
|
2355
|
-
message: BASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND
|
|
2356
|
-
});
|
|
2357
|
-
}
|
|
2358
|
-
const verify = await ctx.context.password.verify({
|
|
2359
|
-
hash: account.password,
|
|
2360
|
-
password: ctx.body.password
|
|
2361
|
-
});
|
|
2362
|
-
if (!verify) {
|
|
2363
|
-
throw new APIError("BAD_REQUEST", {
|
|
2364
|
-
message: BASE_ERROR_CODES.INVALID_PASSWORD
|
|
2365
|
-
});
|
|
2366
|
-
}
|
|
2367
|
-
} else {
|
|
2368
|
-
if (ctx.context.options.session?.freshAge) {
|
|
2369
|
-
const currentAge = session.session.createdAt.getTime();
|
|
2370
|
-
const freshAge = ctx.context.options.session.freshAge;
|
|
2371
|
-
const now = Date.now();
|
|
2372
|
-
if (now - currentAge > freshAge) {
|
|
2373
|
-
throw new APIError("BAD_REQUEST", {
|
|
2374
|
-
message: BASE_ERROR_CODES.SESSION_EXPIRED
|
|
2375
|
-
});
|
|
2376
|
-
}
|
|
2377
|
-
}
|
|
2378
|
-
}
|
|
2379
|
-
if (ctx.body.token) {
|
|
2380
|
-
await deleteUserCallback({
|
|
2381
|
-
...ctx,
|
|
2382
|
-
query: {
|
|
2383
|
-
token: ctx.body.token
|
|
2384
|
-
}
|
|
2385
|
-
});
|
|
2386
|
-
return ctx.json({
|
|
2387
|
-
success: true,
|
|
2388
|
-
message: "User deleted"
|
|
2389
|
-
});
|
|
2390
|
-
}
|
|
2391
|
-
if (ctx.context.options.user.deleteUser?.sendDeleteAccountVerification) {
|
|
2392
|
-
const token = generateRandomString(32, "0-9", "a-z");
|
|
2393
|
-
await ctx.context.internalAdapter.createVerificationValue({
|
|
2394
|
-
value: session.user.id,
|
|
2395
|
-
identifier: `delete-account-${token}`,
|
|
2396
|
-
expiresAt: new Date(Date.now() + 1e3 * 60 * 60 * 24)
|
|
2397
|
-
});
|
|
2398
|
-
const url = `${ctx.context.baseURL}/delete-user/callback?token=${token}&callbackURL=${ctx.body.callbackURL || "/"}`;
|
|
2399
|
-
await ctx.context.options.user.deleteUser.sendDeleteAccountVerification(
|
|
2400
|
-
{
|
|
2401
|
-
user: session.user,
|
|
2402
|
-
url,
|
|
2403
|
-
token
|
|
2404
|
-
},
|
|
2405
|
-
ctx.request
|
|
2406
|
-
);
|
|
2407
|
-
return ctx.json({
|
|
2408
|
-
success: true,
|
|
2409
|
-
message: "Verification email sent"
|
|
2410
|
-
});
|
|
2411
|
-
}
|
|
2412
|
-
const beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete;
|
|
2413
|
-
if (beforeDelete) {
|
|
2414
|
-
await beforeDelete(session.user, ctx.request);
|
|
2415
|
-
}
|
|
2416
|
-
await ctx.context.internalAdapter.deleteUser(session.user.id);
|
|
2417
|
-
await ctx.context.internalAdapter.deleteSessions(session.user.id);
|
|
2418
|
-
await ctx.context.internalAdapter.deleteAccounts(session.user.id);
|
|
2419
|
-
deleteSessionCookie(ctx);
|
|
2420
|
-
const afterDelete = ctx.context.options.user.deleteUser?.afterDelete;
|
|
2421
|
-
if (afterDelete) {
|
|
2422
|
-
await afterDelete(session.user, ctx.request);
|
|
2423
|
-
}
|
|
2424
|
-
return ctx.json({
|
|
2425
|
-
success: true,
|
|
2426
|
-
message: "User deleted"
|
|
2427
|
-
});
|
|
2428
|
-
}
|
|
2429
|
-
);
|
|
2430
|
-
var deleteUserCallback = createAuthEndpoint(
|
|
2431
|
-
"/delete-user/callback",
|
|
2432
|
-
{
|
|
2433
|
-
method: "GET",
|
|
2434
|
-
query: z.object({
|
|
2435
|
-
token: z.string(),
|
|
2436
|
-
callbackURL: z.string().optional()
|
|
2437
|
-
}),
|
|
2438
|
-
use: [originCheck((ctx) => ctx.query.callbackURL)]
|
|
2439
|
-
},
|
|
2440
|
-
async (ctx) => {
|
|
2441
|
-
if (!ctx.context.options.user?.deleteUser?.enabled) {
|
|
2442
|
-
ctx.context.logger.error(
|
|
2443
|
-
"Delete user is disabled. Enable it in the options"
|
|
2444
|
-
);
|
|
2445
|
-
throw new APIError("NOT_FOUND");
|
|
2446
|
-
}
|
|
2447
|
-
const session = await getSessionFromCtx(ctx);
|
|
2448
|
-
if (!session) {
|
|
2449
|
-
throw new APIError("NOT_FOUND", {
|
|
2450
|
-
message: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO
|
|
2451
|
-
});
|
|
2452
|
-
}
|
|
2453
|
-
const token = await ctx.context.internalAdapter.findVerificationValue(
|
|
2454
|
-
`delete-account-${ctx.query.token}`
|
|
2455
|
-
);
|
|
2456
|
-
if (!token || token.expiresAt < /* @__PURE__ */ new Date()) {
|
|
2457
|
-
throw new APIError("NOT_FOUND", {
|
|
2458
|
-
message: BASE_ERROR_CODES.INVALID_TOKEN
|
|
2459
|
-
});
|
|
2460
|
-
}
|
|
2461
|
-
if (token.value !== session.user.id) {
|
|
2462
|
-
throw new APIError("NOT_FOUND", {
|
|
2463
|
-
message: BASE_ERROR_CODES.INVALID_TOKEN
|
|
2464
|
-
});
|
|
2465
|
-
}
|
|
2466
|
-
const beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete;
|
|
2467
|
-
if (beforeDelete) {
|
|
2468
|
-
await beforeDelete(session.user, ctx.request);
|
|
2469
|
-
}
|
|
2470
|
-
await ctx.context.internalAdapter.deleteUser(session.user.id);
|
|
2471
|
-
await ctx.context.internalAdapter.deleteSessions(session.user.id);
|
|
2472
|
-
await ctx.context.internalAdapter.deleteAccounts(session.user.id);
|
|
2473
|
-
await ctx.context.internalAdapter.deleteVerificationValue(token.id);
|
|
2474
|
-
deleteSessionCookie(ctx);
|
|
2475
|
-
const afterDelete = ctx.context.options.user.deleteUser?.afterDelete;
|
|
2476
|
-
if (afterDelete) {
|
|
2477
|
-
await afterDelete(session.user, ctx.request);
|
|
2478
|
-
}
|
|
2479
|
-
if (ctx.query.callbackURL) {
|
|
2480
|
-
throw ctx.redirect(ctx.query.callbackURL || "/");
|
|
2481
|
-
}
|
|
2482
|
-
return ctx.json({
|
|
2483
|
-
success: true,
|
|
2484
|
-
message: "User deleted"
|
|
2485
|
-
});
|
|
2486
|
-
}
|
|
2487
|
-
);
|
|
2488
|
-
var changeEmail = createAuthEndpoint(
|
|
2489
|
-
"/change-email",
|
|
2490
|
-
{
|
|
2491
|
-
method: "POST",
|
|
2492
|
-
body: z.object({
|
|
2493
|
-
newEmail: z.string({
|
|
2494
|
-
description: "The new email to set"
|
|
2495
|
-
}).email(),
|
|
2496
|
-
callbackURL: z.string({
|
|
2497
|
-
description: "The URL to redirect to after email verification"
|
|
2498
|
-
}).optional()
|
|
2499
|
-
}),
|
|
2500
|
-
use: [sessionMiddleware],
|
|
2501
|
-
metadata: {
|
|
2502
|
-
openapi: {
|
|
2503
|
-
responses: {
|
|
2504
|
-
"200": {
|
|
2505
|
-
description: "Success",
|
|
2506
|
-
content: {
|
|
2507
|
-
"application/json": {
|
|
2508
|
-
schema: {
|
|
2509
|
-
type: "object",
|
|
2510
|
-
properties: {
|
|
2511
|
-
user: {
|
|
2512
|
-
type: "object"
|
|
2513
|
-
},
|
|
2514
|
-
status: {
|
|
2515
|
-
type: "boolean"
|
|
2516
|
-
}
|
|
2517
|
-
}
|
|
2518
|
-
}
|
|
2519
|
-
}
|
|
2520
|
-
}
|
|
2521
|
-
}
|
|
2522
|
-
}
|
|
2523
|
-
}
|
|
2524
|
-
}
|
|
2525
|
-
},
|
|
2526
|
-
async (ctx) => {
|
|
2527
|
-
if (!ctx.context.options.user?.changeEmail?.enabled) {
|
|
2528
|
-
ctx.context.logger.error("Change email is disabled.");
|
|
2529
|
-
throw new APIError("BAD_REQUEST", {
|
|
2530
|
-
message: "Change email is disabled"
|
|
2531
|
-
});
|
|
2532
|
-
}
|
|
2533
|
-
if (ctx.body.newEmail === ctx.context.session.user.email) {
|
|
2534
|
-
ctx.context.logger.error("Email is the same");
|
|
2535
|
-
throw new APIError("BAD_REQUEST", {
|
|
2536
|
-
message: "Email is the same"
|
|
2537
|
-
});
|
|
2538
|
-
}
|
|
2539
|
-
const existingUser = await ctx.context.internalAdapter.findUserByEmail(
|
|
2540
|
-
ctx.body.newEmail
|
|
2541
|
-
);
|
|
2542
|
-
if (existingUser) {
|
|
2543
|
-
ctx.context.logger.error("Email already exists");
|
|
2544
|
-
throw new APIError("BAD_REQUEST", {
|
|
2545
|
-
message: "Couldn't update your email"
|
|
2546
|
-
});
|
|
2547
|
-
}
|
|
2548
|
-
if (ctx.context.session.user.emailVerified !== true) {
|
|
2549
|
-
const existing = await ctx.context.internalAdapter.findUserByEmail(
|
|
2550
|
-
ctx.body.newEmail
|
|
2551
|
-
);
|
|
2552
|
-
if (existing) {
|
|
2553
|
-
throw new APIError("UNPROCESSABLE_ENTITY", {
|
|
2554
|
-
message: BASE_ERROR_CODES.USER_ALREADY_EXISTS
|
|
2555
|
-
});
|
|
2556
|
-
}
|
|
2557
|
-
await ctx.context.internalAdapter.updateUserByEmail(
|
|
2558
|
-
ctx.context.session.user.email,
|
|
2559
|
-
{
|
|
2560
|
-
email: ctx.body.newEmail
|
|
2561
|
-
},
|
|
2562
|
-
ctx
|
|
2563
|
-
);
|
|
2564
|
-
if (ctx.context.options.emailVerification?.sendVerificationEmail) {
|
|
2565
|
-
const token2 = await createEmailVerificationToken(
|
|
2566
|
-
ctx.context.secret,
|
|
2567
|
-
ctx.context.session.user.email,
|
|
2568
|
-
ctx.body.newEmail,
|
|
2569
|
-
ctx.context.options.emailVerification?.expiresIn
|
|
2570
|
-
);
|
|
2571
|
-
const url2 = `${ctx.context.baseURL}/verify-email?token=${token2}&callbackURL=${ctx.body.callbackURL || "/"}`;
|
|
2572
|
-
await ctx.context.options.emailVerification.sendVerificationEmail(
|
|
2573
|
-
{
|
|
2574
|
-
user: {
|
|
2575
|
-
...ctx.context.session.user,
|
|
2576
|
-
email: ctx.body.newEmail
|
|
2577
|
-
},
|
|
2578
|
-
url: url2,
|
|
2579
|
-
token: token2
|
|
2580
|
-
},
|
|
2581
|
-
ctx.request
|
|
2582
|
-
);
|
|
2583
|
-
}
|
|
2584
|
-
return ctx.json({
|
|
2585
|
-
status: true
|
|
2586
|
-
});
|
|
2587
|
-
}
|
|
2588
|
-
if (!ctx.context.options.user.changeEmail.sendChangeEmailVerification) {
|
|
2589
|
-
ctx.context.logger.error("Verification email isn't enabled.");
|
|
2590
|
-
throw new APIError("BAD_REQUEST", {
|
|
2591
|
-
message: "Verification email isn't enabled"
|
|
2592
|
-
});
|
|
2593
|
-
}
|
|
2594
|
-
const token = await createEmailVerificationToken(
|
|
2595
|
-
ctx.context.secret,
|
|
2596
|
-
ctx.context.session.user.email,
|
|
2597
|
-
ctx.body.newEmail,
|
|
2598
|
-
ctx.context.options.emailVerification?.expiresIn
|
|
2599
|
-
);
|
|
2600
|
-
const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || "/"}`;
|
|
2601
|
-
await ctx.context.options.user.changeEmail.sendChangeEmailVerification(
|
|
2602
|
-
{
|
|
2603
|
-
user: ctx.context.session.user,
|
|
2604
|
-
newEmail: ctx.body.newEmail,
|
|
2605
|
-
url,
|
|
2606
|
-
token
|
|
2607
|
-
},
|
|
2608
|
-
ctx.request
|
|
2609
|
-
);
|
|
2610
|
-
return ctx.json({
|
|
2611
|
-
status: true
|
|
2612
|
-
});
|
|
2613
|
-
}
|
|
2614
|
-
);
|
|
2615
|
-
|
|
2616
|
-
// src/api/routes/error.ts
|
|
2617
|
-
function sanitize(input) {
|
|
2618
|
-
return input.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2619
|
-
}
|
|
2620
|
-
var html = (errorCode = "Unknown") => `<!DOCTYPE html>
|
|
2621
|
-
<html lang="en">
|
|
2622
|
-
<head>
|
|
2623
|
-
<meta charset="UTF-8">
|
|
2624
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
2625
|
-
<title>Authentication Error</title>
|
|
2626
|
-
<style>
|
|
2627
|
-
:root {
|
|
2628
|
-
--bg-color: #f8f9fa;
|
|
2629
|
-
--text-color: #212529;
|
|
2630
|
-
--accent-color: #000000;
|
|
2631
|
-
--error-color: #dc3545;
|
|
2632
|
-
--border-color: #e9ecef;
|
|
2633
|
-
}
|
|
2634
|
-
body {
|
|
2635
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
2636
|
-
background-color: var(--bg-color);
|
|
2637
|
-
color: var(--text-color);
|
|
2638
|
-
display: flex;
|
|
2639
|
-
justify-content: center;
|
|
2640
|
-
align-items: center;
|
|
2641
|
-
height: 100vh;
|
|
2642
|
-
margin: 0;
|
|
2643
|
-
line-height: 1.5;
|
|
2644
|
-
}
|
|
2645
|
-
.error-container {
|
|
2646
|
-
background-color: #ffffff;
|
|
2647
|
-
border-radius: 12px;
|
|
2648
|
-
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
|
2649
|
-
padding: 2.5rem;
|
|
2650
|
-
text-align: center;
|
|
2651
|
-
max-width: 90%;
|
|
2652
|
-
width: 400px;
|
|
2653
|
-
}
|
|
2654
|
-
h1 {
|
|
2655
|
-
color: var(--error-color);
|
|
2656
|
-
font-size: 1.75rem;
|
|
2657
|
-
margin-bottom: 1rem;
|
|
2658
|
-
font-weight: 600;
|
|
2659
|
-
}
|
|
2660
|
-
p {
|
|
2661
|
-
margin-bottom: 1.5rem;
|
|
2662
|
-
color: #495057;
|
|
2663
|
-
}
|
|
2664
|
-
.btn {
|
|
2665
|
-
background-color: var(--accent-color);
|
|
2666
|
-
color: #ffffff;
|
|
2667
|
-
text-decoration: none;
|
|
2668
|
-
padding: 0.75rem 1.5rem;
|
|
2669
|
-
border-radius: 6px;
|
|
2670
|
-
transition: all 0.3s ease;
|
|
2671
|
-
display: inline-block;
|
|
2672
|
-
font-weight: 500;
|
|
2673
|
-
border: 2px solid var(--accent-color);
|
|
2674
|
-
}
|
|
2675
|
-
.btn:hover {
|
|
2676
|
-
background-color: #131721;
|
|
2677
|
-
}
|
|
2678
|
-
.error-code {
|
|
2679
|
-
font-size: 0.875rem;
|
|
2680
|
-
color: #6c757d;
|
|
2681
|
-
margin-top: 1.5rem;
|
|
2682
|
-
padding-top: 1.5rem;
|
|
2683
|
-
border-top: 1px solid var(--border-color);
|
|
2684
|
-
}
|
|
2685
|
-
.icon {
|
|
2686
|
-
font-size: 3rem;
|
|
2687
|
-
margin-bottom: 1rem;
|
|
2688
|
-
}
|
|
2689
|
-
</style>
|
|
2690
|
-
</head>
|
|
2691
|
-
<body>
|
|
2692
|
-
<div class="error-container">
|
|
2693
|
-
<div class="icon">\u26A0\uFE0F</div>
|
|
2694
|
-
<h1>Better Auth Error</h1>
|
|
2695
|
-
<p>We encountered an issue while processing your request. Please try again or contact the application owner if the problem persists.</p>
|
|
2696
|
-
<a href="/" id="returnLink" class="btn">Return to Application</a>
|
|
2697
|
-
<div class="error-code">Error Code: <span id="errorCode">${sanitize(
|
|
2698
|
-
errorCode
|
|
2699
|
-
)}</span></div>
|
|
2700
|
-
</div>
|
|
2701
|
-
</body>
|
|
2702
|
-
</html>`;
|
|
2703
|
-
var error = createAuthEndpoint(
|
|
2704
|
-
"/error",
|
|
2705
|
-
{
|
|
2706
|
-
method: "GET",
|
|
2707
|
-
metadata: {
|
|
2708
|
-
...HIDE_METADATA,
|
|
2709
|
-
openapi: {
|
|
2710
|
-
description: "Displays an error page",
|
|
2711
|
-
responses: {
|
|
2712
|
-
"200": {
|
|
2713
|
-
description: "Success",
|
|
2714
|
-
content: {
|
|
2715
|
-
"text/html": {
|
|
2716
|
-
schema: {
|
|
2717
|
-
type: "string"
|
|
2718
|
-
}
|
|
2719
|
-
}
|
|
2720
|
-
}
|
|
2721
|
-
}
|
|
2722
|
-
}
|
|
2723
|
-
}
|
|
2724
|
-
}
|
|
2725
|
-
},
|
|
2726
|
-
async (c) => {
|
|
2727
|
-
const query = new URL(c.request?.url || "").searchParams.get("error") || "Unknown";
|
|
2728
|
-
return new Response(html(query), {
|
|
2729
|
-
headers: {
|
|
2730
|
-
"Content-Type": "text/html"
|
|
2731
|
-
}
|
|
2732
|
-
});
|
|
2733
|
-
}
|
|
2734
|
-
);
|
|
2735
|
-
|
|
2736
|
-
// src/api/routes/ok.ts
|
|
2737
|
-
var ok = createAuthEndpoint(
|
|
2738
|
-
"/ok",
|
|
2739
|
-
{
|
|
2740
|
-
method: "GET",
|
|
2741
|
-
metadata: {
|
|
2742
|
-
...HIDE_METADATA,
|
|
2743
|
-
openapi: {
|
|
2744
|
-
description: "Check if the API is working",
|
|
2745
|
-
responses: {
|
|
2746
|
-
"200": {
|
|
2747
|
-
description: "Success",
|
|
2748
|
-
content: {
|
|
2749
|
-
"application/json": {
|
|
2750
|
-
schema: {
|
|
2751
|
-
type: "object",
|
|
2752
|
-
properties: {
|
|
2753
|
-
ok: {
|
|
2754
|
-
type: "boolean"
|
|
2755
|
-
}
|
|
2756
|
-
}
|
|
2757
|
-
}
|
|
2758
|
-
}
|
|
2759
|
-
}
|
|
2760
|
-
}
|
|
2761
|
-
}
|
|
2762
|
-
}
|
|
2763
|
-
}
|
|
2764
|
-
},
|
|
2765
|
-
async (ctx) => {
|
|
2766
|
-
return ctx.json({
|
|
2767
|
-
ok: true
|
|
2768
|
-
});
|
|
2769
|
-
}
|
|
2770
|
-
);
|
|
2771
|
-
var signUpEmail = () => createAuthEndpoint(
|
|
2772
|
-
"/sign-up/email",
|
|
2773
|
-
{
|
|
2774
|
-
method: "POST",
|
|
2775
|
-
body: z.record(z.string(), z.any()),
|
|
2776
|
-
metadata: {
|
|
2777
|
-
$Infer: {
|
|
2778
|
-
body: {}
|
|
2779
|
-
},
|
|
2780
|
-
openapi: {
|
|
2781
|
-
description: "Sign up a user using email and password",
|
|
2782
|
-
requestBody: {
|
|
2783
|
-
content: {
|
|
2784
|
-
"application/json": {
|
|
2785
|
-
schema: {
|
|
2786
|
-
type: "object",
|
|
2787
|
-
properties: {
|
|
2788
|
-
name: {
|
|
2789
|
-
type: "string",
|
|
2790
|
-
description: "The name of the user"
|
|
2791
|
-
},
|
|
2792
|
-
email: {
|
|
2793
|
-
type: "string",
|
|
2794
|
-
description: "The email of the user"
|
|
2795
|
-
},
|
|
2796
|
-
password: {
|
|
2797
|
-
type: "string",
|
|
2798
|
-
description: "The password of the user"
|
|
2799
|
-
},
|
|
2800
|
-
callbackURL: {
|
|
2801
|
-
type: "string",
|
|
2802
|
-
description: "The URL to use for email verification callback"
|
|
2803
|
-
}
|
|
2804
|
-
},
|
|
2805
|
-
required: ["name", "email", "password"]
|
|
2806
|
-
}
|
|
2807
|
-
}
|
|
2808
|
-
}
|
|
2809
|
-
},
|
|
2810
|
-
responses: {
|
|
2811
|
-
"200": {
|
|
2812
|
-
description: "Success",
|
|
2813
|
-
content: {
|
|
2814
|
-
"application/json": {
|
|
2815
|
-
schema: {
|
|
2816
|
-
type: "object",
|
|
2817
|
-
properties: {
|
|
2818
|
-
id: {
|
|
2819
|
-
type: "string",
|
|
2820
|
-
description: "The id of the user"
|
|
2821
|
-
},
|
|
2822
|
-
email: {
|
|
2823
|
-
type: "string",
|
|
2824
|
-
description: "The email of the user"
|
|
2825
|
-
},
|
|
2826
|
-
name: {
|
|
2827
|
-
type: "string",
|
|
2828
|
-
description: "The name of the user"
|
|
2829
|
-
},
|
|
2830
|
-
image: {
|
|
2831
|
-
type: "string",
|
|
2832
|
-
description: "The image of the user"
|
|
2833
|
-
},
|
|
2834
|
-
emailVerified: {
|
|
2835
|
-
type: "boolean",
|
|
2836
|
-
description: "If the email is verified"
|
|
2837
|
-
}
|
|
2838
|
-
}
|
|
2839
|
-
}
|
|
2840
|
-
}
|
|
2841
|
-
}
|
|
2842
|
-
}
|
|
2843
|
-
}
|
|
2844
|
-
}
|
|
2845
|
-
}
|
|
2846
|
-
},
|
|
2847
|
-
async (ctx) => {
|
|
2848
|
-
if (!ctx.context.options.emailAndPassword?.enabled) {
|
|
2849
|
-
throw new APIError("BAD_REQUEST", {
|
|
2850
|
-
message: "Email and password sign up is not enabled"
|
|
2851
|
-
});
|
|
2852
|
-
}
|
|
2853
|
-
const body = ctx.body;
|
|
2854
|
-
const { name, email, password, image, callbackURL, ...additionalFields } = body;
|
|
2855
|
-
const isValidEmail = z.string().email().safeParse(email);
|
|
2856
|
-
if (!isValidEmail.success) {
|
|
2857
|
-
throw new APIError("BAD_REQUEST", {
|
|
2858
|
-
message: BASE_ERROR_CODES.INVALID_EMAIL
|
|
2859
|
-
});
|
|
2860
|
-
}
|
|
2861
|
-
const minPasswordLength = ctx.context.password.config.minPasswordLength;
|
|
2862
|
-
if (password.length < minPasswordLength) {
|
|
2863
|
-
ctx.context.logger.error("Password is too short");
|
|
2864
|
-
throw new APIError("BAD_REQUEST", {
|
|
2865
|
-
message: BASE_ERROR_CODES.PASSWORD_TOO_SHORT
|
|
2866
|
-
});
|
|
2867
|
-
}
|
|
2868
|
-
const maxPasswordLength = ctx.context.password.config.maxPasswordLength;
|
|
2869
|
-
if (password.length > maxPasswordLength) {
|
|
2870
|
-
ctx.context.logger.error("Password is too long");
|
|
2871
|
-
throw new APIError("BAD_REQUEST", {
|
|
2872
|
-
message: BASE_ERROR_CODES.PASSWORD_TOO_LONG
|
|
2873
|
-
});
|
|
2874
|
-
}
|
|
2875
|
-
const dbUser = await ctx.context.internalAdapter.findUserByEmail(email);
|
|
2876
|
-
if (dbUser?.user) {
|
|
2877
|
-
ctx.context.logger.info(`Sign-up attempt for existing email: ${email}`);
|
|
2878
|
-
throw new APIError("UNPROCESSABLE_ENTITY", {
|
|
2879
|
-
message: BASE_ERROR_CODES.USER_ALREADY_EXISTS
|
|
2880
|
-
});
|
|
2881
|
-
}
|
|
2882
|
-
const additionalData = parseUserInput(
|
|
2883
|
-
ctx.context.options,
|
|
2884
|
-
additionalFields
|
|
2885
|
-
);
|
|
2886
|
-
let createdUser;
|
|
2887
|
-
try {
|
|
2888
|
-
createdUser = await ctx.context.internalAdapter.createUser(
|
|
2889
|
-
{
|
|
2890
|
-
email: email.toLowerCase(),
|
|
2891
|
-
name,
|
|
2892
|
-
image,
|
|
2893
|
-
...additionalData,
|
|
2894
|
-
emailVerified: false
|
|
2895
|
-
},
|
|
2896
|
-
ctx
|
|
2897
|
-
);
|
|
2898
|
-
if (!createdUser) {
|
|
2899
|
-
throw new APIError("BAD_REQUEST", {
|
|
2900
|
-
message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER
|
|
2901
|
-
});
|
|
2902
|
-
}
|
|
2903
|
-
} catch (e) {
|
|
2904
|
-
if (isDevelopment) {
|
|
2905
|
-
ctx.context.logger.error("Failed to create user", e);
|
|
2906
|
-
}
|
|
2907
|
-
throw new APIError("UNPROCESSABLE_ENTITY", {
|
|
2908
|
-
message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER,
|
|
2909
|
-
details: e
|
|
2910
|
-
});
|
|
2911
|
-
}
|
|
2912
|
-
if (!createdUser) {
|
|
2913
|
-
throw new APIError("UNPROCESSABLE_ENTITY", {
|
|
2914
|
-
message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER
|
|
2915
|
-
});
|
|
2916
|
-
}
|
|
2917
|
-
const hash = await ctx.context.password.hash(password);
|
|
2918
|
-
await ctx.context.internalAdapter.linkAccount(
|
|
2919
|
-
{
|
|
2920
|
-
userId: createdUser.id,
|
|
2921
|
-
providerId: "credential",
|
|
2922
|
-
accountId: createdUser.id,
|
|
2923
|
-
password: hash
|
|
2924
|
-
},
|
|
2925
|
-
ctx
|
|
2926
|
-
);
|
|
2927
|
-
if (ctx.context.options.emailVerification?.sendOnSignUp || ctx.context.options.emailAndPassword.requireEmailVerification) {
|
|
2928
|
-
const token = await createEmailVerificationToken(
|
|
2929
|
-
ctx.context.secret,
|
|
2930
|
-
createdUser.email,
|
|
2931
|
-
undefined,
|
|
2932
|
-
ctx.context.options.emailVerification?.expiresIn
|
|
2933
|
-
);
|
|
2934
|
-
const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${body.callbackURL || "/"}`;
|
|
2935
|
-
await ctx.context.options.emailVerification?.sendVerificationEmail?.(
|
|
2936
|
-
{
|
|
2937
|
-
user: createdUser,
|
|
2938
|
-
url,
|
|
2939
|
-
token
|
|
2940
|
-
},
|
|
2941
|
-
ctx.request
|
|
2942
|
-
);
|
|
2943
|
-
}
|
|
2944
|
-
if (ctx.context.options.emailAndPassword.autoSignIn === false || ctx.context.options.emailAndPassword.requireEmailVerification) {
|
|
2945
|
-
return ctx.json({
|
|
2946
|
-
token: null,
|
|
2947
|
-
user: {
|
|
2948
|
-
id: createdUser.id,
|
|
2949
|
-
email: createdUser.email,
|
|
2950
|
-
name: createdUser.name,
|
|
2951
|
-
image: createdUser.image,
|
|
2952
|
-
emailVerified: createdUser.emailVerified,
|
|
2953
|
-
createdAt: createdUser.createdAt,
|
|
2954
|
-
updatedAt: createdUser.updatedAt
|
|
2955
|
-
}
|
|
2956
|
-
});
|
|
2957
|
-
}
|
|
2958
|
-
const session = await ctx.context.internalAdapter.createSession(
|
|
2959
|
-
createdUser.id,
|
|
2960
|
-
ctx.request
|
|
2961
|
-
);
|
|
2962
|
-
if (!session) {
|
|
2963
|
-
throw new APIError("BAD_REQUEST", {
|
|
2964
|
-
message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION
|
|
2965
|
-
});
|
|
2966
|
-
}
|
|
2967
|
-
await setSessionCookie(ctx, {
|
|
2968
|
-
session,
|
|
2969
|
-
user: createdUser
|
|
2970
|
-
});
|
|
2971
|
-
return ctx.json({
|
|
2972
|
-
token: session.token,
|
|
2973
|
-
user: {
|
|
2974
|
-
id: createdUser.id,
|
|
2975
|
-
email: createdUser.email,
|
|
2976
|
-
name: createdUser.name,
|
|
2977
|
-
image: createdUser.image,
|
|
2978
|
-
emailVerified: createdUser.emailVerified,
|
|
2979
|
-
createdAt: createdUser.createdAt,
|
|
2980
|
-
updatedAt: createdUser.updatedAt
|
|
2981
|
-
}
|
|
2982
|
-
});
|
|
2983
|
-
}
|
|
2984
|
-
);
|
|
2985
|
-
var listUserAccounts = createAuthEndpoint(
|
|
2986
|
-
"/list-accounts",
|
|
2987
|
-
{
|
|
2988
|
-
method: "GET",
|
|
2989
|
-
use: [sessionMiddleware],
|
|
2990
|
-
metadata: {
|
|
2991
|
-
openapi: {
|
|
2992
|
-
description: "List all accounts linked to the user",
|
|
2993
|
-
responses: {
|
|
2994
|
-
"200": {
|
|
2995
|
-
description: "Success",
|
|
2996
|
-
content: {
|
|
2997
|
-
"application/json": {
|
|
2998
|
-
schema: {
|
|
2999
|
-
type: "array",
|
|
3000
|
-
items: {
|
|
3001
|
-
type: "object",
|
|
3002
|
-
properties: {
|
|
3003
|
-
id: {
|
|
3004
|
-
type: "string"
|
|
3005
|
-
},
|
|
3006
|
-
provider: {
|
|
3007
|
-
type: "string"
|
|
3008
|
-
}
|
|
3009
|
-
}
|
|
3010
|
-
}
|
|
3011
|
-
}
|
|
3012
|
-
}
|
|
3013
|
-
}
|
|
3014
|
-
}
|
|
3015
|
-
}
|
|
3016
|
-
}
|
|
3017
|
-
}
|
|
3018
|
-
},
|
|
3019
|
-
async (c) => {
|
|
3020
|
-
const session = c.context.session;
|
|
3021
|
-
const accounts = await c.context.internalAdapter.findAccounts(
|
|
3022
|
-
session.user.id
|
|
3023
|
-
);
|
|
3024
|
-
return c.json(
|
|
3025
|
-
accounts.map((a) => {
|
|
3026
|
-
return {
|
|
3027
|
-
id: a.id,
|
|
3028
|
-
provider: a.providerId,
|
|
3029
|
-
createdAt: a.createdAt,
|
|
3030
|
-
updatedAt: a.updatedAt,
|
|
3031
|
-
accountId: a.accountId,
|
|
3032
|
-
scopes: a.scope?.split(",") || []
|
|
3033
|
-
};
|
|
3034
|
-
})
|
|
3035
|
-
);
|
|
3036
|
-
}
|
|
3037
|
-
);
|
|
3038
|
-
var linkSocialAccount = createAuthEndpoint(
|
|
3039
|
-
"/link-social",
|
|
3040
|
-
{
|
|
3041
|
-
method: "POST",
|
|
3042
|
-
requireHeaders: true,
|
|
3043
|
-
body: z.object({
|
|
3044
|
-
/**
|
|
3045
|
-
* Callback URL to redirect to after the user has signed in.
|
|
3046
|
-
*/
|
|
3047
|
-
callbackURL: z.string({
|
|
3048
|
-
description: "The URL to redirect to after the user has signed in"
|
|
3049
|
-
}).optional(),
|
|
3050
|
-
/**
|
|
3051
|
-
* OAuth2 provider to use`
|
|
3052
|
-
*/
|
|
3053
|
-
provider: z.enum(socialProviderList, {
|
|
3054
|
-
description: "The OAuth2 provider to use"
|
|
3055
|
-
})
|
|
3056
|
-
}),
|
|
3057
|
-
use: [sessionMiddleware],
|
|
3058
|
-
metadata: {
|
|
3059
|
-
openapi: {
|
|
3060
|
-
description: "Link a social account to the user",
|
|
3061
|
-
responses: {
|
|
3062
|
-
"200": {
|
|
3063
|
-
description: "Success",
|
|
3064
|
-
content: {
|
|
3065
|
-
"application/json": {
|
|
3066
|
-
schema: {
|
|
3067
|
-
type: "object",
|
|
3068
|
-
properties: {
|
|
3069
|
-
url: {
|
|
3070
|
-
type: "string"
|
|
3071
|
-
},
|
|
3072
|
-
redirect: {
|
|
3073
|
-
type: "boolean"
|
|
3074
|
-
}
|
|
3075
|
-
},
|
|
3076
|
-
required: ["url", "redirect"]
|
|
3077
|
-
}
|
|
3078
|
-
}
|
|
3079
|
-
}
|
|
3080
|
-
}
|
|
3081
|
-
}
|
|
3082
|
-
}
|
|
3083
|
-
}
|
|
3084
|
-
},
|
|
3085
|
-
async (c) => {
|
|
3086
|
-
const session = c.context.session;
|
|
3087
|
-
const account = await c.context.internalAdapter.findAccounts(
|
|
3088
|
-
session.user.id
|
|
3089
|
-
);
|
|
3090
|
-
const existingAccount = account.find(
|
|
3091
|
-
(a) => a.providerId === c.body.provider
|
|
3092
|
-
);
|
|
3093
|
-
if (existingAccount) {
|
|
3094
|
-
throw new APIError("BAD_REQUEST", {
|
|
3095
|
-
message: BASE_ERROR_CODES.SOCIAL_ACCOUNT_ALREADY_LINKED
|
|
3096
|
-
});
|
|
3097
|
-
}
|
|
3098
|
-
const provider = c.context.socialProviders.find(
|
|
3099
|
-
(p) => p.id === c.body.provider
|
|
3100
|
-
);
|
|
3101
|
-
if (!provider) {
|
|
3102
|
-
c.context.logger.error(
|
|
3103
|
-
"Provider not found. Make sure to add the provider in your auth config",
|
|
3104
|
-
{
|
|
3105
|
-
provider: c.body.provider
|
|
3106
|
-
}
|
|
3107
|
-
);
|
|
3108
|
-
throw new APIError("NOT_FOUND", {
|
|
3109
|
-
message: BASE_ERROR_CODES.PROVIDER_NOT_FOUND
|
|
3110
|
-
});
|
|
3111
|
-
}
|
|
3112
|
-
const state = await generateState(c, {
|
|
3113
|
-
userId: session.user.id,
|
|
3114
|
-
email: session.user.email
|
|
3115
|
-
});
|
|
3116
|
-
const url = await provider.createAuthorizationURL({
|
|
3117
|
-
state: state.state,
|
|
3118
|
-
codeVerifier: state.codeVerifier,
|
|
3119
|
-
redirectURI: `${c.context.baseURL}/callback/${provider.id}`
|
|
3120
|
-
});
|
|
3121
|
-
return c.json({
|
|
3122
|
-
url: url.toString(),
|
|
3123
|
-
redirect: true
|
|
3124
|
-
});
|
|
3125
|
-
}
|
|
3126
|
-
);
|
|
3127
|
-
var unlinkAccount = createAuthEndpoint(
|
|
3128
|
-
"/unlink-account",
|
|
3129
|
-
{
|
|
3130
|
-
method: "POST",
|
|
3131
|
-
body: z.object({
|
|
3132
|
-
providerId: z.string()
|
|
3133
|
-
}),
|
|
3134
|
-
use: [freshSessionMiddleware]
|
|
3135
|
-
},
|
|
3136
|
-
async (ctx) => {
|
|
3137
|
-
const accounts = await ctx.context.internalAdapter.findAccounts(
|
|
3138
|
-
ctx.context.session.user.id
|
|
3139
|
-
);
|
|
3140
|
-
if (accounts.length === 1) {
|
|
3141
|
-
throw new APIError("BAD_REQUEST", {
|
|
3142
|
-
message: BASE_ERROR_CODES.FAILED_TO_UNLINK_LAST_ACCOUNT
|
|
3143
|
-
});
|
|
3144
|
-
}
|
|
3145
|
-
const accountExist = accounts.find(
|
|
3146
|
-
(account) => account.providerId === ctx.body.providerId
|
|
3147
|
-
);
|
|
3148
|
-
if (!accountExist) {
|
|
3149
|
-
throw new APIError("BAD_REQUEST", {
|
|
3150
|
-
message: BASE_ERROR_CODES.ACCOUNT_NOT_FOUND
|
|
3151
|
-
});
|
|
3152
|
-
}
|
|
3153
|
-
await ctx.context.internalAdapter.deleteAccount(
|
|
3154
|
-
ctx.body.providerId,
|
|
3155
|
-
ctx.context.session.user.id
|
|
3156
|
-
);
|
|
3157
|
-
return ctx.json({
|
|
3158
|
-
status: true
|
|
3159
|
-
});
|
|
3160
|
-
}
|
|
3161
|
-
);
|
|
3162
|
-
|
|
3163
|
-
// src/api/rate-limiter/index.ts
|
|
3164
|
-
function shouldRateLimit(max, window, rateLimitData) {
|
|
3165
|
-
const now = Date.now();
|
|
3166
|
-
const windowInMs = window * 1e3;
|
|
3167
|
-
const timeSinceLastRequest = now - rateLimitData.lastRequest;
|
|
3168
|
-
return timeSinceLastRequest < windowInMs && rateLimitData.count >= max;
|
|
3169
|
-
}
|
|
3170
|
-
function rateLimitResponse(retryAfter) {
|
|
3171
|
-
return new Response(
|
|
3172
|
-
JSON.stringify({
|
|
3173
|
-
message: "Too many requests. Please try again later."
|
|
3174
|
-
}),
|
|
3175
|
-
{
|
|
3176
|
-
status: 429,
|
|
3177
|
-
statusText: "Too Many Requests",
|
|
3178
|
-
headers: {
|
|
3179
|
-
"X-Retry-After": retryAfter.toString()
|
|
3180
|
-
}
|
|
3181
|
-
}
|
|
3182
|
-
);
|
|
3183
|
-
}
|
|
3184
|
-
function getRetryAfter(lastRequest, window) {
|
|
3185
|
-
const now = Date.now();
|
|
3186
|
-
const windowInMs = window * 1e3;
|
|
3187
|
-
return Math.ceil((lastRequest + windowInMs - now) / 1e3);
|
|
3188
|
-
}
|
|
3189
|
-
function createDBStorage(ctx, modelName) {
|
|
3190
|
-
const model = ctx.options.rateLimit?.modelName || "rateLimit";
|
|
3191
|
-
const db = ctx.adapter;
|
|
3192
|
-
return {
|
|
3193
|
-
get: async (key) => {
|
|
3194
|
-
const res = await db.findMany({
|
|
3195
|
-
model,
|
|
3196
|
-
where: [{ field: "key", value: key }]
|
|
3197
|
-
});
|
|
3198
|
-
const data = res[0];
|
|
3199
|
-
if (typeof data?.lastRequest === "bigint") {
|
|
3200
|
-
data.lastRequest = Number(data.lastRequest);
|
|
3201
|
-
}
|
|
3202
|
-
return data;
|
|
3203
|
-
},
|
|
3204
|
-
set: async (key, value, _update) => {
|
|
3205
|
-
try {
|
|
3206
|
-
if (_update) {
|
|
3207
|
-
await db.updateMany({
|
|
3208
|
-
model: modelName ?? "rateLimit",
|
|
3209
|
-
where: [{ field: "key", value: key }],
|
|
3210
|
-
update: {
|
|
3211
|
-
count: value.count,
|
|
3212
|
-
lastRequest: value.lastRequest
|
|
3213
|
-
}
|
|
3214
|
-
});
|
|
3215
|
-
} else {
|
|
3216
|
-
await db.create({
|
|
3217
|
-
model: modelName ?? "rateLimit",
|
|
3218
|
-
data: {
|
|
3219
|
-
key,
|
|
3220
|
-
count: value.count,
|
|
3221
|
-
lastRequest: value.lastRequest
|
|
3222
|
-
}
|
|
3223
|
-
});
|
|
3224
|
-
}
|
|
3225
|
-
} catch (e) {
|
|
3226
|
-
ctx.logger.error("Error setting rate limit", e);
|
|
3227
|
-
}
|
|
3228
|
-
}
|
|
3229
|
-
};
|
|
3230
|
-
}
|
|
3231
|
-
var memory = /* @__PURE__ */ new Map();
|
|
3232
|
-
function getRateLimitStorage(ctx) {
|
|
3233
|
-
if (ctx.options.rateLimit?.customStorage) {
|
|
3234
|
-
return ctx.options.rateLimit.customStorage;
|
|
3235
|
-
}
|
|
3236
|
-
if (ctx.rateLimit.storage === "secondary-storage") {
|
|
3237
|
-
return {
|
|
3238
|
-
get: async (key) => {
|
|
3239
|
-
const stringified = await ctx.options.secondaryStorage?.get(key);
|
|
3240
|
-
return stringified ? JSON.parse(stringified) : undefined;
|
|
3241
|
-
},
|
|
3242
|
-
set: async (key, value) => {
|
|
3243
|
-
await ctx.options.secondaryStorage?.set?.(key, JSON.stringify(value));
|
|
3244
|
-
}
|
|
3245
|
-
};
|
|
3246
|
-
}
|
|
3247
|
-
const storage = ctx.rateLimit.storage;
|
|
3248
|
-
if (storage === "memory") {
|
|
3249
|
-
return {
|
|
3250
|
-
async get(key) {
|
|
3251
|
-
return memory.get(key);
|
|
3252
|
-
},
|
|
3253
|
-
async set(key, value, _update) {
|
|
3254
|
-
memory.set(key, value);
|
|
3255
|
-
}
|
|
3256
|
-
};
|
|
3257
|
-
}
|
|
3258
|
-
return createDBStorage(ctx, ctx.rateLimit.modelName);
|
|
3259
|
-
}
|
|
3260
|
-
async function onRequestRateLimit(req, ctx) {
|
|
3261
|
-
if (!ctx.rateLimit.enabled) {
|
|
3262
|
-
return;
|
|
3263
|
-
}
|
|
3264
|
-
const baseURL = ctx.baseURL;
|
|
3265
|
-
const path = req.url.replace(baseURL, "").split("?")[0];
|
|
3266
|
-
let window = ctx.rateLimit.window;
|
|
3267
|
-
let max = ctx.rateLimit.max;
|
|
3268
|
-
const key = getIp(req, ctx.options) + path;
|
|
3269
|
-
const specialRules = getDefaultSpecialRules();
|
|
3270
|
-
const specialRule = specialRules.find((rule) => rule.pathMatcher(path));
|
|
3271
|
-
if (specialRule) {
|
|
3272
|
-
window = specialRule.window;
|
|
3273
|
-
max = specialRule.max;
|
|
3274
|
-
}
|
|
3275
|
-
for (const plugin of ctx.options.plugins || []) {
|
|
3276
|
-
if (plugin.rateLimit) {
|
|
3277
|
-
const matchedRule = plugin.rateLimit.find(
|
|
3278
|
-
(rule) => rule.pathMatcher(path)
|
|
3279
|
-
);
|
|
3280
|
-
if (matchedRule) {
|
|
3281
|
-
window = matchedRule.window;
|
|
3282
|
-
max = matchedRule.max;
|
|
3283
|
-
break;
|
|
3284
|
-
}
|
|
3285
|
-
}
|
|
3286
|
-
}
|
|
3287
|
-
if (ctx.rateLimit.customRules) {
|
|
3288
|
-
const _path = Object.keys(ctx.rateLimit.customRules).find((p) => {
|
|
3289
|
-
if (p.includes("*")) {
|
|
3290
|
-
const isMatch2 = wildcardMatch(p)(path);
|
|
3291
|
-
return isMatch2;
|
|
3292
|
-
}
|
|
3293
|
-
return p === path;
|
|
3294
|
-
});
|
|
3295
|
-
if (_path) {
|
|
3296
|
-
const customRule = ctx.rateLimit.customRules[_path];
|
|
3297
|
-
const resolved = typeof customRule === "function" ? await customRule(req) : customRule;
|
|
3298
|
-
if (resolved) {
|
|
3299
|
-
window = resolved.window;
|
|
3300
|
-
max = resolved.max;
|
|
3301
|
-
}
|
|
3302
|
-
}
|
|
3303
|
-
}
|
|
3304
|
-
const storage = getRateLimitStorage(ctx);
|
|
3305
|
-
const data = await storage.get(key);
|
|
3306
|
-
const now = Date.now();
|
|
3307
|
-
if (!data) {
|
|
3308
|
-
await storage.set(key, {
|
|
3309
|
-
key,
|
|
3310
|
-
count: 1,
|
|
3311
|
-
lastRequest: now
|
|
3312
|
-
});
|
|
3313
|
-
} else {
|
|
3314
|
-
const timeSinceLastRequest = now - data.lastRequest;
|
|
3315
|
-
if (shouldRateLimit(max, window, data)) {
|
|
3316
|
-
const retryAfter = getRetryAfter(data.lastRequest, window);
|
|
3317
|
-
return rateLimitResponse(retryAfter);
|
|
3318
|
-
} else if (timeSinceLastRequest > window * 1e3) {
|
|
3319
|
-
await storage.set(
|
|
3320
|
-
key,
|
|
3321
|
-
{
|
|
3322
|
-
...data,
|
|
3323
|
-
count: 1,
|
|
3324
|
-
lastRequest: now
|
|
3325
|
-
},
|
|
3326
|
-
true
|
|
3327
|
-
);
|
|
3328
|
-
} else {
|
|
3329
|
-
await storage.set(
|
|
3330
|
-
key,
|
|
3331
|
-
{
|
|
3332
|
-
...data,
|
|
3333
|
-
count: data.count + 1,
|
|
3334
|
-
lastRequest: now
|
|
3335
|
-
},
|
|
3336
|
-
true
|
|
3337
|
-
);
|
|
3338
|
-
}
|
|
3339
|
-
}
|
|
3340
|
-
}
|
|
3341
|
-
function getDefaultSpecialRules() {
|
|
3342
|
-
const specialRules = [
|
|
3343
|
-
{
|
|
3344
|
-
pathMatcher(path) {
|
|
3345
|
-
return path.startsWith("/sign-in") || path.startsWith("/sign-up") || path.startsWith("/change-password") || path.startsWith("/change-email");
|
|
3346
|
-
},
|
|
3347
|
-
window: 10,
|
|
3348
|
-
max: 3
|
|
3349
|
-
}
|
|
3350
|
-
];
|
|
3351
|
-
return specialRules;
|
|
3352
|
-
}
|
|
3353
|
-
function toAuthEndpoints(endpoints, ctx) {
|
|
3354
|
-
const api = {};
|
|
3355
|
-
for (const [key, endpoint] of Object.entries(endpoints)) {
|
|
3356
|
-
api[key] = async (context) => {
|
|
3357
|
-
const authContext = await ctx;
|
|
3358
|
-
let internalContext = {
|
|
3359
|
-
...context,
|
|
3360
|
-
context: {
|
|
3361
|
-
...authContext,
|
|
3362
|
-
returned: undefined,
|
|
3363
|
-
responseHeaders: undefined,
|
|
3364
|
-
session: null
|
|
3365
|
-
},
|
|
3366
|
-
path: endpoint.path,
|
|
3367
|
-
headers: context?.headers ? new Headers(context?.headers) : undefined
|
|
3368
|
-
};
|
|
3369
|
-
const { beforeHooks, afterHooks } = getHooks(authContext);
|
|
3370
|
-
const before = await runBeforeHooks(internalContext, beforeHooks);
|
|
3371
|
-
if ("context" in before && before.context && typeof before.context === "object") {
|
|
3372
|
-
const { headers, ...rest } = before.context;
|
|
3373
|
-
if (headers) {
|
|
3374
|
-
headers.forEach((value, key2) => {
|
|
3375
|
-
internalContext.headers.set(key2, value);
|
|
3376
|
-
});
|
|
3377
|
-
}
|
|
3378
|
-
internalContext = defu(rest, internalContext);
|
|
3379
|
-
} else if (before) {
|
|
3380
|
-
return before;
|
|
3381
|
-
}
|
|
3382
|
-
internalContext.asResponse = false;
|
|
3383
|
-
internalContext.returnHeaders = true;
|
|
3384
|
-
const result = await endpoint(internalContext).catch((e) => {
|
|
3385
|
-
if (e instanceof APIError) {
|
|
3386
|
-
return {
|
|
3387
|
-
response: e,
|
|
3388
|
-
headers: e.headers ? new Headers(e.headers) : null
|
|
3389
|
-
};
|
|
3390
|
-
}
|
|
3391
|
-
throw e;
|
|
3392
|
-
});
|
|
3393
|
-
internalContext.context.returned = result.response;
|
|
3394
|
-
internalContext.context.responseHeaders = result.headers;
|
|
3395
|
-
const after = await runAfterHooks(internalContext, afterHooks);
|
|
3396
|
-
if (after.response) {
|
|
3397
|
-
result.response = after.response;
|
|
3398
|
-
}
|
|
3399
|
-
if (result.response instanceof APIError && !context?.asResponse) {
|
|
3400
|
-
throw result.response;
|
|
3401
|
-
}
|
|
3402
|
-
const response = context?.asResponse ? toResponse(result.response, {
|
|
3403
|
-
headers: result.headers
|
|
3404
|
-
}) : context?.returnHeaders ? {
|
|
3405
|
-
headers: result.headers,
|
|
3406
|
-
response: result.response
|
|
3407
|
-
} : result.response;
|
|
3408
|
-
return response;
|
|
3409
|
-
};
|
|
3410
|
-
api[key].path = endpoint.path;
|
|
3411
|
-
api[key].options = endpoint.options;
|
|
3412
|
-
}
|
|
3413
|
-
return api;
|
|
3414
|
-
}
|
|
3415
|
-
async function runBeforeHooks(context, hooks) {
|
|
3416
|
-
let modifiedContext = {};
|
|
3417
|
-
for (const hook of hooks) {
|
|
3418
|
-
if (hook.matcher(context)) {
|
|
3419
|
-
const result = await hook.handler({
|
|
3420
|
-
...context,
|
|
3421
|
-
returnHeaders: false
|
|
3422
|
-
});
|
|
3423
|
-
if (result && typeof result === "object") {
|
|
3424
|
-
if ("context" in result && typeof result.context === "object") {
|
|
3425
|
-
const { headers, ...rest } = result.context;
|
|
3426
|
-
if (headers instanceof Headers) {
|
|
3427
|
-
if (modifiedContext.headers) {
|
|
3428
|
-
headers.forEach((value, key) => {
|
|
3429
|
-
modifiedContext.headers?.set(key, value);
|
|
3430
|
-
});
|
|
3431
|
-
} else {
|
|
3432
|
-
modifiedContext.headers = headers;
|
|
3433
|
-
}
|
|
3434
|
-
}
|
|
3435
|
-
modifiedContext = defu(rest, modifiedContext);
|
|
3436
|
-
continue;
|
|
3437
|
-
}
|
|
3438
|
-
return result;
|
|
3439
|
-
}
|
|
3440
|
-
}
|
|
3441
|
-
}
|
|
3442
|
-
return { context: modifiedContext };
|
|
3443
|
-
}
|
|
3444
|
-
async function runAfterHooks(context, hooks) {
|
|
3445
|
-
for (const hook of hooks) {
|
|
3446
|
-
if (hook.matcher(context)) {
|
|
3447
|
-
const result = await hook.handler(context).catch((e) => {
|
|
3448
|
-
if (e instanceof APIError) {
|
|
3449
|
-
return {
|
|
3450
|
-
response: e,
|
|
3451
|
-
headers: e.headers ? new Headers(e.headers) : null
|
|
3452
|
-
};
|
|
3453
|
-
}
|
|
3454
|
-
throw e;
|
|
3455
|
-
});
|
|
3456
|
-
if (result.headers) {
|
|
3457
|
-
result.headers.forEach((value, key) => {
|
|
3458
|
-
if (!context.context.responseHeaders) {
|
|
3459
|
-
context.context.responseHeaders = new Headers({
|
|
3460
|
-
[key]: value
|
|
3461
|
-
});
|
|
3462
|
-
} else {
|
|
3463
|
-
if (key.toLowerCase() === "set-cookie") {
|
|
3464
|
-
context.context.responseHeaders.append(key, value);
|
|
3465
|
-
} else {
|
|
3466
|
-
context.context.responseHeaders.set(key, value);
|
|
3467
|
-
}
|
|
3468
|
-
}
|
|
3469
|
-
});
|
|
3470
|
-
}
|
|
3471
|
-
if (result.response) {
|
|
3472
|
-
context.context.returned = result.response;
|
|
3473
|
-
}
|
|
3474
|
-
}
|
|
3475
|
-
}
|
|
3476
|
-
return {
|
|
3477
|
-
response: context.context.returned,
|
|
3478
|
-
headers: context.context.responseHeaders
|
|
3479
|
-
};
|
|
3480
|
-
}
|
|
3481
|
-
function getHooks(authContext) {
|
|
3482
|
-
const plugins = authContext.options.plugins || [];
|
|
3483
|
-
const beforeHooks = [];
|
|
3484
|
-
const afterHooks = [];
|
|
3485
|
-
if (authContext.options.hooks?.before) {
|
|
3486
|
-
beforeHooks.push({
|
|
3487
|
-
matcher: () => true,
|
|
3488
|
-
handler: authContext.options.hooks.before
|
|
3489
|
-
});
|
|
3490
|
-
}
|
|
3491
|
-
if (authContext.options.hooks?.after) {
|
|
3492
|
-
afterHooks.push({
|
|
3493
|
-
matcher: () => true,
|
|
3494
|
-
handler: authContext.options.hooks.after
|
|
3495
|
-
});
|
|
3496
|
-
}
|
|
3497
|
-
const pluginBeforeHooks = plugins.map((plugin) => {
|
|
3498
|
-
if (plugin.hooks?.before) {
|
|
3499
|
-
return plugin.hooks.before;
|
|
3500
|
-
}
|
|
3501
|
-
}).filter((plugin) => plugin !== undefined).flat();
|
|
3502
|
-
const pluginAfterHooks = plugins.map((plugin) => {
|
|
3503
|
-
if (plugin.hooks?.after) {
|
|
3504
|
-
return plugin.hooks.after;
|
|
3505
|
-
}
|
|
3506
|
-
}).filter((plugin) => plugin !== undefined).flat();
|
|
3507
|
-
pluginBeforeHooks.length && beforeHooks.push(...pluginBeforeHooks);
|
|
3508
|
-
pluginAfterHooks.length && afterHooks.push(...pluginAfterHooks);
|
|
3509
|
-
return {
|
|
3510
|
-
beforeHooks,
|
|
3511
|
-
afterHooks
|
|
3512
|
-
};
|
|
3513
|
-
}
|
|
3514
|
-
function getEndpoints(ctx, options) {
|
|
3515
|
-
const pluginEndpoints = options.plugins?.reduce(
|
|
3516
|
-
(acc, plugin) => {
|
|
3517
|
-
return {
|
|
3518
|
-
...acc,
|
|
3519
|
-
...plugin.endpoints
|
|
3520
|
-
};
|
|
3521
|
-
},
|
|
3522
|
-
{}
|
|
3523
|
-
);
|
|
3524
|
-
const middlewares = options.plugins?.map(
|
|
3525
|
-
(plugin) => plugin.middlewares?.map((m) => {
|
|
3526
|
-
const middleware = async (context) => {
|
|
3527
|
-
return m.middleware({
|
|
3528
|
-
...context,
|
|
3529
|
-
context: {
|
|
3530
|
-
...ctx,
|
|
3531
|
-
...context.context
|
|
3532
|
-
}
|
|
3533
|
-
});
|
|
3534
|
-
};
|
|
3535
|
-
middleware.options = m.middleware.options;
|
|
3536
|
-
return {
|
|
3537
|
-
path: m.path,
|
|
3538
|
-
middleware
|
|
3539
|
-
};
|
|
3540
|
-
})
|
|
3541
|
-
).filter((plugin) => plugin !== undefined).flat() || [];
|
|
3542
|
-
const baseEndpoints = {
|
|
3543
|
-
signInSocial,
|
|
3544
|
-
callbackOAuth,
|
|
3545
|
-
getSession: getSession(),
|
|
3546
|
-
signOut,
|
|
3547
|
-
signUpEmail: signUpEmail(),
|
|
3548
|
-
signInEmail,
|
|
3549
|
-
forgetPassword,
|
|
3550
|
-
resetPassword,
|
|
3551
|
-
verifyEmail,
|
|
3552
|
-
sendVerificationEmail,
|
|
3553
|
-
changeEmail,
|
|
3554
|
-
changePassword,
|
|
3555
|
-
setPassword,
|
|
3556
|
-
updateUser: updateUser(),
|
|
3557
|
-
deleteUser,
|
|
3558
|
-
forgetPasswordCallback,
|
|
3559
|
-
listSessions: listSessions(),
|
|
3560
|
-
revokeSession,
|
|
3561
|
-
revokeSessions,
|
|
3562
|
-
revokeOtherSessions,
|
|
3563
|
-
linkSocialAccount,
|
|
3564
|
-
listUserAccounts,
|
|
3565
|
-
deleteUserCallback,
|
|
3566
|
-
unlinkAccount
|
|
3567
|
-
};
|
|
3568
|
-
const endpoints = {
|
|
3569
|
-
...baseEndpoints,
|
|
3570
|
-
...pluginEndpoints,
|
|
3571
|
-
ok,
|
|
3572
|
-
error
|
|
3573
|
-
};
|
|
3574
|
-
const api = toAuthEndpoints(endpoints, ctx);
|
|
3575
|
-
return {
|
|
3576
|
-
api,
|
|
3577
|
-
middlewares
|
|
3578
|
-
};
|
|
3579
|
-
}
|
|
3580
|
-
var router = (ctx, options) => {
|
|
3581
|
-
const { api, middlewares } = getEndpoints(ctx, options);
|
|
3582
|
-
const basePath = new URL(ctx.baseURL).pathname;
|
|
3583
|
-
return createRouter(api, {
|
|
3584
|
-
routerContext: ctx,
|
|
3585
|
-
openapi: {
|
|
3586
|
-
disabled: true
|
|
3587
|
-
},
|
|
3588
|
-
basePath,
|
|
3589
|
-
routerMiddleware: [
|
|
3590
|
-
{
|
|
3591
|
-
path: "/**",
|
|
3592
|
-
middleware: originCheckMiddleware
|
|
3593
|
-
},
|
|
3594
|
-
...middlewares
|
|
3595
|
-
],
|
|
3596
|
-
async onRequest(req) {
|
|
3597
|
-
for (const plugin of ctx.options.plugins || []) {
|
|
3598
|
-
if (plugin.onRequest) {
|
|
3599
|
-
const response = await plugin.onRequest(req, ctx);
|
|
3600
|
-
if (response && "response" in response) {
|
|
3601
|
-
return response.response;
|
|
3602
|
-
}
|
|
3603
|
-
}
|
|
3604
|
-
}
|
|
3605
|
-
return onRequestRateLimit(req, ctx);
|
|
3606
|
-
},
|
|
3607
|
-
async onResponse(res) {
|
|
3608
|
-
for (const plugin of ctx.options.plugins || []) {
|
|
3609
|
-
if (plugin.onResponse) {
|
|
3610
|
-
const response = await plugin.onResponse(res, ctx);
|
|
3611
|
-
if (response) {
|
|
3612
|
-
return response.response;
|
|
3613
|
-
}
|
|
3614
|
-
}
|
|
3615
|
-
}
|
|
3616
|
-
return res;
|
|
3617
|
-
},
|
|
3618
|
-
onError(e) {
|
|
3619
|
-
if (e instanceof APIError && e.status === "FOUND") {
|
|
3620
|
-
return;
|
|
3621
|
-
}
|
|
3622
|
-
if (options.onAPIError?.throw) {
|
|
3623
|
-
throw e;
|
|
3624
|
-
}
|
|
3625
|
-
if (options.onAPIError?.onError) {
|
|
3626
|
-
options.onAPIError.onError(e, ctx);
|
|
3627
|
-
return;
|
|
3628
|
-
}
|
|
3629
|
-
const optLogLevel = options.logger?.level;
|
|
3630
|
-
const log = optLogLevel === "error" || optLogLevel === "warn" || optLogLevel === "debug" ? logger : undefined;
|
|
3631
|
-
if (options.logger?.disabled !== true) {
|
|
3632
|
-
if (e && typeof e === "object" && "message" in e && typeof e.message === "string") {
|
|
3633
|
-
if (e.message.includes("no column") || e.message.includes("column") || e.message.includes("relation") || e.message.includes("table") || e.message.includes("does not exist")) {
|
|
3634
|
-
ctx.logger?.error(e.message);
|
|
3635
|
-
return;
|
|
3636
|
-
}
|
|
3637
|
-
}
|
|
3638
|
-
if (e instanceof APIError) {
|
|
3639
|
-
if (e.status === "INTERNAL_SERVER_ERROR") {
|
|
3640
|
-
ctx.logger.error(e.status, e);
|
|
3641
|
-
}
|
|
3642
|
-
log?.error(e.message);
|
|
3643
|
-
} else {
|
|
3644
|
-
ctx.logger?.error(
|
|
3645
|
-
e && typeof e === "object" && "name" in e ? e.name : "",
|
|
3646
|
-
e
|
|
3647
|
-
);
|
|
3648
|
-
}
|
|
3649
|
-
}
|
|
3650
|
-
}
|
|
3651
|
-
});
|
|
3652
|
-
};
|
|
3653
|
-
|
|
3654
|
-
export { BASE_ERROR_CODES, callbackOAuth, changeEmail, changePassword, createAuthEndpoint, createAuthMiddleware, createEmailVerificationToken, deleteUser, deleteUserCallback, error, forgetPassword, forgetPasswordCallback, freshSessionMiddleware, getEndpoints, getSession, getSessionFromCtx, handleOAuthUserInfo, linkSocialAccount, listSessions, listUserAccounts, ok, optionsMiddleware, originCheck, originCheckMiddleware, requestOnlySessionMiddleware, resetPassword, revokeOtherSessions, revokeSession, revokeSessions, router, sendVerificationEmail, sendVerificationEmailFn, sessionMiddleware, setPassword, signInEmail, signInSocial, signOut, signUpEmail, unlinkAccount, updateUser, verifyEmail };
|