better-auth 1.4.9 → 1.5.0-beta.1
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/api/index.d.mts +396 -395
- package/dist/api/index.mjs +6 -4
- package/dist/api/index.mjs.map +1 -1
- package/dist/api/middlewares/origin-check.d.mts +3 -3
- package/dist/api/middlewares/origin-check.mjs +14 -4
- package/dist/api/middlewares/origin-check.mjs.map +1 -1
- package/dist/api/routes/account.d.mts +11 -11
- package/dist/api/routes/account.mjs +59 -30
- package/dist/api/routes/account.mjs.map +1 -1
- package/dist/api/routes/callback.d.mts +2 -2
- package/dist/api/routes/email-verification.d.mts +4 -4
- package/dist/api/routes/email-verification.mjs +14 -14
- package/dist/api/routes/email-verification.mjs.map +1 -1
- package/dist/api/routes/error.d.mts +2 -2
- package/dist/api/routes/ok.d.mts +2 -2
- package/dist/api/routes/reset-password.d.mts +5 -5
- package/dist/api/routes/reset-password.mjs +9 -7
- package/dist/api/routes/reset-password.mjs.map +1 -1
- package/dist/api/routes/session.d.mts +14 -14
- package/dist/api/routes/session.mjs +31 -11
- package/dist/api/routes/session.mjs.map +1 -1
- package/dist/api/routes/sign-in.d.mts +3 -3
- package/dist/api/routes/sign-in.mjs +22 -17
- package/dist/api/routes/sign-in.mjs.map +1 -1
- package/dist/api/routes/sign-out.d.mts +2 -2
- package/dist/api/routes/sign-up.d.mts +2 -2
- package/dist/api/routes/sign-up.mjs +15 -12
- package/dist/api/routes/sign-up.mjs.map +1 -1
- package/dist/api/routes/update-user.d.mts +13 -13
- package/dist/api/routes/update-user.mjs +29 -24
- package/dist/api/routes/update-user.mjs.map +1 -1
- package/dist/api/to-auth-endpoints.mjs +7 -6
- package/dist/api/to-auth-endpoints.mjs.map +1 -1
- package/dist/client/lynx/index.d.mts +15 -15
- package/dist/client/plugins/index.d.mts +12 -2
- package/dist/client/plugins/index.mjs +11 -1
- package/dist/client/react/index.d.mts +13 -13
- package/dist/client/solid/index.d.mts +13 -13
- package/dist/client/svelte/index.d.mts +15 -15
- package/dist/client/types.d.mts +4 -1
- package/dist/client/vue/index.d.mts +13 -13
- package/dist/context/create-context.mjs +2 -2
- package/dist/context/create-context.mjs.map +1 -1
- package/dist/context/helpers.mjs +2 -2
- package/dist/context/helpers.mjs.map +1 -1
- package/dist/db/field.d.mts +6 -6
- package/dist/db/schema.mjs +14 -5
- package/dist/db/schema.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/integrations/next-js.d.mts +4 -4
- package/dist/integrations/svelte-kit.d.mts +2 -2
- package/dist/integrations/tanstack-start.d.mts +4 -4
- package/dist/oauth2/link-account.mjs +3 -2
- package/dist/oauth2/link-account.mjs.map +1 -1
- package/dist/oauth2/state.mjs +3 -3
- package/dist/oauth2/state.mjs.map +1 -1
- package/dist/plugins/admin/admin.d.mts +200 -137
- package/dist/plugins/admin/admin.mjs +3 -4
- package/dist/plugins/admin/admin.mjs.map +1 -1
- package/dist/plugins/admin/client.d.mts +87 -0
- package/dist/plugins/admin/client.mjs +3 -1
- package/dist/plugins/admin/client.mjs.map +1 -1
- package/dist/plugins/admin/error-codes.d.mts +90 -0
- package/dist/plugins/admin/error-codes.mjs.map +1 -1
- package/dist/plugins/admin/routes.mjs +40 -46
- package/dist/plugins/admin/routes.mjs.map +1 -1
- package/dist/plugins/anonymous/client.d.mts +19 -0
- package/dist/plugins/anonymous/client.mjs +4 -1
- package/dist/plugins/anonymous/client.mjs.map +1 -1
- package/dist/plugins/anonymous/error-codes.d.mts +22 -0
- package/dist/plugins/anonymous/index.d.mts +21 -9
- package/dist/plugins/anonymous/index.mjs +5 -5
- package/dist/plugins/anonymous/index.mjs.map +1 -1
- package/dist/plugins/api-key/client.d.mts +103 -0
- package/dist/plugins/api-key/client.mjs +4 -1
- package/dist/plugins/api-key/client.mjs.map +1 -1
- package/dist/plugins/api-key/error-codes.d.mts +106 -0
- package/dist/plugins/api-key/error-codes.mjs +34 -0
- package/dist/plugins/api-key/error-codes.mjs.map +1 -0
- package/dist/plugins/api-key/index.d.mts +181 -112
- package/dist/plugins/api-key/index.mjs +7 -34
- package/dist/plugins/api-key/index.mjs.map +1 -1
- package/dist/plugins/api-key/rate-limit.mjs +3 -2
- package/dist/plugins/api-key/rate-limit.mjs.map +1 -1
- package/dist/plugins/api-key/routes/create-api-key.mjs +19 -17
- package/dist/plugins/api-key/routes/create-api-key.mjs.map +1 -1
- package/dist/plugins/api-key/routes/delete-api-key.mjs +7 -5
- package/dist/plugins/api-key/routes/delete-api-key.mjs.map +1 -1
- package/dist/plugins/api-key/routes/get-api-key.mjs +5 -3
- package/dist/plugins/api-key/routes/get-api-key.mjs.map +1 -1
- package/dist/plugins/api-key/routes/update-api-key.mjs +18 -16
- package/dist/plugins/api-key/routes/update-api-key.mjs.map +1 -1
- package/dist/plugins/api-key/routes/verify-api-key.mjs +16 -35
- package/dist/plugins/api-key/routes/verify-api-key.mjs.map +1 -1
- package/dist/plugins/bearer/index.d.mts +3 -3
- package/dist/plugins/captcha/index.d.mts +2 -2
- package/dist/plugins/captcha/index.mjs +3 -3
- package/dist/plugins/captcha/index.mjs.map +1 -1
- package/dist/plugins/captcha/verify-handlers/captchafox.mjs +2 -2
- package/dist/plugins/captcha/verify-handlers/captchafox.mjs.map +1 -1
- package/dist/plugins/captcha/verify-handlers/cloudflare-turnstile.mjs +2 -2
- package/dist/plugins/captcha/verify-handlers/cloudflare-turnstile.mjs.map +1 -1
- package/dist/plugins/captcha/verify-handlers/google-recaptcha.mjs +2 -2
- package/dist/plugins/captcha/verify-handlers/google-recaptcha.mjs.map +1 -1
- package/dist/plugins/captcha/verify-handlers/h-captcha.mjs +2 -2
- package/dist/plugins/captcha/verify-handlers/h-captcha.mjs.map +1 -1
- package/dist/plugins/custom-session/index.d.mts +5 -5
- package/dist/plugins/device-authorization/index.d.mts +54 -18
- package/dist/plugins/device-authorization/routes.mjs +18 -18
- package/dist/plugins/device-authorization/routes.mjs.map +1 -1
- package/dist/plugins/email-otp/client.d.mts +15 -0
- package/dist/plugins/email-otp/client.mjs +4 -1
- package/dist/plugins/email-otp/client.mjs.map +1 -1
- package/dist/plugins/email-otp/error-codes.d.mts +18 -0
- package/dist/plugins/email-otp/error-codes.mjs +12 -0
- package/dist/plugins/email-otp/error-codes.mjs.map +1 -0
- package/dist/plugins/email-otp/index.d.mts +64 -55
- package/dist/plugins/email-otp/index.mjs +4 -3
- package/dist/plugins/email-otp/index.mjs.map +1 -1
- package/dist/plugins/email-otp/routes.mjs +30 -35
- package/dist/plugins/email-otp/routes.mjs.map +1 -1
- package/dist/plugins/generic-oauth/client.d.mts +27 -0
- package/dist/plugins/generic-oauth/client.mjs +4 -1
- package/dist/plugins/generic-oauth/client.mjs.map +1 -1
- package/dist/plugins/generic-oauth/error-codes.d.mts +30 -0
- package/dist/plugins/generic-oauth/index.d.mts +55 -37
- package/dist/plugins/generic-oauth/index.mjs +4 -4
- package/dist/plugins/generic-oauth/index.mjs.map +1 -1
- package/dist/plugins/generic-oauth/routes.mjs +11 -12
- package/dist/plugins/generic-oauth/routes.mjs.map +1 -1
- package/dist/plugins/haveibeenpwned/index.d.mts +7 -4
- package/dist/plugins/haveibeenpwned/index.mjs +5 -4
- package/dist/plugins/haveibeenpwned/index.mjs.map +1 -1
- package/dist/plugins/index.d.mts +4 -2
- package/dist/plugins/index.mjs +6 -4
- package/dist/plugins/jwt/index.d.mts +9 -9
- package/dist/plugins/jwt/index.mjs +2 -2
- package/dist/plugins/jwt/index.mjs.map +1 -1
- package/dist/plugins/last-login-method/index.d.mts +4 -4
- package/dist/plugins/magic-link/index.d.mts +4 -4
- package/dist/plugins/mcp/authorize.mjs +1 -1
- package/dist/plugins/mcp/authorize.mjs.map +1 -1
- package/dist/plugins/mcp/index.d.mts +10 -10
- package/dist/plugins/multi-session/client.d.mts +10 -14
- package/dist/plugins/multi-session/client.mjs +5 -2
- package/dist/plugins/multi-session/client.mjs.map +1 -1
- package/dist/plugins/multi-session/error-codes.d.mts +10 -0
- package/dist/plugins/multi-session/error-codes.mjs +8 -0
- package/dist/plugins/multi-session/error-codes.mjs.map +1 -0
- package/dist/plugins/multi-session/index.d.mts +18 -14
- package/dist/plugins/multi-session/index.mjs +6 -7
- package/dist/plugins/multi-session/index.mjs.map +1 -1
- package/dist/plugins/oauth-proxy/index.d.mts +8 -8
- package/dist/plugins/oidc-provider/authorize.mjs +1 -1
- package/dist/plugins/oidc-provider/authorize.mjs.map +1 -1
- package/dist/plugins/oidc-provider/error.mjs +1 -1
- package/dist/plugins/oidc-provider/error.mjs.map +1 -1
- package/dist/plugins/oidc-provider/index.d.mts +15 -15
- package/dist/plugins/one-tap/client.d.mts +2 -2
- package/dist/plugins/one-tap/index.d.mts +2 -2
- package/dist/plugins/one-time-token/index.d.mts +5 -5
- package/dist/plugins/open-api/index.d.mts +3 -3
- package/dist/plugins/organization/client.d.mts +229 -2
- package/dist/plugins/organization/client.mjs +3 -1
- package/dist/plugins/organization/client.mjs.map +1 -1
- package/dist/plugins/organization/error-codes.d.mts +224 -56
- package/dist/plugins/organization/organization.d.mts +7 -7
- package/dist/plugins/organization/organization.mjs +4 -4
- package/dist/plugins/organization/organization.mjs.map +1 -1
- package/dist/plugins/organization/routes/crud-access-control.d.mts +22 -22
- package/dist/plugins/organization/routes/crud-access-control.mjs +40 -39
- package/dist/plugins/organization/routes/crud-access-control.mjs.map +1 -1
- package/dist/plugins/organization/routes/crud-invites.d.mts +58 -58
- package/dist/plugins/organization/routes/crud-invites.mjs +42 -40
- package/dist/plugins/organization/routes/crud-invites.mjs.map +1 -1
- package/dist/plugins/organization/routes/crud-members.d.mts +67 -67
- package/dist/plugins/organization/routes/crud-members.mjs +41 -54
- package/dist/plugins/organization/routes/crud-members.mjs.map +1 -1
- package/dist/plugins/organization/routes/crud-org.d.mts +51 -51
- package/dist/plugins/organization/routes/crud-org.mjs +28 -25
- package/dist/plugins/organization/routes/crud-org.mjs.map +1 -1
- package/dist/plugins/organization/routes/crud-team.d.mts +77 -77
- package/dist/plugins/organization/routes/crud-team.mjs +41 -47
- package/dist/plugins/organization/routes/crud-team.mjs.map +1 -1
- package/dist/plugins/phone-number/client.d.mts +51 -0
- package/dist/plugins/phone-number/client.mjs +4 -1
- package/dist/plugins/phone-number/client.mjs.map +1 -1
- package/dist/plugins/phone-number/error-codes.d.mts +54 -0
- package/dist/plugins/phone-number/index.d.mts +81 -45
- package/dist/plugins/phone-number/index.mjs +2 -2
- package/dist/plugins/phone-number/index.mjs.map +1 -1
- package/dist/plugins/phone-number/routes.mjs +27 -28
- package/dist/plugins/phone-number/routes.mjs.map +1 -1
- package/dist/plugins/siwe/index.d.mts +3 -3
- package/dist/plugins/siwe/index.mjs +7 -6
- package/dist/plugins/siwe/index.mjs.map +1 -1
- package/dist/plugins/two-factor/backup-codes/index.mjs +7 -7
- package/dist/plugins/two-factor/backup-codes/index.mjs.map +1 -1
- package/dist/plugins/two-factor/client.d.mts +39 -0
- package/dist/plugins/two-factor/client.mjs +4 -1
- package/dist/plugins/two-factor/client.mjs.map +1 -1
- package/dist/plugins/two-factor/error-code.d.mts +36 -9
- package/dist/plugins/two-factor/index.d.mts +54 -27
- package/dist/plugins/two-factor/index.mjs +4 -5
- package/dist/plugins/two-factor/index.mjs.map +1 -1
- package/dist/plugins/two-factor/otp/index.mjs +8 -6
- package/dist/plugins/two-factor/otp/index.mjs.map +1 -1
- package/dist/plugins/two-factor/totp/index.mjs +16 -8
- package/dist/plugins/two-factor/totp/index.mjs.map +1 -1
- package/dist/plugins/two-factor/verify-two-factor.mjs +9 -6
- package/dist/plugins/two-factor/verify-two-factor.mjs.map +1 -1
- package/dist/plugins/username/client.d.mts +35 -0
- package/dist/plugins/username/client.mjs +4 -1
- package/dist/plugins/username/client.mjs.map +1 -1
- package/dist/plugins/username/error-codes.d.mts +32 -8
- package/dist/plugins/username/index.d.mts +41 -17
- package/dist/plugins/username/index.mjs +21 -31
- package/dist/plugins/username/index.mjs.map +1 -1
- package/dist/plugins/username/schema.d.mts +3 -3
- package/dist/test-utils/test-instance.d.mts +1349 -1198
- package/dist/utils/is-api-error.d.mts +7 -0
- package/dist/utils/is-api-error.mjs +11 -0
- package/dist/utils/is-api-error.mjs.map +1 -0
- package/dist/utils/password.mjs +3 -3
- package/dist/utils/password.mjs.map +1 -1
- package/dist/utils/plugin-helper.mjs +2 -2
- package/dist/utils/plugin-helper.mjs.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reset-password.mjs","names":[],"sources":["../../../src/api/routes/reset-password.ts"],"sourcesContent":["import type { AuthContext } from \"@better-auth/core\";\nimport { createAuthEndpoint } from \"@better-auth/core/api\";\nimport { BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport { APIError } from \"better-call\";\nimport * as z from \"zod\";\nimport { generateId } from \"../../utils\";\nimport { getDate } from \"../../utils/date\";\nimport { originCheck } from \"../middlewares\";\n\nfunction redirectError(\n\tctx: AuthContext,\n\tcallbackURL: string | undefined,\n\tquery?: Record<string, string> | undefined,\n): string {\n\tconst url = callbackURL\n\t\t? new URL(callbackURL, ctx.baseURL)\n\t\t: new URL(`${ctx.baseURL}/error`);\n\tif (query)\n\t\tObject.entries(query).forEach(([k, v]) => url.searchParams.set(k, v));\n\treturn url.href;\n}\n\nfunction redirectCallback(\n\tctx: AuthContext,\n\tcallbackURL: string,\n\tquery?: Record<string, string> | undefined,\n): string {\n\tconst url = new URL(callbackURL, ctx.baseURL);\n\tif (query)\n\t\tObject.entries(query).forEach(([k, v]) => url.searchParams.set(k, v));\n\treturn url.href;\n}\n\nexport const requestPasswordReset = createAuthEndpoint(\n\t\"/request-password-reset\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The email address of the user to send a password reset email to.\n\t\t\t */\n\t\t\temail: z.email().meta({\n\t\t\t\tdescription:\n\t\t\t\t\t\"The email address of the user to send a password reset email to\",\n\t\t\t}),\n\t\t\t/**\n\t\t\t * The URL to redirect the user to reset their password.\n\t\t\t * If the token isn't valid or expired, it'll be redirected with a query parameter `?\n\t\t\t * error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?\n\t\t\t * token=VALID_TOKEN\n\t\t\t */\n\t\t\tredirectTo: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"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\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"requestPasswordReset\",\n\t\t\t\tdescription: \"Send a password reset email to the user\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.options.emailAndPassword?.sendResetPassword) {\n\t\t\tctx.context.logger.error(\n\t\t\t\t\"Reset password isn't enabled.Please pass an emailAndPassword.sendResetPassword function in your auth config!\",\n\t\t\t);\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Reset password isn't enabled\",\n\t\t\t});\n\t\t}\n\t\tconst { email, redirectTo } = ctx.body;\n\n\t\tconst user = await ctx.context.internalAdapter.findUserByEmail(email, {\n\t\t\tincludeAccounts: true,\n\t\t});\n\t\tif (!user) {\n\t\t\t/**\n\t\t\t * We simulate the verification token generation and the database lookup\n\t\t\t * to mitigate timing attacks.\n\t\t\t */\n\t\t\tgenerateId(24);\n\t\t\tawait ctx.context.internalAdapter.findVerificationValue(\n\t\t\t\t\"dummy-verification-token\",\n\t\t\t);\n\t\t\tctx.context.logger.error(\"Reset Password: User not found\", { email });\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t\tmessage:\n\t\t\t\t\t\"If this email exists in our system, check your email for the reset link\",\n\t\t\t});\n\t\t}\n\t\tconst defaultExpiresIn = 60 * 60 * 1;\n\t\tconst expiresAt = getDate(\n\t\t\tctx.context.options.emailAndPassword.resetPasswordTokenExpiresIn ||\n\t\t\t\tdefaultExpiresIn,\n\t\t\t\"sec\",\n\t\t);\n\t\tconst verificationToken = generateId(24);\n\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\tvalue: user.user.id,\n\t\t\tidentifier: `reset-password:${verificationToken}`,\n\t\t\texpiresAt,\n\t\t});\n\t\tconst callbackURL = redirectTo ? encodeURIComponent(redirectTo) : \"\";\n\t\tconst url = `${ctx.context.baseURL}/reset-password/${verificationToken}?callbackURL=${callbackURL}`;\n\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\tctx.context.options.emailAndPassword.sendResetPassword(\n\t\t\t\t{\n\t\t\t\t\tuser: user.user,\n\t\t\t\t\turl,\n\t\t\t\t\ttoken: verificationToken,\n\t\t\t\t},\n\t\t\t\tctx.request,\n\t\t\t),\n\t\t);\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t\tmessage:\n\t\t\t\t\"If this email exists in our system, check your email for the reset link\",\n\t\t});\n\t},\n);\n\nexport const requestPasswordResetCallback = createAuthEndpoint(\n\t\"/reset-password/:token\",\n\t{\n\t\tmethod: \"GET\",\n\t\toperationId: \"forgetPasswordCallback\",\n\t\tquery: z.object({\n\t\t\tcallbackURL: z.string().meta({\n\t\t\t\tdescription: \"The URL to redirect the user to reset their password\",\n\t\t\t}),\n\t\t}),\n\t\tuse: [originCheck((ctx) => ctx.query.callbackURL)],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"resetPasswordCallback\",\n\t\t\t\tdescription: \"Redirects the user to the callback URL with the token\",\n\t\t\t\tparameters: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: \"token\",\n\t\t\t\t\t\tin: \"path\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tdescription: \"The token to reset the password\",\n\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: \"callbackURL\",\n\t\t\t\t\t\tin: \"query\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tdescription: \"The URL to redirect the user to reset their password\",\n\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst { token } = ctx.params;\n\t\tconst { callbackURL } = ctx.query;\n\t\tif (!token || !callbackURL) {\n\t\t\tthrow ctx.redirect(\n\t\t\t\tredirectError(ctx.context, callbackURL, { error: \"INVALID_TOKEN\" }),\n\t\t\t);\n\t\t}\n\t\tconst verification =\n\t\t\tawait ctx.context.internalAdapter.findVerificationValue(\n\t\t\t\t`reset-password:${token}`,\n\t\t\t);\n\t\tif (!verification || verification.expiresAt < new Date()) {\n\t\t\tthrow ctx.redirect(\n\t\t\t\tredirectError(ctx.context, callbackURL, { error: \"INVALID_TOKEN\" }),\n\t\t\t);\n\t\t}\n\n\t\tthrow ctx.redirect(redirectCallback(ctx.context, callbackURL, { token }));\n\t},\n);\n\nexport const resetPassword = createAuthEndpoint(\n\t\"/reset-password\",\n\t{\n\t\tmethod: \"POST\",\n\t\toperationId: \"resetPassword\",\n\t\tquery: z\n\t\t\t.object({\n\t\t\t\ttoken: z.string().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t\tbody: z.object({\n\t\t\tnewPassword: z.string().meta({\n\t\t\t\tdescription: \"The new password to set\",\n\t\t\t}),\n\t\t\ttoken: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"The token to reset the password\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"resetPassword\",\n\t\t\t\tdescription: \"Reset the password for a user\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst token = ctx.body.token || ctx.query?.token;\n\t\tif (!token) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: BASE_ERROR_CODES.INVALID_TOKEN,\n\t\t\t});\n\t\t}\n\n\t\tconst { newPassword } = ctx.body;\n\n\t\tconst minLength = ctx.context.password?.config.minPasswordLength;\n\t\tconst maxLength = ctx.context.password?.config.maxPasswordLength;\n\t\tif (newPassword.length < minLength) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: BASE_ERROR_CODES.PASSWORD_TOO_SHORT,\n\t\t\t});\n\t\t}\n\t\tif (newPassword.length > maxLength) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: BASE_ERROR_CODES.PASSWORD_TOO_LONG,\n\t\t\t});\n\t\t}\n\n\t\tconst id = `reset-password:${token}`;\n\n\t\tconst verification =\n\t\t\tawait ctx.context.internalAdapter.findVerificationValue(id);\n\t\tif (!verification || verification.expiresAt < new Date()) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: BASE_ERROR_CODES.INVALID_TOKEN,\n\t\t\t});\n\t\t}\n\t\tconst userId = verification.value;\n\t\tconst hashedPassword = await ctx.context.password.hash(newPassword);\n\t\tconst accounts = await ctx.context.internalAdapter.findAccounts(userId);\n\t\tconst account = accounts.find((ac) => ac.providerId === \"credential\");\n\t\tif (!account) {\n\t\t\tawait ctx.context.internalAdapter.createAccount({\n\t\t\t\tuserId,\n\t\t\t\tproviderId: \"credential\",\n\t\t\t\tpassword: hashedPassword,\n\t\t\t\taccountId: userId,\n\t\t\t});\n\t\t} else {\n\t\t\tawait ctx.context.internalAdapter.updatePassword(userId, hashedPassword);\n\t\t}\n\t\tawait ctx.context.internalAdapter.deleteVerificationValue(verification.id);\n\n\t\tif (ctx.context.options.emailAndPassword?.onPasswordReset) {\n\t\t\tconst user = await ctx.context.internalAdapter.findUserById(userId);\n\t\t\tif (user) {\n\t\t\t\tawait ctx.context.options.emailAndPassword.onPasswordReset(\n\t\t\t\t\t{\n\t\t\t\t\t\tuser,\n\t\t\t\t\t},\n\t\t\t\t\tctx.request,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (ctx.context.options.emailAndPassword?.revokeSessionsOnPasswordReset) {\n\t\t\tawait ctx.context.internalAdapter.deleteSessions(userId);\n\t\t}\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"reset-password.mjs","names":[],"sources":["../../../src/api/routes/reset-password.ts"],"sourcesContent":["import type { AuthContext } from \"@better-auth/core\";\nimport { createAuthEndpoint } from \"@better-auth/core/api\";\nimport { APIError, BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport * as z from \"zod\";\nimport { generateId } from \"../../utils\";\nimport { getDate } from \"../../utils/date\";\nimport { originCheck } from \"../middlewares\";\n\nfunction redirectError(\n\tctx: AuthContext,\n\tcallbackURL: string | undefined,\n\tquery?: Record<string, string> | undefined,\n): string {\n\tconst url = callbackURL\n\t\t? new URL(callbackURL, ctx.baseURL)\n\t\t: new URL(`${ctx.baseURL}/error`);\n\tif (query)\n\t\tObject.entries(query).forEach(([k, v]) => url.searchParams.set(k, v));\n\treturn url.href;\n}\n\nfunction redirectCallback(\n\tctx: AuthContext,\n\tcallbackURL: string,\n\tquery?: Record<string, string> | undefined,\n): string {\n\tconst url = new URL(callbackURL, ctx.baseURL);\n\tif (query)\n\t\tObject.entries(query).forEach(([k, v]) => url.searchParams.set(k, v));\n\treturn url.href;\n}\n\nexport const requestPasswordReset = createAuthEndpoint(\n\t\"/request-password-reset\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The email address of the user to send a password reset email to.\n\t\t\t */\n\t\t\temail: z.email().meta({\n\t\t\t\tdescription:\n\t\t\t\t\t\"The email address of the user to send a password reset email to\",\n\t\t\t}),\n\t\t\t/**\n\t\t\t * The URL to redirect the user to reset their password.\n\t\t\t * If the token isn't valid or expired, it'll be redirected with a query parameter `?\n\t\t\t * error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?\n\t\t\t * token=VALID_TOKEN\n\t\t\t */\n\t\t\tredirectTo: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"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\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"requestPasswordReset\",\n\t\t\t\tdescription: \"Send a password reset email to the user\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.options.emailAndPassword?.sendResetPassword) {\n\t\t\tctx.context.logger.error(\n\t\t\t\t\"Reset password isn't enabled.Please pass an emailAndPassword.sendResetPassword function in your auth config!\",\n\t\t\t);\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Reset password isn't enabled\",\n\t\t\t\tcode: \"RESET_PASSWORD_DISABLED\",\n\t\t\t});\n\t\t}\n\t\tconst { email, redirectTo } = ctx.body;\n\n\t\tconst user = await ctx.context.internalAdapter.findUserByEmail(email, {\n\t\t\tincludeAccounts: true,\n\t\t});\n\t\tif (!user) {\n\t\t\t/**\n\t\t\t * We simulate the verification token generation and the database lookup\n\t\t\t * to mitigate timing attacks.\n\t\t\t */\n\t\t\tgenerateId(24);\n\t\t\tawait ctx.context.internalAdapter.findVerificationValue(\n\t\t\t\t\"dummy-verification-token\",\n\t\t\t);\n\t\t\tctx.context.logger.error(\"Reset Password: User not found\", { email });\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t\tmessage:\n\t\t\t\t\t\"If this email exists in our system, check your email for the reset link\",\n\t\t\t});\n\t\t}\n\t\tconst defaultExpiresIn = 60 * 60 * 1;\n\t\tconst expiresAt = getDate(\n\t\t\tctx.context.options.emailAndPassword.resetPasswordTokenExpiresIn ||\n\t\t\t\tdefaultExpiresIn,\n\t\t\t\"sec\",\n\t\t);\n\t\tconst verificationToken = generateId(24);\n\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\tvalue: user.user.id,\n\t\t\tidentifier: `reset-password:${verificationToken}`,\n\t\t\texpiresAt,\n\t\t});\n\t\tconst callbackURL = redirectTo ? encodeURIComponent(redirectTo) : \"\";\n\t\tconst url = `${ctx.context.baseURL}/reset-password/${verificationToken}?callbackURL=${callbackURL}`;\n\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\tctx.context.options.emailAndPassword.sendResetPassword(\n\t\t\t\t{\n\t\t\t\t\tuser: user.user,\n\t\t\t\t\turl,\n\t\t\t\t\ttoken: verificationToken,\n\t\t\t\t},\n\t\t\t\tctx.request,\n\t\t\t),\n\t\t);\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t\tmessage:\n\t\t\t\t\"If this email exists in our system, check your email for the reset link\",\n\t\t});\n\t},\n);\n\nexport const requestPasswordResetCallback = createAuthEndpoint(\n\t\"/reset-password/:token\",\n\t{\n\t\tmethod: \"GET\",\n\t\toperationId: \"forgetPasswordCallback\",\n\t\tquery: z.object({\n\t\t\tcallbackURL: z.string().meta({\n\t\t\t\tdescription: \"The URL to redirect the user to reset their password\",\n\t\t\t}),\n\t\t}),\n\t\tuse: [originCheck((ctx) => ctx.query.callbackURL)],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"resetPasswordCallback\",\n\t\t\t\tdescription: \"Redirects the user to the callback URL with the token\",\n\t\t\t\tparameters: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: \"token\",\n\t\t\t\t\t\tin: \"path\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tdescription: \"The token to reset the password\",\n\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: \"callbackURL\",\n\t\t\t\t\t\tin: \"query\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tdescription: \"The URL to redirect the user to reset their password\",\n\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst { token } = ctx.params;\n\t\tconst { callbackURL } = ctx.query;\n\t\tif (!token || !callbackURL) {\n\t\t\tthrow ctx.redirect(\n\t\t\t\tredirectError(ctx.context, callbackURL, { error: \"INVALID_TOKEN\" }),\n\t\t\t);\n\t\t}\n\t\tconst verification =\n\t\t\tawait ctx.context.internalAdapter.findVerificationValue(\n\t\t\t\t`reset-password:${token}`,\n\t\t\t);\n\t\tif (!verification || verification.expiresAt < new Date()) {\n\t\t\tthrow ctx.redirect(\n\t\t\t\tredirectError(ctx.context, callbackURL, { error: \"INVALID_TOKEN\" }),\n\t\t\t);\n\t\t}\n\n\t\tthrow ctx.redirect(redirectCallback(ctx.context, callbackURL, { token }));\n\t},\n);\n\nexport const resetPassword = createAuthEndpoint(\n\t\"/reset-password\",\n\t{\n\t\tmethod: \"POST\",\n\t\toperationId: \"resetPassword\",\n\t\tquery: z\n\t\t\t.object({\n\t\t\t\ttoken: z.string().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t\tbody: z.object({\n\t\t\tnewPassword: z.string().meta({\n\t\t\t\tdescription: \"The new password to set\",\n\t\t\t}),\n\t\t\ttoken: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"The token to reset the password\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"resetPassword\",\n\t\t\t\tdescription: \"Reset the password for a user\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst token = ctx.body.token || ctx.query?.token;\n\t\tif (!token) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_TOKEN);\n\t\t}\n\n\t\tconst { newPassword } = ctx.body;\n\n\t\tconst minLength = ctx.context.password?.config.minPasswordLength;\n\t\tconst maxLength = ctx.context.password?.config.maxPasswordLength;\n\t\tif (newPassword.length < minLength) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_TOO_SHORT);\n\t\t}\n\t\tif (newPassword.length > maxLength) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.PASSWORD_TOO_LONG);\n\t\t}\n\n\t\tconst id = `reset-password:${token}`;\n\n\t\tconst verification =\n\t\t\tawait ctx.context.internalAdapter.findVerificationValue(id);\n\t\tif (!verification || verification.expiresAt < new Date()) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_TOKEN);\n\t\t}\n\t\tconst userId = verification.value;\n\t\tconst hashedPassword = await ctx.context.password.hash(newPassword);\n\t\tconst accounts = await ctx.context.internalAdapter.findAccounts(userId);\n\t\tconst account = accounts.find((ac) => ac.providerId === \"credential\");\n\t\tif (!account) {\n\t\t\tawait ctx.context.internalAdapter.createAccount({\n\t\t\t\tuserId,\n\t\t\t\tproviderId: \"credential\",\n\t\t\t\tpassword: hashedPassword,\n\t\t\t\taccountId: userId,\n\t\t\t});\n\t\t} else {\n\t\t\tawait ctx.context.internalAdapter.updatePassword(userId, hashedPassword);\n\t\t}\n\t\tawait ctx.context.internalAdapter.deleteVerificationValue(verification.id);\n\n\t\tif (ctx.context.options.emailAndPassword?.onPasswordReset) {\n\t\t\tconst user = await ctx.context.internalAdapter.findUserById(userId);\n\t\t\tif (user) {\n\t\t\t\tawait ctx.context.options.emailAndPassword.onPasswordReset(\n\t\t\t\t\t{\n\t\t\t\t\t\tuser,\n\t\t\t\t\t},\n\t\t\t\t\tctx.request,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (ctx.context.options.emailAndPassword?.revokeSessionsOnPasswordReset) {\n\t\t\tawait ctx.context.internalAdapter.deleteSessions(userId);\n\t\t}\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n"],"mappings":"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"}
|
|
@@ -3,10 +3,10 @@ import { InferSession, InferUser, Session, User } from "../../types/models.mjs";
|
|
|
3
3
|
import "../../types/index.mjs";
|
|
4
4
|
import { BetterAuthOptions, GenericEndpointContext } from "@better-auth/core";
|
|
5
5
|
import * as z from "zod";
|
|
6
|
-
import * as
|
|
6
|
+
import * as better_call741 from "better-call";
|
|
7
7
|
|
|
8
8
|
//#region src/api/routes/session.d.ts
|
|
9
|
-
declare const getSession: <Option extends BetterAuthOptions>() =>
|
|
9
|
+
declare const getSession: <Option extends BetterAuthOptions>() => better_call741.StrictEndpoint<"/get-session", {
|
|
10
10
|
method: "GET";
|
|
11
11
|
operationId: string;
|
|
12
12
|
query: z.ZodOptional<z.ZodObject<{
|
|
@@ -56,7 +56,7 @@ declare const getSessionFromCtx: <U extends Record<string, any> = Record<string,
|
|
|
56
56
|
/**
|
|
57
57
|
* The middleware forces the endpoint to require a valid session.
|
|
58
58
|
*/
|
|
59
|
-
declare const sessionMiddleware: (inputContext:
|
|
59
|
+
declare const sessionMiddleware: (inputContext: better_call741.MiddlewareInputContext<better_call741.MiddlewareOptions>) => Promise<{
|
|
60
60
|
session: {
|
|
61
61
|
session: Record<string, any> & {
|
|
62
62
|
id: string;
|
|
@@ -84,7 +84,7 @@ declare const sessionMiddleware: (inputContext: better_call896.MiddlewareInputCo
|
|
|
84
84
|
* This should be used for sensitive operations like password changes, account deletion, etc.
|
|
85
85
|
* to ensure that revoked sessions cannot be used even if they're still cached in cookies.
|
|
86
86
|
*/
|
|
87
|
-
declare const sensitiveSessionMiddleware: (inputContext:
|
|
87
|
+
declare const sensitiveSessionMiddleware: (inputContext: better_call741.MiddlewareInputContext<better_call741.MiddlewareOptions>) => Promise<{
|
|
88
88
|
session: {
|
|
89
89
|
session: Record<string, any> & {
|
|
90
90
|
id: string;
|
|
@@ -111,7 +111,7 @@ declare const sensitiveSessionMiddleware: (inputContext: better_call896.Middlewa
|
|
|
111
111
|
* This middleware allows you to call the endpoint on the client if session is valid.
|
|
112
112
|
* However, if called on the server, no session is required.
|
|
113
113
|
*/
|
|
114
|
-
declare const requestOnlySessionMiddleware: (inputContext:
|
|
114
|
+
declare const requestOnlySessionMiddleware: (inputContext: better_call741.MiddlewareInputContext<better_call741.MiddlewareOptions>) => Promise<{
|
|
115
115
|
session: {
|
|
116
116
|
session: Record<string, any> & {
|
|
117
117
|
id: string;
|
|
@@ -141,7 +141,7 @@ declare const requestOnlySessionMiddleware: (inputContext: better_call896.Middle
|
|
|
141
141
|
* Session freshness check will be skipped if the session config's freshAge
|
|
142
142
|
* is set to 0
|
|
143
143
|
*/
|
|
144
|
-
declare const freshSessionMiddleware: (inputContext:
|
|
144
|
+
declare const freshSessionMiddleware: (inputContext: better_call741.MiddlewareInputContext<better_call741.MiddlewareOptions>) => Promise<{
|
|
145
145
|
session: {
|
|
146
146
|
session: Record<string, any> & {
|
|
147
147
|
id: string;
|
|
@@ -167,10 +167,10 @@ declare const freshSessionMiddleware: (inputContext: better_call896.MiddlewareIn
|
|
|
167
167
|
/**
|
|
168
168
|
* user active sessions list
|
|
169
169
|
*/
|
|
170
|
-
declare const listSessions: <Option extends BetterAuthOptions>() =>
|
|
170
|
+
declare const listSessions: <Option extends BetterAuthOptions>() => better_call741.StrictEndpoint<"/list-sessions", {
|
|
171
171
|
method: "GET";
|
|
172
172
|
operationId: string;
|
|
173
|
-
use: ((inputContext:
|
|
173
|
+
use: ((inputContext: better_call741.MiddlewareInputContext<better_call741.MiddlewareOptions>) => Promise<{
|
|
174
174
|
session: {
|
|
175
175
|
session: Record<string, any> & {
|
|
176
176
|
id: string;
|
|
@@ -219,12 +219,12 @@ declare const listSessions: <Option extends BetterAuthOptions>() => better_call8
|
|
|
219
219
|
/**
|
|
220
220
|
* revoke a single session
|
|
221
221
|
*/
|
|
222
|
-
declare const revokeSession:
|
|
222
|
+
declare const revokeSession: better_call741.StrictEndpoint<"/revoke-session", {
|
|
223
223
|
method: "POST";
|
|
224
224
|
body: z.ZodObject<{
|
|
225
225
|
token: z.ZodString;
|
|
226
226
|
}, z.core.$strip>;
|
|
227
|
-
use: ((inputContext:
|
|
227
|
+
use: ((inputContext: better_call741.MiddlewareInputContext<better_call741.MiddlewareOptions>) => Promise<{
|
|
228
228
|
session: {
|
|
229
229
|
session: Record<string, any> & {
|
|
230
230
|
id: string;
|
|
@@ -294,9 +294,9 @@ declare const revokeSession: better_call896.StrictEndpoint<"/revoke-session", {
|
|
|
294
294
|
/**
|
|
295
295
|
* revoke all user sessions
|
|
296
296
|
*/
|
|
297
|
-
declare const revokeSessions:
|
|
297
|
+
declare const revokeSessions: better_call741.StrictEndpoint<"/revoke-sessions", {
|
|
298
298
|
method: "POST";
|
|
299
|
-
use: ((inputContext:
|
|
299
|
+
use: ((inputContext: better_call741.MiddlewareInputContext<better_call741.MiddlewareOptions>) => Promise<{
|
|
300
300
|
session: {
|
|
301
301
|
session: Record<string, any> & {
|
|
302
302
|
id: string;
|
|
@@ -347,10 +347,10 @@ declare const revokeSessions: better_call896.StrictEndpoint<"/revoke-sessions",
|
|
|
347
347
|
}, {
|
|
348
348
|
status: boolean;
|
|
349
349
|
}>;
|
|
350
|
-
declare const revokeOtherSessions:
|
|
350
|
+
declare const revokeOtherSessions: better_call741.StrictEndpoint<"/revoke-other-sessions", {
|
|
351
351
|
method: "POST";
|
|
352
352
|
requireHeaders: true;
|
|
353
|
-
use: ((inputContext:
|
|
353
|
+
use: ((inputContext: better_call741.MiddlewareInputContext<better_call741.MiddlewareOptions>) => Promise<{
|
|
354
354
|
session: {
|
|
355
355
|
session: Record<string, any> & {
|
|
356
356
|
id: string;
|
|
@@ -5,10 +5,9 @@ import { symmetricDecodeJWT, verifyJWT } from "../../crypto/jwt.mjs";
|
|
|
5
5
|
import "../../crypto/index.mjs";
|
|
6
6
|
import { getChunkedCookie, getSessionQuerySchema } from "../../cookies/session-store.mjs";
|
|
7
7
|
import { deleteSessionCookie, setCookieCache, setSessionCookie } from "../../cookies/index.mjs";
|
|
8
|
-
import { BASE_ERROR_CODES } from "@better-auth/core/error";
|
|
8
|
+
import { APIError, BASE_ERROR_CODES } from "@better-auth/core/error";
|
|
9
9
|
import { safeJSONParse } from "@better-auth/core/utils";
|
|
10
10
|
import * as z from "zod";
|
|
11
|
-
import { APIError } from "better-call";
|
|
12
11
|
import { createAuthEndpoint, createAuthMiddleware } from "@better-auth/core/api";
|
|
13
12
|
import { base64Url } from "@better-auth/utils/base64";
|
|
14
13
|
import { binary } from "@better-auth/utils/binary";
|
|
@@ -227,7 +226,7 @@ const getSession = () => createAuthEndpoint("/get-session", {
|
|
|
227
226
|
return ctx.json(session);
|
|
228
227
|
} catch (error) {
|
|
229
228
|
ctx.context.logger.error("INTERNAL_SERVER_ERROR", error);
|
|
230
|
-
throw
|
|
229
|
+
throw APIError.from("INTERNAL_SERVER_ERROR", BASE_ERROR_CODES.FAILED_TO_GET_SESSION);
|
|
231
230
|
}
|
|
232
231
|
});
|
|
233
232
|
const getSessionFromCtx = async (ctx, config) => {
|
|
@@ -253,7 +252,10 @@ const getSessionFromCtx = async (ctx, config) => {
|
|
|
253
252
|
*/
|
|
254
253
|
const sessionMiddleware = createAuthMiddleware(async (ctx) => {
|
|
255
254
|
const session = await getSessionFromCtx(ctx);
|
|
256
|
-
if (!session?.session) throw
|
|
255
|
+
if (!session?.session) throw APIError.from("UNAUTHORIZED", {
|
|
256
|
+
message: "Unauthorized",
|
|
257
|
+
code: "UNAUTHORIZED"
|
|
258
|
+
});
|
|
257
259
|
return { session };
|
|
258
260
|
});
|
|
259
261
|
/**
|
|
@@ -263,7 +265,10 @@ const sessionMiddleware = createAuthMiddleware(async (ctx) => {
|
|
|
263
265
|
*/
|
|
264
266
|
const sensitiveSessionMiddleware = createAuthMiddleware(async (ctx) => {
|
|
265
267
|
const session = await getSessionFromCtx(ctx, { disableCookieCache: true });
|
|
266
|
-
if (!session?.session) throw
|
|
268
|
+
if (!session?.session) throw APIError.from("UNAUTHORIZED", {
|
|
269
|
+
message: "Unauthorized",
|
|
270
|
+
code: "UNAUTHORIZED"
|
|
271
|
+
});
|
|
267
272
|
return { session };
|
|
268
273
|
});
|
|
269
274
|
/**
|
|
@@ -272,7 +277,10 @@ const sensitiveSessionMiddleware = createAuthMiddleware(async (ctx) => {
|
|
|
272
277
|
*/
|
|
273
278
|
const requestOnlySessionMiddleware = createAuthMiddleware(async (ctx) => {
|
|
274
279
|
const session = await getSessionFromCtx(ctx);
|
|
275
|
-
if (!session?.session && (ctx.request || ctx.headers)) throw
|
|
280
|
+
if (!session?.session && (ctx.request || ctx.headers)) throw APIError.from("UNAUTHORIZED", {
|
|
281
|
+
message: "Unauthorized",
|
|
282
|
+
code: "UNAUTHORIZED"
|
|
283
|
+
});
|
|
276
284
|
return { session };
|
|
277
285
|
});
|
|
278
286
|
/**
|
|
@@ -284,11 +292,14 @@ const requestOnlySessionMiddleware = createAuthMiddleware(async (ctx) => {
|
|
|
284
292
|
*/
|
|
285
293
|
const freshSessionMiddleware = createAuthMiddleware(async (ctx) => {
|
|
286
294
|
const session = await getSessionFromCtx(ctx);
|
|
287
|
-
if (!session?.session) throw
|
|
295
|
+
if (!session?.session) throw APIError.from("UNAUTHORIZED", {
|
|
296
|
+
message: "Unauthorized",
|
|
297
|
+
code: "UNAUTHORIZED"
|
|
298
|
+
});
|
|
288
299
|
if (ctx.context.sessionConfig.freshAge === 0) return { session };
|
|
289
300
|
const freshAge = ctx.context.sessionConfig.freshAge;
|
|
290
301
|
const lastUpdated = new Date(session.session.updatedAt || session.session.createdAt).getTime();
|
|
291
|
-
if (!(Date.now() - lastUpdated < freshAge * 1e3)) throw
|
|
302
|
+
if (!(Date.now() - lastUpdated < freshAge * 1e3)) throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.SESSION_NOT_FRESH);
|
|
292
303
|
return { session };
|
|
293
304
|
});
|
|
294
305
|
/**
|
|
@@ -357,7 +368,10 @@ const revokeSession = createAuthEndpoint("/revoke-session", {
|
|
|
357
368
|
await ctx.context.internalAdapter.deleteSession(token);
|
|
358
369
|
} catch (error) {
|
|
359
370
|
ctx.context.logger.error(error && typeof error === "object" && "name" in error ? error.name : "", error);
|
|
360
|
-
throw
|
|
371
|
+
throw APIError.from("INTERNAL_SERVER_ERROR", {
|
|
372
|
+
message: "Internal Server Error",
|
|
373
|
+
code: "INTERNAL_SERVER_ERROR"
|
|
374
|
+
});
|
|
361
375
|
}
|
|
362
376
|
return ctx.json({ status: true });
|
|
363
377
|
});
|
|
@@ -387,7 +401,10 @@ const revokeSessions = createAuthEndpoint("/revoke-sessions", {
|
|
|
387
401
|
await ctx.context.internalAdapter.deleteSessions(ctx.context.session.user.id);
|
|
388
402
|
} catch (error) {
|
|
389
403
|
ctx.context.logger.error(error && typeof error === "object" && "name" in error ? error.name : "", error);
|
|
390
|
-
throw
|
|
404
|
+
throw APIError.from("INTERNAL_SERVER_ERROR", {
|
|
405
|
+
message: "Internal Server Error",
|
|
406
|
+
code: "INTERNAL_SERVER_ERROR"
|
|
407
|
+
});
|
|
391
408
|
}
|
|
392
409
|
return ctx.json({ status: true });
|
|
393
410
|
});
|
|
@@ -411,7 +428,10 @@ const revokeOtherSessions = createAuthEndpoint("/revoke-other-sessions", {
|
|
|
411
428
|
} }
|
|
412
429
|
}, async (ctx) => {
|
|
413
430
|
const session = ctx.context.session;
|
|
414
|
-
if (!session.user) throw
|
|
431
|
+
if (!session.user) throw APIError.from("UNAUTHORIZED", {
|
|
432
|
+
message: "Unauthorized",
|
|
433
|
+
code: "UNAUTHORIZED"
|
|
434
|
+
});
|
|
415
435
|
const otherSessions = (await ctx.context.internalAdapter.listSessions(session.user.id)).filter((session$1) => {
|
|
416
436
|
return session$1.expiresAt > /* @__PURE__ */ new Date();
|
|
417
437
|
}).filter((session$1) => session$1.token !== ctx.context.session.session.token);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.mjs","names":["sessionDataPayload: {\n\t\t\t\t\tsession: {\n\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\tupdatedAt: number;\n\t\t\t\t\t\tversion?: string;\n\t\t\t\t\t};\n\t\t\t\t\texpiresAt: number;\n\t\t\t\t} | null","session","e: any"],"sources":["../../../src/api/routes/session.ts"],"sourcesContent":["import type {\n\tBetterAuthOptions,\n\tGenericEndpointContext,\n} from \"@better-auth/core\";\nimport {\n\tcreateAuthEndpoint,\n\tcreateAuthMiddleware,\n} from \"@better-auth/core/api\";\nimport { BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport { safeJSONParse } from \"@better-auth/core/utils\";\nimport { base64Url } from \"@better-auth/utils/base64\";\nimport { binary } from \"@better-auth/utils/binary\";\nimport { createHMAC } from \"@better-auth/utils/hmac\";\nimport { APIError } from \"better-call\";\nimport * as z from \"zod\";\nimport {\n\tdeleteSessionCookie,\n\tgetChunkedCookie,\n\tsetCookieCache,\n\tsetSessionCookie,\n} from \"../../cookies\";\nimport { getSessionQuerySchema } from \"../../cookies/session-store\";\nimport { symmetricDecodeJWT, verifyJWT } from \"../../crypto\";\nimport { parseSessionOutput, parseUserOutput } from \"../../db\";\nimport type { InferSession, InferUser, Session, User } from \"../../types\";\nimport type { Prettify } from \"../../types/helper\";\nimport { getDate } from \"../../utils/date\";\n\nexport const getSession = <Option extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/get-session\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\toperationId: \"getSession\",\n\t\t\tquery: getSessionQuerySchema,\n\t\t\trequireHeaders: true,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"getSession\",\n\t\t\t\t\tdescription: \"Get the current session\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/Session\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/User\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\trequired: [\"session\", \"user\"],\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tasync (\n\t\t\tctx,\n\t\t): Promise<{\n\t\t\tsession: InferSession<Option>;\n\t\t\tuser: InferUser<Option>;\n\t\t} | null> => {\n\t\t\ttry {\n\t\t\t\tconst sessionCookieToken = await ctx.getSignedCookie(\n\t\t\t\t\tctx.context.authCookies.sessionToken.name,\n\t\t\t\t\tctx.context.secret,\n\t\t\t\t);\n\n\t\t\t\tif (!sessionCookieToken) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst sessionDataCookie = getChunkedCookie(\n\t\t\t\t\tctx,\n\t\t\t\t\tctx.context.authCookies.sessionData.name,\n\t\t\t\t);\n\n\t\t\t\tlet sessionDataPayload: {\n\t\t\t\t\tsession: {\n\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\tupdatedAt: number;\n\t\t\t\t\t\tversion?: string;\n\t\t\t\t\t};\n\t\t\t\t\texpiresAt: number;\n\t\t\t\t} | null = null;\n\n\t\t\t\tif (sessionDataCookie) {\n\t\t\t\t\tconst strategy =\n\t\t\t\t\t\tctx.context.options.session?.cookieCache?.strategy || \"compact\";\n\n\t\t\t\t\tif (strategy === \"jwe\") {\n\t\t\t\t\t\t// Decode JWE (encrypted)\n\t\t\t\t\t\tconst payload = await symmetricDecodeJWT<{\n\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t\tupdatedAt: number;\n\t\t\t\t\t\t\tversion?: string;\n\t\t\t\t\t\t\texp?: number;\n\t\t\t\t\t\t}>(sessionDataCookie, ctx.context.secret, \"better-auth-session\");\n\n\t\t\t\t\t\tif (payload && payload.session && payload.user) {\n\t\t\t\t\t\t\tsessionDataPayload = {\n\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\tsession: payload.session,\n\t\t\t\t\t\t\t\t\tuser: payload.user,\n\t\t\t\t\t\t\t\t\tupdatedAt: payload.updatedAt,\n\t\t\t\t\t\t\t\t\tversion: payload.version,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\texpiresAt: payload.exp ? payload.exp * 1000 : Date.now(),\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst dataCookie = ctx.context.authCookies.sessionData.name;\n\t\t\t\t\t\t\tctx.setCookie(dataCookie, \"\", {\n\t\t\t\t\t\t\t\tmaxAge: 0,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\treturn ctx.json(null);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (strategy === \"jwt\") {\n\t\t\t\t\t\t// Decode JWT (signed with HMAC, not encrypted)\n\t\t\t\t\t\tconst payload = await verifyJWT<{\n\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t\tupdatedAt: number;\n\t\t\t\t\t\t\tversion?: string;\n\t\t\t\t\t\t\texp?: number;\n\t\t\t\t\t\t}>(sessionDataCookie, ctx.context.secret);\n\n\t\t\t\t\t\tif (payload && payload.session && payload.user) {\n\t\t\t\t\t\t\tsessionDataPayload = {\n\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\tsession: payload.session,\n\t\t\t\t\t\t\t\t\tuser: payload.user,\n\t\t\t\t\t\t\t\t\tupdatedAt: payload.updatedAt,\n\t\t\t\t\t\t\t\t\tversion: payload.version,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\texpiresAt: payload.exp ? payload.exp * 1000 : Date.now(),\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst dataCookie = ctx.context.authCookies.sessionData.name;\n\t\t\t\t\t\t\tctx.setCookie(dataCookie, \"\", {\n\t\t\t\t\t\t\t\tmaxAge: 0,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\treturn ctx.json(null);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Decode compact format (or legacy base64-hmac)\n\t\t\t\t\t\tconst parsed = safeJSONParse<{\n\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t\t\tupdatedAt: number;\n\t\t\t\t\t\t\t\tversion?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tsignature: string;\n\t\t\t\t\t\t\texpiresAt: number;\n\t\t\t\t\t\t}>(binary.decode(base64Url.decode(sessionDataCookie)));\n\n\t\t\t\t\t\tif (parsed) {\n\t\t\t\t\t\t\tconst isValid = await createHMAC(\n\t\t\t\t\t\t\t\t\"SHA-256\",\n\t\t\t\t\t\t\t\t\"base64urlnopad\",\n\t\t\t\t\t\t\t).verify(\n\t\t\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\t\t...parsed.session,\n\t\t\t\t\t\t\t\t\texpiresAt: parsed.expiresAt,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\tparsed.signature,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tif (isValid) {\n\t\t\t\t\t\t\t\tsessionDataPayload = parsed;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconst dataCookie = ctx.context.authCookies.sessionData.name;\n\t\t\t\t\t\t\t\tctx.setCookie(dataCookie, \"\", {\n\t\t\t\t\t\t\t\t\tmaxAge: 0,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\treturn ctx.json(null);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst dontRememberMe = await ctx.getSignedCookie(\n\t\t\t\t\tctx.context.authCookies.dontRememberToken.name,\n\t\t\t\t\tctx.context.secret,\n\t\t\t\t);\n\n\t\t\t\t/**\n\t\t\t\t * If session data is present in the cookie, check if it should be used or refreshed\n\t\t\t\t */\n\t\t\t\tif (\n\t\t\t\t\tsessionDataPayload?.session &&\n\t\t\t\t\tctx.context.options.session?.cookieCache?.enabled &&\n\t\t\t\t\t!ctx.query?.disableCookieCache\n\t\t\t\t) {\n\t\t\t\t\tconst session = sessionDataPayload.session;\n\n\t\t\t\t\tconst versionConfig =\n\t\t\t\t\t\tctx.context.options.session?.cookieCache?.version;\n\t\t\t\t\tlet expectedVersion = \"1\";\n\t\t\t\t\tif (versionConfig) {\n\t\t\t\t\t\tif (typeof versionConfig === \"string\") {\n\t\t\t\t\t\t\texpectedVersion = versionConfig;\n\t\t\t\t\t\t} else if (typeof versionConfig === \"function\") {\n\t\t\t\t\t\t\tconst result = versionConfig(session.session, session.user);\n\t\t\t\t\t\t\texpectedVersion =\n\t\t\t\t\t\t\t\tresult instanceof Promise ? await result : result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst cookieVersion = session.version || \"1\";\n\t\t\t\t\tif (cookieVersion !== expectedVersion) {\n\t\t\t\t\t\t// Version mismatch - invalidate the cookie cache\n\t\t\t\t\t\tconst dataCookie = ctx.context.authCookies.sessionData.name;\n\t\t\t\t\t\tctx.setCookie(dataCookie, \"\", {\n\t\t\t\t\t\t\tmaxAge: 0,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst cachedSessionExpiresAt = new Date(\n\t\t\t\t\t\t\tsession.session.expiresAt as unknown as string | number | Date,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst hasExpired =\n\t\t\t\t\t\t\tsessionDataPayload.expiresAt < Date.now() ||\n\t\t\t\t\t\t\tcachedSessionExpiresAt < new Date();\n\n\t\t\t\t\t\tif (hasExpired) {\n\t\t\t\t\t\t\t// When the session data cookie has expired, delete it;\n\t\t\t\t\t\t\t// then we try to fetch from DB\n\t\t\t\t\t\t\tconst dataCookie = ctx.context.authCookies.sessionData.name;\n\t\t\t\t\t\t\tctx.setCookie(dataCookie, \"\", {\n\t\t\t\t\t\t\t\tmaxAge: 0,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Check if the cookie cache needs to be refreshed based on refreshCache\n\t\t\t\t\t\t\tconst cookieRefreshCache =\n\t\t\t\t\t\t\t\tctx.context.sessionConfig.cookieRefreshCache;\n\n\t\t\t\t\t\t\tif (cookieRefreshCache === false) {\n\t\t\t\t\t\t\t\t// If refreshCache is disabled, return the session from cookie as-is\n\t\t\t\t\t\t\t\tctx.context.session = session;\n\t\t\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\t\t\tsession: session.session,\n\t\t\t\t\t\t\t\t\tuser: session.user,\n\t\t\t\t\t\t\t\t} as {\n\t\t\t\t\t\t\t\t\tsession: InferSession<Option>;\n\t\t\t\t\t\t\t\t\tuser: InferUser<Option>;\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst timeUntilExpiry = sessionDataPayload.expiresAt - Date.now();\n\t\t\t\t\t\t\tconst updateAge = cookieRefreshCache.updateAge * 1000; // Convert to milliseconds\n\n\t\t\t\t\t\t\tif (timeUntilExpiry < updateAge) {\n\t\t\t\t\t\t\t\tconst cookieMaxAge =\n\t\t\t\t\t\t\t\t\tctx.context.options.session?.cookieCache?.maxAge || 60 * 5;\n\t\t\t\t\t\t\t\tconst newExpiresAt = getDate(cookieMaxAge, \"sec\");\n\t\t\t\t\t\t\t\tconst refreshedSession = {\n\t\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\t\t...session.session,\n\t\t\t\t\t\t\t\t\t\texpiresAt: newExpiresAt,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tuser: session.user,\n\t\t\t\t\t\t\t\t\tupdatedAt: Date.now(),\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t// Set the refreshed cookie cache\n\t\t\t\t\t\t\t\tawait setCookieCache(ctx, refreshedSession, false);\n\n\t\t\t\t\t\t\t\t// Parse session and user to ensure additionalFields are included\n\t\t\t\t\t\t\t\t// Rehydrate date fields from JSON strings before parsing\n\t\t\t\t\t\t\t\tconst parsedRefreshedSession = parseSessionOutput(\n\t\t\t\t\t\t\t\t\tctx.context.options,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t...refreshedSession.session,\n\t\t\t\t\t\t\t\t\t\texpiresAt: new Date(refreshedSession.session.expiresAt),\n\t\t\t\t\t\t\t\t\t\tcreatedAt: new Date(refreshedSession.session.createdAt),\n\t\t\t\t\t\t\t\t\t\tupdatedAt: new Date(refreshedSession.session.updatedAt),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tconst parsedRefreshedUser = parseUserOutput(\n\t\t\t\t\t\t\t\t\tctx.context.options,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t...refreshedSession.user,\n\t\t\t\t\t\t\t\t\t\tcreatedAt: new Date(refreshedSession.user.createdAt),\n\t\t\t\t\t\t\t\t\t\tupdatedAt: new Date(refreshedSession.user.updatedAt),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tctx.context.session = {\n\t\t\t\t\t\t\t\t\tsession: parsedRefreshedSession,\n\t\t\t\t\t\t\t\t\tuser: parsedRefreshedUser,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\t\t\tsession: parsedRefreshedSession,\n\t\t\t\t\t\t\t\t\tuser: parsedRefreshedUser,\n\t\t\t\t\t\t\t\t} as {\n\t\t\t\t\t\t\t\t\tsession: InferSession<Option>;\n\t\t\t\t\t\t\t\t\tuser: InferUser<Option>;\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Parse session and user to ensure additionalFields are included\n\t\t\t\t\t\t\tconst parsedSession = parseSessionOutput(ctx.context.options, {\n\t\t\t\t\t\t\t\t...session.session,\n\t\t\t\t\t\t\t\texpiresAt: new Date(session.session.expiresAt),\n\t\t\t\t\t\t\t\tcreatedAt: new Date(session.session.createdAt),\n\t\t\t\t\t\t\t\tupdatedAt: new Date(session.session.updatedAt),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tconst parsedUser = parseUserOutput(ctx.context.options, {\n\t\t\t\t\t\t\t\t...session.user,\n\t\t\t\t\t\t\t\tcreatedAt: new Date(session.user.createdAt),\n\t\t\t\t\t\t\t\tupdatedAt: new Date(session.user.updatedAt),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tctx.context.session = {\n\t\t\t\t\t\t\t\tsession: parsedSession,\n\t\t\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\t\tsession: parsedSession,\n\t\t\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t\t\t} as {\n\t\t\t\t\t\t\t\tsession: InferSession<Option>;\n\t\t\t\t\t\t\t\tuser: InferUser<Option>;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst session =\n\t\t\t\t\tawait ctx.context.internalAdapter.findSession(sessionCookieToken);\n\t\t\t\tctx.context.session = session;\n\t\t\t\tif (!session || session.session.expiresAt < new Date()) {\n\t\t\t\t\tdeleteSessionCookie(ctx);\n\t\t\t\t\tif (session) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * if session expired clean up the session\n\t\t\t\t\t\t */\n\t\t\t\t\t\tawait ctx.context.internalAdapter.deleteSession(\n\t\t\t\t\t\t\tsession.session.token,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn ctx.json(null);\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * We don't need to update the session if the user doesn't want to be remembered\n\t\t\t\t * or if the session refresh is disabled\n\t\t\t\t */\n\t\t\t\tif (dontRememberMe || ctx.query?.disableRefresh) {\n\t\t\t\t\t// Parse session and user to ensure additionalFields are included\n\t\t\t\t\tconst parsedSession = parseSessionOutput(\n\t\t\t\t\t\tctx.context.options,\n\t\t\t\t\t\tsession.session,\n\t\t\t\t\t);\n\t\t\t\t\tconst parsedUser = parseUserOutput(ctx.context.options, session.user);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tsession: parsedSession,\n\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t} as {\n\t\t\t\t\t\tsession: InferSession<Option>;\n\t\t\t\t\t\tuser: InferUser<Option>;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst expiresIn = ctx.context.sessionConfig.expiresIn;\n\t\t\t\tconst updateAge = ctx.context.sessionConfig.updateAge;\n\t\t\t\t/**\n\t\t\t\t * Calculate last updated date to throttle write updates to database\n\t\t\t\t * Formula: ({expiry date} - sessionMaxAge) + sessionUpdateAge\n\t\t\t\t *\n\t\t\t\t * e.g. ({expiry date} - 30 days) + 1 hour\n\t\t\t\t *\n\t\t\t\t * inspired by: https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/lib/actions/session.ts\n\t\t\t\t */\n\t\t\t\tconst sessionIsDueToBeUpdatedDate =\n\t\t\t\t\tsession.session.expiresAt.valueOf() -\n\t\t\t\t\texpiresIn * 1000 +\n\t\t\t\t\tupdateAge * 1000;\n\t\t\t\tconst shouldBeUpdated = sessionIsDueToBeUpdatedDate <= Date.now();\n\n\t\t\t\tif (\n\t\t\t\t\tshouldBeUpdated &&\n\t\t\t\t\t(!ctx.query?.disableRefresh ||\n\t\t\t\t\t\t!ctx.context.options.session?.disableSessionRefresh)\n\t\t\t\t) {\n\t\t\t\t\tconst updatedSession =\n\t\t\t\t\t\tawait ctx.context.internalAdapter.updateSession(\n\t\t\t\t\t\t\tsession.session.token,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\texpiresAt: getDate(ctx.context.sessionConfig.expiresIn, \"sec\"),\n\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\tif (!updatedSession) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Handle case where session update fails (e.g., concurrent deletion)\n\t\t\t\t\t\t */\n\t\t\t\t\t\tdeleteSessionCookie(ctx);\n\t\t\t\t\t\treturn ctx.json(null, { status: 401 });\n\t\t\t\t\t}\n\t\t\t\t\tconst maxAge =\n\t\t\t\t\t\t(updatedSession.expiresAt.valueOf() - Date.now()) / 1000;\n\t\t\t\t\tawait setSessionCookie(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsession: updatedSession,\n\t\t\t\t\t\t\tuser: session.user,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmaxAge,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\n\t\t\t\t\t// Parse session and user to ensure additionalFields are included\n\t\t\t\t\tconst parsedUpdatedSession = parseSessionOutput(\n\t\t\t\t\t\tctx.context.options,\n\t\t\t\t\t\tupdatedSession,\n\t\t\t\t\t);\n\t\t\t\t\tconst parsedUser = parseUserOutput(ctx.context.options, session.user);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tsession: parsedUpdatedSession,\n\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t} as unknown as {\n\t\t\t\t\t\tsession: InferSession<Option>;\n\t\t\t\t\t\tuser: InferUser<Option>;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tawait setCookieCache(ctx, session, !!dontRememberMe);\n\t\t\t\treturn ctx.json(\n\t\t\t\t\tsession as unknown as {\n\t\t\t\t\t\tsession: InferSession<Option>;\n\t\t\t\t\t\tuser: InferUser<Option>;\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tctx.context.logger.error(\"INTERNAL_SERVER_ERROR\", error);\n\t\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\t\tmessage: BASE_ERROR_CODES.FAILED_TO_GET_SESSION,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t);\n\nexport const getSessionFromCtx = async <\n\tU extends Record<string, any> = Record<string, any>,\n\tS extends Record<string, any> = Record<string, any>,\n>(\n\tctx: GenericEndpointContext,\n\tconfig?:\n\t\t| {\n\t\t\t\tdisableCookieCache?: boolean;\n\t\t\t\tdisableRefresh?: boolean;\n\t\t }\n\t\t| undefined,\n) => {\n\tif (ctx.context.session) {\n\t\treturn ctx.context.session as {\n\t\t\tsession: S & Session;\n\t\t\tuser: U & User;\n\t\t};\n\t}\n\n\tconst session = await getSession()({\n\t\t...ctx,\n\t\tasResponse: false,\n\t\theaders: ctx.headers!,\n\t\treturnHeaders: false,\n\t\treturnStatus: false,\n\t\tquery: {\n\t\t\t...config,\n\t\t\t...ctx.query,\n\t\t},\n\t}).catch((e) => {\n\t\treturn null;\n\t});\n\tctx.context.session = session;\n\treturn session as {\n\t\tsession: S & Session;\n\t\tuser: U & User;\n\t} | null;\n};\n\n/**\n * The middleware forces the endpoint to require a valid session.\n */\nexport const sessionMiddleware = createAuthMiddleware(async (ctx) => {\n\tconst session = await getSessionFromCtx(ctx);\n\tif (!session?.session) {\n\t\tthrow new APIError(\"UNAUTHORIZED\");\n\t}\n\treturn {\n\t\tsession,\n\t};\n});\n\n/**\n * This middleware forces the endpoint to require a valid session and ignores cookie cache.\n * This should be used for sensitive operations like password changes, account deletion, etc.\n * to ensure that revoked sessions cannot be used even if they're still cached in cookies.\n */\nexport const sensitiveSessionMiddleware = createAuthMiddleware(async (ctx) => {\n\tconst session = await getSessionFromCtx(ctx, { disableCookieCache: true });\n\tif (!session?.session) {\n\t\tthrow new APIError(\"UNAUTHORIZED\");\n\t}\n\treturn {\n\t\tsession,\n\t};\n});\n\n/**\n * This middleware allows you to call the endpoint on the client if session is valid.\n * However, if called on the server, no session is required.\n */\nexport const requestOnlySessionMiddleware = createAuthMiddleware(\n\tasync (ctx) => {\n\t\tconst session = await getSessionFromCtx(ctx);\n\t\tif (!session?.session && (ctx.request || ctx.headers)) {\n\t\t\tthrow new APIError(\"UNAUTHORIZED\");\n\t\t}\n\t\treturn { session };\n\t},\n);\n\n/**\n * This middleware forces the endpoint to require a valid session,\n * as well as making sure the session is fresh before proceeding.\n *\n * Session freshness check will be skipped if the session config's freshAge\n * is set to 0\n */\nexport const freshSessionMiddleware = createAuthMiddleware(async (ctx) => {\n\tconst session = await getSessionFromCtx(ctx);\n\tif (!session?.session) {\n\t\tthrow new APIError(\"UNAUTHORIZED\");\n\t}\n\tif (ctx.context.sessionConfig.freshAge === 0) {\n\t\treturn {\n\t\t\tsession,\n\t\t};\n\t}\n\tconst freshAge = ctx.context.sessionConfig.freshAge;\n\tconst lastUpdated = new Date(\n\t\tsession.session.updatedAt || session.session.createdAt,\n\t).getTime();\n\tconst now = Date.now();\n\tconst isFresh = now - lastUpdated < freshAge * 1000;\n\tif (!isFresh) {\n\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\tmessage: \"Session is not fresh\",\n\t\t});\n\t}\n\treturn {\n\t\tsession,\n\t};\n});\n/**\n * user active sessions list\n */\nexport const listSessions = <Option extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/list-sessions\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\toperationId: \"listUserSessions\",\n\t\t\tuse: [sessionMiddleware],\n\t\t\trequireHeaders: true,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"listUserSessions\",\n\t\t\t\t\tdescription: \"List all active sessions for the user\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/Session\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tasync (ctx) => {\n\t\t\ttry {\n\t\t\t\tconst sessions = await ctx.context.internalAdapter.listSessions(\n\t\t\t\t\tctx.context.session.user.id,\n\t\t\t\t);\n\t\t\t\tconst activeSessions = sessions.filter((session) => {\n\t\t\t\t\treturn session.expiresAt > new Date();\n\t\t\t\t});\n\t\t\t\treturn ctx.json(\n\t\t\t\t\tactiveSessions as unknown as Prettify<InferSession<Option>>[],\n\t\t\t\t);\n\t\t\t} catch (e: any) {\n\t\t\t\tctx.context.logger.error(e);\n\t\t\t\tthrow ctx.error(\"INTERNAL_SERVER_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n/**\n * revoke a single session\n */\nexport const revokeSession = createAuthEndpoint(\n\t\"/revoke-session\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\ttoken: z.string().meta({\n\t\t\t\tdescription: \"The token to revoke\",\n\t\t\t}),\n\t\t}),\n\t\tuse: [sensitiveSessionMiddleware],\n\t\trequireHeaders: true,\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\tdescription: \"Revoke a single session\",\n\t\t\t\trequestBody: {\n\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\tdescription: \"The token to revoke\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\trequired: [\"token\"],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\t\"Indicates if the session was revoked successfully\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"status\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst token = ctx.body.token;\n\t\tconst session = await ctx.context.internalAdapter.findSession(token);\n\n\t\tif (session?.session.userId === ctx.context.session.user.id) {\n\t\t\ttry {\n\t\t\t\tawait ctx.context.internalAdapter.deleteSession(token);\n\t\t\t} catch (error) {\n\t\t\t\tctx.context.logger.error(\n\t\t\t\t\terror && typeof error === \"object\" && \"name\" in error\n\t\t\t\t\t\t? (error.name as string)\n\t\t\t\t\t\t: \"\",\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\");\n\t\t\t}\n\t\t}\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n/**\n * revoke all user sessions\n */\nexport const revokeSessions = createAuthEndpoint(\n\t\"/revoke-sessions\",\n\t{\n\t\tmethod: \"POST\",\n\t\tuse: [sensitiveSessionMiddleware],\n\t\trequireHeaders: true,\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\tdescription: \"Revoke all sessions for the user\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\t\"Indicates if all sessions were revoked successfully\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"status\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\ttry {\n\t\t\tawait ctx.context.internalAdapter.deleteSessions(\n\t\t\t\tctx.context.session.user.id,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tctx.context.logger.error(\n\t\t\t\terror && typeof error === \"object\" && \"name\" in error\n\t\t\t\t\t? (error.name as string)\n\t\t\t\t\t: \"\",\n\t\t\t\terror,\n\t\t\t);\n\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\");\n\t\t}\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n\nexport const revokeOtherSessions = createAuthEndpoint(\n\t\"/revoke-other-sessions\",\n\t{\n\t\tmethod: \"POST\",\n\t\trequireHeaders: true,\n\t\tuse: [sensitiveSessionMiddleware],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\tdescription:\n\t\t\t\t\t\"Revoke all other sessions for the user except the current one\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\t\"Indicates if all other sessions were revoked successfully\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"status\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst session = ctx.context.session;\n\t\tif (!session.user) {\n\t\t\tthrow new APIError(\"UNAUTHORIZED\");\n\t\t}\n\t\tconst sessions = await ctx.context.internalAdapter.listSessions(\n\t\t\tsession.user.id,\n\t\t);\n\t\tconst activeSessions = sessions.filter((session) => {\n\t\t\treturn session.expiresAt > new Date();\n\t\t});\n\t\tconst otherSessions = activeSessions.filter(\n\t\t\t(session) => session.token !== ctx.context.session.session.token,\n\t\t);\n\t\tawait Promise.all(\n\t\t\totherSessions.map((session) =>\n\t\t\t\tctx.context.internalAdapter.deleteSession(session.token),\n\t\t\t),\n\t\t);\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"session.mjs","names":["sessionDataPayload: {\n\t\t\t\t\tsession: {\n\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\tupdatedAt: number;\n\t\t\t\t\t\tversion?: string;\n\t\t\t\t\t};\n\t\t\t\t\texpiresAt: number;\n\t\t\t\t} | null","session","e: any"],"sources":["../../../src/api/routes/session.ts"],"sourcesContent":["import type {\n\tBetterAuthOptions,\n\tGenericEndpointContext,\n} from \"@better-auth/core\";\nimport {\n\tcreateAuthEndpoint,\n\tcreateAuthMiddleware,\n} from \"@better-auth/core/api\";\nimport { APIError, BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport { safeJSONParse } from \"@better-auth/core/utils\";\nimport { base64Url } from \"@better-auth/utils/base64\";\nimport { binary } from \"@better-auth/utils/binary\";\nimport { createHMAC } from \"@better-auth/utils/hmac\";\n\nimport * as z from \"zod\";\nimport {\n\tdeleteSessionCookie,\n\tgetChunkedCookie,\n\tsetCookieCache,\n\tsetSessionCookie,\n} from \"../../cookies\";\nimport { getSessionQuerySchema } from \"../../cookies/session-store\";\nimport { symmetricDecodeJWT, verifyJWT } from \"../../crypto\";\nimport { parseSessionOutput, parseUserOutput } from \"../../db\";\nimport type { InferSession, InferUser, Session, User } from \"../../types\";\nimport type { Prettify } from \"../../types/helper\";\nimport { getDate } from \"../../utils/date\";\n\nexport const getSession = <Option extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/get-session\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\toperationId: \"getSession\",\n\t\t\tquery: getSessionQuerySchema,\n\t\t\trequireHeaders: true,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"getSession\",\n\t\t\t\t\tdescription: \"Get the current session\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/Session\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/User\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\trequired: [\"session\", \"user\"],\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tasync (\n\t\t\tctx,\n\t\t): Promise<{\n\t\t\tsession: InferSession<Option>;\n\t\t\tuser: InferUser<Option>;\n\t\t} | null> => {\n\t\t\ttry {\n\t\t\t\tconst sessionCookieToken = await ctx.getSignedCookie(\n\t\t\t\t\tctx.context.authCookies.sessionToken.name,\n\t\t\t\t\tctx.context.secret,\n\t\t\t\t);\n\n\t\t\t\tif (!sessionCookieToken) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst sessionDataCookie = getChunkedCookie(\n\t\t\t\t\tctx,\n\t\t\t\t\tctx.context.authCookies.sessionData.name,\n\t\t\t\t);\n\n\t\t\t\tlet sessionDataPayload: {\n\t\t\t\t\tsession: {\n\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\tupdatedAt: number;\n\t\t\t\t\t\tversion?: string;\n\t\t\t\t\t};\n\t\t\t\t\texpiresAt: number;\n\t\t\t\t} | null = null;\n\n\t\t\t\tif (sessionDataCookie) {\n\t\t\t\t\tconst strategy =\n\t\t\t\t\t\tctx.context.options.session?.cookieCache?.strategy || \"compact\";\n\n\t\t\t\t\tif (strategy === \"jwe\") {\n\t\t\t\t\t\t// Decode JWE (encrypted)\n\t\t\t\t\t\tconst payload = await symmetricDecodeJWT<{\n\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t\tupdatedAt: number;\n\t\t\t\t\t\t\tversion?: string;\n\t\t\t\t\t\t\texp?: number;\n\t\t\t\t\t\t}>(sessionDataCookie, ctx.context.secret, \"better-auth-session\");\n\n\t\t\t\t\t\tif (payload && payload.session && payload.user) {\n\t\t\t\t\t\t\tsessionDataPayload = {\n\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\tsession: payload.session,\n\t\t\t\t\t\t\t\t\tuser: payload.user,\n\t\t\t\t\t\t\t\t\tupdatedAt: payload.updatedAt,\n\t\t\t\t\t\t\t\t\tversion: payload.version,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\texpiresAt: payload.exp ? payload.exp * 1000 : Date.now(),\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst dataCookie = ctx.context.authCookies.sessionData.name;\n\t\t\t\t\t\t\tctx.setCookie(dataCookie, \"\", {\n\t\t\t\t\t\t\t\tmaxAge: 0,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\treturn ctx.json(null);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (strategy === \"jwt\") {\n\t\t\t\t\t\t// Decode JWT (signed with HMAC, not encrypted)\n\t\t\t\t\t\tconst payload = await verifyJWT<{\n\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t\tupdatedAt: number;\n\t\t\t\t\t\t\tversion?: string;\n\t\t\t\t\t\t\texp?: number;\n\t\t\t\t\t\t}>(sessionDataCookie, ctx.context.secret);\n\n\t\t\t\t\t\tif (payload && payload.session && payload.user) {\n\t\t\t\t\t\t\tsessionDataPayload = {\n\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\tsession: payload.session,\n\t\t\t\t\t\t\t\t\tuser: payload.user,\n\t\t\t\t\t\t\t\t\tupdatedAt: payload.updatedAt,\n\t\t\t\t\t\t\t\t\tversion: payload.version,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\texpiresAt: payload.exp ? payload.exp * 1000 : Date.now(),\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst dataCookie = ctx.context.authCookies.sessionData.name;\n\t\t\t\t\t\t\tctx.setCookie(dataCookie, \"\", {\n\t\t\t\t\t\t\t\tmaxAge: 0,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\treturn ctx.json(null);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Decode compact format (or legacy base64-hmac)\n\t\t\t\t\t\tconst parsed = safeJSONParse<{\n\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t\t\tupdatedAt: number;\n\t\t\t\t\t\t\t\tversion?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tsignature: string;\n\t\t\t\t\t\t\texpiresAt: number;\n\t\t\t\t\t\t}>(binary.decode(base64Url.decode(sessionDataCookie)));\n\n\t\t\t\t\t\tif (parsed) {\n\t\t\t\t\t\t\tconst isValid = await createHMAC(\n\t\t\t\t\t\t\t\t\"SHA-256\",\n\t\t\t\t\t\t\t\t\"base64urlnopad\",\n\t\t\t\t\t\t\t).verify(\n\t\t\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\t\t...parsed.session,\n\t\t\t\t\t\t\t\t\texpiresAt: parsed.expiresAt,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\tparsed.signature,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tif (isValid) {\n\t\t\t\t\t\t\t\tsessionDataPayload = parsed;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconst dataCookie = ctx.context.authCookies.sessionData.name;\n\t\t\t\t\t\t\t\tctx.setCookie(dataCookie, \"\", {\n\t\t\t\t\t\t\t\t\tmaxAge: 0,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\treturn ctx.json(null);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst dontRememberMe = await ctx.getSignedCookie(\n\t\t\t\t\tctx.context.authCookies.dontRememberToken.name,\n\t\t\t\t\tctx.context.secret,\n\t\t\t\t);\n\n\t\t\t\t/**\n\t\t\t\t * If session data is present in the cookie, check if it should be used or refreshed\n\t\t\t\t */\n\t\t\t\tif (\n\t\t\t\t\tsessionDataPayload?.session &&\n\t\t\t\t\tctx.context.options.session?.cookieCache?.enabled &&\n\t\t\t\t\t!ctx.query?.disableCookieCache\n\t\t\t\t) {\n\t\t\t\t\tconst session = sessionDataPayload.session;\n\n\t\t\t\t\tconst versionConfig =\n\t\t\t\t\t\tctx.context.options.session?.cookieCache?.version;\n\t\t\t\t\tlet expectedVersion = \"1\";\n\t\t\t\t\tif (versionConfig) {\n\t\t\t\t\t\tif (typeof versionConfig === \"string\") {\n\t\t\t\t\t\t\texpectedVersion = versionConfig;\n\t\t\t\t\t\t} else if (typeof versionConfig === \"function\") {\n\t\t\t\t\t\t\tconst result = versionConfig(session.session, session.user);\n\t\t\t\t\t\t\texpectedVersion =\n\t\t\t\t\t\t\t\tresult instanceof Promise ? await result : result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst cookieVersion = session.version || \"1\";\n\t\t\t\t\tif (cookieVersion !== expectedVersion) {\n\t\t\t\t\t\t// Version mismatch - invalidate the cookie cache\n\t\t\t\t\t\tconst dataCookie = ctx.context.authCookies.sessionData.name;\n\t\t\t\t\t\tctx.setCookie(dataCookie, \"\", {\n\t\t\t\t\t\t\tmaxAge: 0,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst cachedSessionExpiresAt = new Date(\n\t\t\t\t\t\t\tsession.session.expiresAt as unknown as string | number | Date,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst hasExpired =\n\t\t\t\t\t\t\tsessionDataPayload.expiresAt < Date.now() ||\n\t\t\t\t\t\t\tcachedSessionExpiresAt < new Date();\n\n\t\t\t\t\t\tif (hasExpired) {\n\t\t\t\t\t\t\t// When the session data cookie has expired, delete it;\n\t\t\t\t\t\t\t// then we try to fetch from DB\n\t\t\t\t\t\t\tconst dataCookie = ctx.context.authCookies.sessionData.name;\n\t\t\t\t\t\t\tctx.setCookie(dataCookie, \"\", {\n\t\t\t\t\t\t\t\tmaxAge: 0,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Check if the cookie cache needs to be refreshed based on refreshCache\n\t\t\t\t\t\t\tconst cookieRefreshCache =\n\t\t\t\t\t\t\t\tctx.context.sessionConfig.cookieRefreshCache;\n\n\t\t\t\t\t\t\tif (cookieRefreshCache === false) {\n\t\t\t\t\t\t\t\t// If refreshCache is disabled, return the session from cookie as-is\n\t\t\t\t\t\t\t\tctx.context.session = session;\n\t\t\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\t\t\tsession: session.session,\n\t\t\t\t\t\t\t\t\tuser: session.user,\n\t\t\t\t\t\t\t\t} as {\n\t\t\t\t\t\t\t\t\tsession: InferSession<Option>;\n\t\t\t\t\t\t\t\t\tuser: InferUser<Option>;\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst timeUntilExpiry = sessionDataPayload.expiresAt - Date.now();\n\t\t\t\t\t\t\tconst updateAge = cookieRefreshCache.updateAge * 1000; // Convert to milliseconds\n\n\t\t\t\t\t\t\tif (timeUntilExpiry < updateAge) {\n\t\t\t\t\t\t\t\tconst cookieMaxAge =\n\t\t\t\t\t\t\t\t\tctx.context.options.session?.cookieCache?.maxAge || 60 * 5;\n\t\t\t\t\t\t\t\tconst newExpiresAt = getDate(cookieMaxAge, \"sec\");\n\t\t\t\t\t\t\t\tconst refreshedSession = {\n\t\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\t\t...session.session,\n\t\t\t\t\t\t\t\t\t\texpiresAt: newExpiresAt,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tuser: session.user,\n\t\t\t\t\t\t\t\t\tupdatedAt: Date.now(),\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t// Set the refreshed cookie cache\n\t\t\t\t\t\t\t\tawait setCookieCache(ctx, refreshedSession, false);\n\n\t\t\t\t\t\t\t\t// Parse session and user to ensure additionalFields are included\n\t\t\t\t\t\t\t\t// Rehydrate date fields from JSON strings before parsing\n\t\t\t\t\t\t\t\tconst parsedRefreshedSession = parseSessionOutput(\n\t\t\t\t\t\t\t\t\tctx.context.options,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t...refreshedSession.session,\n\t\t\t\t\t\t\t\t\t\texpiresAt: new Date(refreshedSession.session.expiresAt),\n\t\t\t\t\t\t\t\t\t\tcreatedAt: new Date(refreshedSession.session.createdAt),\n\t\t\t\t\t\t\t\t\t\tupdatedAt: new Date(refreshedSession.session.updatedAt),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tconst parsedRefreshedUser = parseUserOutput(\n\t\t\t\t\t\t\t\t\tctx.context.options,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t...refreshedSession.user,\n\t\t\t\t\t\t\t\t\t\tcreatedAt: new Date(refreshedSession.user.createdAt),\n\t\t\t\t\t\t\t\t\t\tupdatedAt: new Date(refreshedSession.user.updatedAt),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tctx.context.session = {\n\t\t\t\t\t\t\t\t\tsession: parsedRefreshedSession,\n\t\t\t\t\t\t\t\t\tuser: parsedRefreshedUser,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\t\t\tsession: parsedRefreshedSession,\n\t\t\t\t\t\t\t\t\tuser: parsedRefreshedUser,\n\t\t\t\t\t\t\t\t} as {\n\t\t\t\t\t\t\t\t\tsession: InferSession<Option>;\n\t\t\t\t\t\t\t\t\tuser: InferUser<Option>;\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Parse session and user to ensure additionalFields are included\n\t\t\t\t\t\t\tconst parsedSession = parseSessionOutput(ctx.context.options, {\n\t\t\t\t\t\t\t\t...session.session,\n\t\t\t\t\t\t\t\texpiresAt: new Date(session.session.expiresAt),\n\t\t\t\t\t\t\t\tcreatedAt: new Date(session.session.createdAt),\n\t\t\t\t\t\t\t\tupdatedAt: new Date(session.session.updatedAt),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tconst parsedUser = parseUserOutput(ctx.context.options, {\n\t\t\t\t\t\t\t\t...session.user,\n\t\t\t\t\t\t\t\tcreatedAt: new Date(session.user.createdAt),\n\t\t\t\t\t\t\t\tupdatedAt: new Date(session.user.updatedAt),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tctx.context.session = {\n\t\t\t\t\t\t\t\tsession: parsedSession,\n\t\t\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\t\tsession: parsedSession,\n\t\t\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t\t\t} as {\n\t\t\t\t\t\t\t\tsession: InferSession<Option>;\n\t\t\t\t\t\t\t\tuser: InferUser<Option>;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst session =\n\t\t\t\t\tawait ctx.context.internalAdapter.findSession(sessionCookieToken);\n\t\t\t\tctx.context.session = session;\n\t\t\t\tif (!session || session.session.expiresAt < new Date()) {\n\t\t\t\t\tdeleteSessionCookie(ctx);\n\t\t\t\t\tif (session) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * if session expired clean up the session\n\t\t\t\t\t\t */\n\t\t\t\t\t\tawait ctx.context.internalAdapter.deleteSession(\n\t\t\t\t\t\t\tsession.session.token,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn ctx.json(null);\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * We don't need to update the session if the user doesn't want to be remembered\n\t\t\t\t * or if the session refresh is disabled\n\t\t\t\t */\n\t\t\t\tif (dontRememberMe || ctx.query?.disableRefresh) {\n\t\t\t\t\t// Parse session and user to ensure additionalFields are included\n\t\t\t\t\tconst parsedSession = parseSessionOutput(\n\t\t\t\t\t\tctx.context.options,\n\t\t\t\t\t\tsession.session,\n\t\t\t\t\t);\n\t\t\t\t\tconst parsedUser = parseUserOutput(ctx.context.options, session.user);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tsession: parsedSession,\n\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t} as {\n\t\t\t\t\t\tsession: InferSession<Option>;\n\t\t\t\t\t\tuser: InferUser<Option>;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst expiresIn = ctx.context.sessionConfig.expiresIn;\n\t\t\t\tconst updateAge = ctx.context.sessionConfig.updateAge;\n\t\t\t\t/**\n\t\t\t\t * Calculate last updated date to throttle write updates to database\n\t\t\t\t * Formula: ({expiry date} - sessionMaxAge) + sessionUpdateAge\n\t\t\t\t *\n\t\t\t\t * e.g. ({expiry date} - 30 days) + 1 hour\n\t\t\t\t *\n\t\t\t\t * inspired by: https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/lib/actions/session.ts\n\t\t\t\t */\n\t\t\t\tconst sessionIsDueToBeUpdatedDate =\n\t\t\t\t\tsession.session.expiresAt.valueOf() -\n\t\t\t\t\texpiresIn * 1000 +\n\t\t\t\t\tupdateAge * 1000;\n\t\t\t\tconst shouldBeUpdated = sessionIsDueToBeUpdatedDate <= Date.now();\n\n\t\t\t\tif (\n\t\t\t\t\tshouldBeUpdated &&\n\t\t\t\t\t(!ctx.query?.disableRefresh ||\n\t\t\t\t\t\t!ctx.context.options.session?.disableSessionRefresh)\n\t\t\t\t) {\n\t\t\t\t\tconst updatedSession =\n\t\t\t\t\t\tawait ctx.context.internalAdapter.updateSession(\n\t\t\t\t\t\t\tsession.session.token,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\texpiresAt: getDate(ctx.context.sessionConfig.expiresIn, \"sec\"),\n\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\tif (!updatedSession) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Handle case where session update fails (e.g., concurrent deletion)\n\t\t\t\t\t\t */\n\t\t\t\t\t\tdeleteSessionCookie(ctx);\n\t\t\t\t\t\treturn ctx.json(null, { status: 401 });\n\t\t\t\t\t}\n\t\t\t\t\tconst maxAge =\n\t\t\t\t\t\t(updatedSession.expiresAt.valueOf() - Date.now()) / 1000;\n\t\t\t\t\tawait setSessionCookie(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsession: updatedSession,\n\t\t\t\t\t\t\tuser: session.user,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmaxAge,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\n\t\t\t\t\t// Parse session and user to ensure additionalFields are included\n\t\t\t\t\tconst parsedUpdatedSession = parseSessionOutput(\n\t\t\t\t\t\tctx.context.options,\n\t\t\t\t\t\tupdatedSession,\n\t\t\t\t\t);\n\t\t\t\t\tconst parsedUser = parseUserOutput(ctx.context.options, session.user);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tsession: parsedUpdatedSession,\n\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t} as unknown as {\n\t\t\t\t\t\tsession: InferSession<Option>;\n\t\t\t\t\t\tuser: InferUser<Option>;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tawait setCookieCache(ctx, session, !!dontRememberMe);\n\t\t\t\treturn ctx.json(\n\t\t\t\t\tsession as unknown as {\n\t\t\t\t\t\tsession: InferSession<Option>;\n\t\t\t\t\t\tuser: InferUser<Option>;\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tctx.context.logger.error(\"INTERNAL_SERVER_ERROR\", error);\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"INTERNAL_SERVER_ERROR\",\n\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_GET_SESSION,\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t);\n\nexport const getSessionFromCtx = async <\n\tU extends Record<string, any> = Record<string, any>,\n\tS extends Record<string, any> = Record<string, any>,\n>(\n\tctx: GenericEndpointContext,\n\tconfig?:\n\t\t| {\n\t\t\t\tdisableCookieCache?: boolean;\n\t\t\t\tdisableRefresh?: boolean;\n\t\t }\n\t\t| undefined,\n) => {\n\tif (ctx.context.session) {\n\t\treturn ctx.context.session as {\n\t\t\tsession: S & Session;\n\t\t\tuser: U & User;\n\t\t};\n\t}\n\n\tconst session = await getSession()({\n\t\t...ctx,\n\t\tasResponse: false,\n\t\theaders: ctx.headers!,\n\t\treturnHeaders: false,\n\t\treturnStatus: false,\n\t\tquery: {\n\t\t\t...config,\n\t\t\t...ctx.query,\n\t\t},\n\t}).catch((e) => {\n\t\treturn null;\n\t});\n\tctx.context.session = session;\n\treturn session as {\n\t\tsession: S & Session;\n\t\tuser: U & User;\n\t} | null;\n};\n\n/**\n * The middleware forces the endpoint to require a valid session.\n */\nexport const sessionMiddleware = createAuthMiddleware(async (ctx) => {\n\tconst session = await getSessionFromCtx(ctx);\n\tif (!session?.session) {\n\t\tthrow APIError.from(\"UNAUTHORIZED\", {\n\t\t\tmessage: \"Unauthorized\",\n\t\t\tcode: \"UNAUTHORIZED\",\n\t\t});\n\t}\n\treturn {\n\t\tsession,\n\t};\n});\n\n/**\n * This middleware forces the endpoint to require a valid session and ignores cookie cache.\n * This should be used for sensitive operations like password changes, account deletion, etc.\n * to ensure that revoked sessions cannot be used even if they're still cached in cookies.\n */\nexport const sensitiveSessionMiddleware = createAuthMiddleware(async (ctx) => {\n\tconst session = await getSessionFromCtx(ctx, { disableCookieCache: true });\n\tif (!session?.session) {\n\t\tthrow APIError.from(\"UNAUTHORIZED\", {\n\t\t\tmessage: \"Unauthorized\",\n\t\t\tcode: \"UNAUTHORIZED\",\n\t\t});\n\t}\n\treturn {\n\t\tsession,\n\t};\n});\n\n/**\n * This middleware allows you to call the endpoint on the client if session is valid.\n * However, if called on the server, no session is required.\n */\nexport const requestOnlySessionMiddleware = createAuthMiddleware(\n\tasync (ctx) => {\n\t\tconst session = await getSessionFromCtx(ctx);\n\t\tif (!session?.session && (ctx.request || ctx.headers)) {\n\t\t\tthrow APIError.from(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"Unauthorized\",\n\t\t\t\tcode: \"UNAUTHORIZED\",\n\t\t\t});\n\t\t}\n\t\treturn { session };\n\t},\n);\n\n/**\n * This middleware forces the endpoint to require a valid session,\n * as well as making sure the session is fresh before proceeding.\n *\n * Session freshness check will be skipped if the session config's freshAge\n * is set to 0\n */\nexport const freshSessionMiddleware = createAuthMiddleware(async (ctx) => {\n\tconst session = await getSessionFromCtx(ctx);\n\tif (!session?.session) {\n\t\tthrow APIError.from(\"UNAUTHORIZED\", {\n\t\t\tmessage: \"Unauthorized\",\n\t\t\tcode: \"UNAUTHORIZED\",\n\t\t});\n\t}\n\tif (ctx.context.sessionConfig.freshAge === 0) {\n\t\treturn {\n\t\t\tsession,\n\t\t};\n\t}\n\tconst freshAge = ctx.context.sessionConfig.freshAge;\n\tconst lastUpdated = new Date(\n\t\tsession.session.updatedAt || session.session.createdAt,\n\t).getTime();\n\tconst now = Date.now();\n\tconst isFresh = now - lastUpdated < freshAge * 1000;\n\tif (!isFresh) {\n\t\tthrow APIError.from(\"FORBIDDEN\", BASE_ERROR_CODES.SESSION_NOT_FRESH);\n\t}\n\treturn {\n\t\tsession,\n\t};\n});\n/**\n * user active sessions list\n */\nexport const listSessions = <Option extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/list-sessions\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\toperationId: \"listUserSessions\",\n\t\t\tuse: [sessionMiddleware],\n\t\t\trequireHeaders: true,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"listUserSessions\",\n\t\t\t\t\tdescription: \"List all active sessions for the user\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/Session\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tasync (ctx) => {\n\t\t\ttry {\n\t\t\t\tconst sessions = await ctx.context.internalAdapter.listSessions(\n\t\t\t\t\tctx.context.session.user.id,\n\t\t\t\t);\n\t\t\t\tconst activeSessions = sessions.filter((session) => {\n\t\t\t\t\treturn session.expiresAt > new Date();\n\t\t\t\t});\n\t\t\t\treturn ctx.json(\n\t\t\t\t\tactiveSessions as unknown as Prettify<InferSession<Option>>[],\n\t\t\t\t);\n\t\t\t} catch (e: any) {\n\t\t\t\tctx.context.logger.error(e);\n\t\t\t\tthrow ctx.error(\"INTERNAL_SERVER_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n/**\n * revoke a single session\n */\nexport const revokeSession = createAuthEndpoint(\n\t\"/revoke-session\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\ttoken: z.string().meta({\n\t\t\t\tdescription: \"The token to revoke\",\n\t\t\t}),\n\t\t}),\n\t\tuse: [sensitiveSessionMiddleware],\n\t\trequireHeaders: true,\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\tdescription: \"Revoke a single session\",\n\t\t\t\trequestBody: {\n\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\tdescription: \"The token to revoke\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\trequired: [\"token\"],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\t\"Indicates if the session was revoked successfully\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"status\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst token = ctx.body.token;\n\t\tconst session = await ctx.context.internalAdapter.findSession(token);\n\n\t\tif (session?.session.userId === ctx.context.session.user.id) {\n\t\t\ttry {\n\t\t\t\tawait ctx.context.internalAdapter.deleteSession(token);\n\t\t\t} catch (error) {\n\t\t\t\tctx.context.logger.error(\n\t\t\t\t\terror && typeof error === \"object\" && \"name\" in error\n\t\t\t\t\t\t? (error.name as string)\n\t\t\t\t\t\t: \"\",\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t\tthrow APIError.from(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\t\tmessage: \"Internal Server Error\",\n\t\t\t\t\tcode: \"INTERNAL_SERVER_ERROR\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n/**\n * revoke all user sessions\n */\nexport const revokeSessions = createAuthEndpoint(\n\t\"/revoke-sessions\",\n\t{\n\t\tmethod: \"POST\",\n\t\tuse: [sensitiveSessionMiddleware],\n\t\trequireHeaders: true,\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\tdescription: \"Revoke all sessions for the user\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\t\"Indicates if all sessions were revoked successfully\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"status\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\ttry {\n\t\t\tawait ctx.context.internalAdapter.deleteSessions(\n\t\t\t\tctx.context.session.user.id,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tctx.context.logger.error(\n\t\t\t\terror && typeof error === \"object\" && \"name\" in error\n\t\t\t\t\t? (error.name as string)\n\t\t\t\t\t: \"\",\n\t\t\t\terror,\n\t\t\t);\n\t\t\tthrow APIError.from(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\tmessage: \"Internal Server Error\",\n\t\t\t\tcode: \"INTERNAL_SERVER_ERROR\",\n\t\t\t});\n\t\t}\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n\nexport const revokeOtherSessions = createAuthEndpoint(\n\t\"/revoke-other-sessions\",\n\t{\n\t\tmethod: \"POST\",\n\t\trequireHeaders: true,\n\t\tuse: [sensitiveSessionMiddleware],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\tdescription:\n\t\t\t\t\t\"Revoke all other sessions for the user except the current one\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\t\"Indicates if all other sessions were revoked successfully\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"status\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst session = ctx.context.session;\n\t\tif (!session.user) {\n\t\t\tthrow APIError.from(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"Unauthorized\",\n\t\t\t\tcode: \"UNAUTHORIZED\",\n\t\t\t});\n\t\t}\n\t\tconst sessions = await ctx.context.internalAdapter.listSessions(\n\t\t\tsession.user.id,\n\t\t);\n\t\tconst activeSessions = sessions.filter((session) => {\n\t\t\treturn session.expiresAt > new Date();\n\t\t});\n\t\tconst otherSessions = activeSessions.filter(\n\t\t\t(session) => session.token !== ctx.context.session.session.token,\n\t\t);\n\t\tawait Promise.all(\n\t\t\totherSessions.map((session) =>\n\t\t\t\tctx.context.internalAdapter.deleteSession(session.token),\n\t\t\t),\n\t\t);\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { InferUser } from "../../types/models.mjs";
|
|
|
2
2
|
import "../../types/index.mjs";
|
|
3
3
|
import { BetterAuthOptions } from "@better-auth/core";
|
|
4
4
|
import * as z from "zod";
|
|
5
|
-
import * as
|
|
5
|
+
import * as better_call738 from "better-call";
|
|
6
6
|
|
|
7
7
|
//#region src/api/routes/sign-in.d.ts
|
|
8
8
|
declare const socialSignInBodySchema: z.ZodObject<{
|
|
@@ -23,7 +23,7 @@ declare const socialSignInBodySchema: z.ZodObject<{
|
|
|
23
23
|
loginHint: z.ZodOptional<z.ZodString>;
|
|
24
24
|
additionalData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
25
25
|
}, z.core.$strip>;
|
|
26
|
-
declare const signInSocial: <O extends BetterAuthOptions>() =>
|
|
26
|
+
declare const signInSocial: <O extends BetterAuthOptions>() => better_call738.StrictEndpoint<"/sign-in/social", {
|
|
27
27
|
method: "POST";
|
|
28
28
|
operationId: string;
|
|
29
29
|
body: z.ZodObject<{
|
|
@@ -98,7 +98,7 @@ declare const signInSocial: <O extends BetterAuthOptions>() => better_call894.St
|
|
|
98
98
|
url: undefined;
|
|
99
99
|
user: InferUser<O>;
|
|
100
100
|
}>;
|
|
101
|
-
declare const signInEmail: <O extends BetterAuthOptions>() =>
|
|
101
|
+
declare const signInEmail: <O extends BetterAuthOptions>() => better_call738.StrictEndpoint<"/sign-in/email", {
|
|
102
102
|
method: "POST";
|
|
103
103
|
operationId: string;
|
|
104
104
|
body: z.ZodObject<{
|
|
@@ -4,9 +4,8 @@ import { setSessionCookie } from "../../cookies/index.mjs";
|
|
|
4
4
|
import { handleOAuthUserInfo } from "../../oauth2/link-account.mjs";
|
|
5
5
|
import { createEmailVerificationToken } from "./email-verification.mjs";
|
|
6
6
|
import "../../utils/index.mjs";
|
|
7
|
-
import { BASE_ERROR_CODES } from "@better-auth/core/error";
|
|
7
|
+
import { APIError, BASE_ERROR_CODES } from "@better-auth/core/error";
|
|
8
8
|
import * as z from "zod";
|
|
9
|
-
import { APIError } from "better-call";
|
|
10
9
|
import { SocialProviderListEnum } from "@better-auth/core/social-providers";
|
|
11
10
|
import { createAuthEndpoint } from "@better-auth/core/api";
|
|
12
11
|
|
|
@@ -71,17 +70,17 @@ const signInSocial = () => createAuthEndpoint("/sign-in/social", {
|
|
|
71
70
|
const provider = c.context.socialProviders.find((p) => p.id === c.body.provider);
|
|
72
71
|
if (!provider) {
|
|
73
72
|
c.context.logger.error("Provider not found. Make sure to add the provider in your auth config", { provider: c.body.provider });
|
|
74
|
-
throw
|
|
73
|
+
throw APIError.from("NOT_FOUND", BASE_ERROR_CODES.PROVIDER_NOT_FOUND);
|
|
75
74
|
}
|
|
76
75
|
if (c.body.idToken) {
|
|
77
76
|
if (!provider.verifyIdToken) {
|
|
78
77
|
c.context.logger.error("Provider does not support id token verification", { provider: c.body.provider });
|
|
79
|
-
throw
|
|
78
|
+
throw APIError.from("NOT_FOUND", BASE_ERROR_CODES.ID_TOKEN_NOT_SUPPORTED);
|
|
80
79
|
}
|
|
81
80
|
const { token, nonce } = c.body.idToken;
|
|
82
81
|
if (!await provider.verifyIdToken(token, nonce)) {
|
|
83
82
|
c.context.logger.error("Invalid id token", { provider: c.body.provider });
|
|
84
|
-
throw
|
|
83
|
+
throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.INVALID_TOKEN);
|
|
85
84
|
}
|
|
86
85
|
const userInfo = await provider.getUserInfo({
|
|
87
86
|
idToken: token,
|
|
@@ -90,11 +89,11 @@ const signInSocial = () => createAuthEndpoint("/sign-in/social", {
|
|
|
90
89
|
});
|
|
91
90
|
if (!userInfo || !userInfo?.user) {
|
|
92
91
|
c.context.logger.error("Failed to get user info", { provider: c.body.provider });
|
|
93
|
-
throw
|
|
92
|
+
throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO);
|
|
94
93
|
}
|
|
95
94
|
if (!userInfo.user.email) {
|
|
96
95
|
c.context.logger.error("User email not found", { provider: c.body.provider });
|
|
97
|
-
throw
|
|
96
|
+
throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.USER_EMAIL_NOT_FOUND);
|
|
98
97
|
}
|
|
99
98
|
const data = await handleOAuthUserInfo(c, {
|
|
100
99
|
userInfo: {
|
|
@@ -113,7 +112,10 @@ const signInSocial = () => createAuthEndpoint("/sign-in/social", {
|
|
|
113
112
|
callbackURL: c.body.callbackURL,
|
|
114
113
|
disableSignUp: provider.disableImplicitSignUp && !c.body.requestSignUp || provider.disableSignUp
|
|
115
114
|
});
|
|
116
|
-
if (data.error) throw
|
|
115
|
+
if (data.error) throw APIError.from("UNAUTHORIZED", {
|
|
116
|
+
message: data.error,
|
|
117
|
+
code: "OAUTH_LINK_ERROR"
|
|
118
|
+
});
|
|
117
119
|
await setSessionCookie(c, data.data);
|
|
118
120
|
return c.json({
|
|
119
121
|
redirect: false,
|
|
@@ -187,37 +189,40 @@ const signInEmail = () => createAuthEndpoint("/sign-in/email", {
|
|
|
187
189
|
}, async (ctx) => {
|
|
188
190
|
if (!ctx.context.options?.emailAndPassword?.enabled) {
|
|
189
191
|
ctx.context.logger.error("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!");
|
|
190
|
-
throw
|
|
192
|
+
throw APIError.from("BAD_REQUEST", {
|
|
193
|
+
code: "EMAIL_PASSWORD_DISABLED",
|
|
194
|
+
message: "Email and password is not enabled"
|
|
195
|
+
});
|
|
191
196
|
}
|
|
192
197
|
const { email, password } = ctx.body;
|
|
193
|
-
if (!z.email().safeParse(email).success) throw
|
|
198
|
+
if (!z.email().safeParse(email).success) throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.INVALID_EMAIL);
|
|
194
199
|
const user = await ctx.context.internalAdapter.findUserByEmail(email, { includeAccounts: true });
|
|
195
200
|
if (!user) {
|
|
196
201
|
await ctx.context.password.hash(password);
|
|
197
202
|
ctx.context.logger.error("User not found", { email });
|
|
198
|
-
throw
|
|
203
|
+
throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD);
|
|
199
204
|
}
|
|
200
205
|
const credentialAccount = user.accounts.find((a) => a.providerId === "credential");
|
|
201
206
|
if (!credentialAccount) {
|
|
202
207
|
await ctx.context.password.hash(password);
|
|
203
208
|
ctx.context.logger.error("Credential account not found", { email });
|
|
204
|
-
throw
|
|
209
|
+
throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD);
|
|
205
210
|
}
|
|
206
211
|
const currentPassword = credentialAccount?.password;
|
|
207
212
|
if (!currentPassword) {
|
|
208
213
|
await ctx.context.password.hash(password);
|
|
209
214
|
ctx.context.logger.error("Password not found", { email });
|
|
210
|
-
throw
|
|
215
|
+
throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD);
|
|
211
216
|
}
|
|
212
217
|
if (!await ctx.context.password.verify({
|
|
213
218
|
hash: currentPassword,
|
|
214
219
|
password
|
|
215
220
|
})) {
|
|
216
221
|
ctx.context.logger.error("Invalid password");
|
|
217
|
-
throw
|
|
222
|
+
throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD);
|
|
218
223
|
}
|
|
219
224
|
if (ctx.context.options?.emailAndPassword?.requireEmailVerification && !user.user.emailVerified) {
|
|
220
|
-
if (!ctx.context.options?.emailVerification?.sendVerificationEmail) throw
|
|
225
|
+
if (!ctx.context.options?.emailVerification?.sendVerificationEmail) throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.EMAIL_NOT_VERIFIED);
|
|
221
226
|
if (ctx.context.options?.emailVerification?.sendOnSignIn) {
|
|
222
227
|
const token = await createEmailVerificationToken(ctx.context.secret, user.user.email, void 0, ctx.context.options.emailVerification?.expiresIn);
|
|
223
228
|
const callbackURL = ctx.body.callbackURL ? encodeURIComponent(ctx.body.callbackURL) : encodeURIComponent("/");
|
|
@@ -228,12 +233,12 @@ const signInEmail = () => createAuthEndpoint("/sign-in/email", {
|
|
|
228
233
|
token
|
|
229
234
|
}, ctx.request));
|
|
230
235
|
}
|
|
231
|
-
throw
|
|
236
|
+
throw APIError.from("FORBIDDEN", BASE_ERROR_CODES.EMAIL_NOT_VERIFIED);
|
|
232
237
|
}
|
|
233
238
|
const session = await ctx.context.internalAdapter.createSession(user.user.id, ctx.body.rememberMe === false);
|
|
234
239
|
if (!session) {
|
|
235
240
|
ctx.context.logger.error("Failed to create session");
|
|
236
|
-
throw
|
|
241
|
+
throw APIError.from("UNAUTHORIZED", BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION);
|
|
237
242
|
}
|
|
238
243
|
await setSessionCookie(ctx, {
|
|
239
244
|
session,
|