better-auth 1.5.3 → 1.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/index.d.mts +25 -1
- package/dist/adapters/index.mjs +9 -1
- package/dist/adapters/index.mjs.map +1 -0
- package/dist/api/index.d.mts +30 -0
- package/dist/api/routes/password.d.mts +1 -0
- package/dist/api/routes/password.mjs +2 -1
- package/dist/api/routes/password.mjs.map +1 -1
- package/dist/api/routes/sign-in.d.mts +14 -0
- package/dist/api/routes/sign-in.mjs +10 -2
- package/dist/api/routes/sign-in.mjs.map +1 -1
- package/dist/api/routes/sign-up.mjs +3 -2
- package/dist/api/routes/sign-up.mjs.map +1 -1
- package/dist/client/index.d.mts +3 -2
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/path-to-object.d.mts +6 -1
- package/dist/client/query.mjs +3 -2
- package/dist/client/query.mjs.map +1 -1
- package/dist/client/session-refresh.d.mts +11 -2
- package/dist/client/session-refresh.mjs +1 -4
- package/dist/client/session-refresh.mjs.map +1 -1
- package/dist/db/get-migration.mjs +3 -2
- package/dist/db/get-migration.mjs.map +1 -1
- package/dist/plugins/oidc-provider/authorize.mjs +13 -4
- package/dist/plugins/oidc-provider/authorize.mjs.map +1 -1
- package/dist/plugins/oidc-provider/error.mjs +12 -2
- package/dist/plugins/oidc-provider/error.mjs.map +1 -1
- package/dist/plugins/organization/routes/crud-invites.mjs +1 -1
- package/dist/plugins/organization/routes/crud-invites.mjs.map +1 -1
- package/dist/plugins/organization/routes/crud-members.mjs +1 -1
- package/dist/plugins/organization/routes/crud-members.mjs.map +1 -1
- package/dist/plugins/two-factor/index.mjs +7 -1
- package/dist/plugins/two-factor/index.mjs.map +1 -1
- package/dist/plugins/two-factor/otp/index.d.mts +2 -2
- package/dist/plugins/two-factor/otp/index.mjs.map +1 -1
- package/dist/plugins/two-factor/types.d.mts +7 -0
- package/dist/test-utils/test-instance.d.mts +91 -0
- package/package.json +10 -22
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
import * as _better_auth_core0 from "@better-auth/core";
|
|
1
2
|
import { AdapterFactory, AdapterFactoryConfig, AdapterFactoryCustomizeAdapterCreator, AdapterFactoryOptions, AdapterTestDebugLogs, CustomAdapter, createAdapterFactory, initGetDefaultFieldName, initGetDefaultModelName, initGetFieldAttributes, initGetFieldName, initGetIdField, initGetModelName } from "@better-auth/core/db/adapter";
|
|
2
3
|
export * from "@better-auth/core/db/adapter";
|
|
3
|
-
|
|
4
|
+
|
|
5
|
+
//#region src/adapters/index.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated Use `createAdapterFactory` instead.
|
|
8
|
+
*/
|
|
9
|
+
declare const createAdapter: <Options extends _better_auth_core0.BetterAuthOptions>({
|
|
10
|
+
adapter: customAdapter,
|
|
11
|
+
config: cfg
|
|
12
|
+
}: AdapterFactoryOptions) => AdapterFactory<Options>;
|
|
13
|
+
/**
|
|
14
|
+
* @deprecated Use `AdapterFactoryOptions` instead.
|
|
15
|
+
*/
|
|
16
|
+
type CreateAdapterOptions = AdapterFactoryOptions;
|
|
17
|
+
/**
|
|
18
|
+
* @deprecated Use `AdapterFactoryConfig` instead.
|
|
19
|
+
*/
|
|
20
|
+
type AdapterConfig = AdapterFactoryConfig;
|
|
21
|
+
/**
|
|
22
|
+
* @deprecated Use `AdapterFactoryCustomizeAdapterCreator` instead.
|
|
23
|
+
*/
|
|
24
|
+
type CreateCustomAdapter = AdapterFactoryCustomizeAdapterCreator;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { AdapterConfig, type AdapterFactory, type AdapterFactoryConfig, type AdapterFactoryCustomizeAdapterCreator, type AdapterFactoryOptions, type AdapterTestDebugLogs, CreateAdapterOptions, CreateCustomAdapter, type CustomAdapter, createAdapter, createAdapterFactory, initGetDefaultFieldName, initGetDefaultModelName, initGetFieldAttributes, initGetFieldName, initGetIdField, initGetModelName };
|
|
27
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/adapters/index.mjs
CHANGED
|
@@ -2,4 +2,12 @@ import { createAdapterFactory, initGetDefaultFieldName, initGetDefaultModelName,
|
|
|
2
2
|
|
|
3
3
|
export * from "@better-auth/core/db/adapter"
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
//#region src/adapters/index.ts
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated Use `createAdapterFactory` instead.
|
|
8
|
+
*/
|
|
9
|
+
const createAdapter = createAdapterFactory;
|
|
10
|
+
|
|
11
|
+
//#endregion
|
|
12
|
+
export { createAdapter, createAdapterFactory, initGetDefaultFieldName, initGetDefaultModelName, initGetFieldAttributes, initGetFieldName, initGetIdField, initGetModelName };
|
|
13
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/adapters/index.ts"],"sourcesContent":["import type {\n\tAdapterFactory,\n\tAdapterFactoryConfig,\n\tAdapterFactoryCustomizeAdapterCreator,\n\tAdapterFactoryOptions,\n\tAdapterTestDebugLogs,\n\tCustomAdapter,\n} from \"@better-auth/core/db/adapter\";\nimport {\n\tcreateAdapterFactory,\n\tinitGetDefaultFieldName,\n\tinitGetDefaultModelName,\n\tinitGetFieldAttributes,\n\tinitGetFieldName,\n\tinitGetIdField,\n\tinitGetModelName,\n} from \"@better-auth/core/db/adapter\";\n\nexport * from \"@better-auth/core/db/adapter\";\n\nexport type {\n\tAdapterFactoryOptions,\n\tAdapterFactory,\n\tAdapterTestDebugLogs,\n\tAdapterFactoryConfig,\n\tCustomAdapter,\n\tAdapterFactoryCustomizeAdapterCreator,\n};\nexport {\n\tcreateAdapterFactory,\n\tinitGetDefaultFieldName,\n\tinitGetDefaultModelName,\n\tinitGetFieldName,\n\tinitGetModelName,\n\tinitGetFieldAttributes,\n\tinitGetIdField,\n};\n\n/**\n * @deprecated Use `createAdapterFactory` instead.\n */\nexport const createAdapter = createAdapterFactory;\n\n/**\n * @deprecated Use `AdapterFactoryOptions` instead.\n */\nexport type CreateAdapterOptions = AdapterFactoryOptions;\n\n/**\n * @deprecated Use `AdapterFactoryConfig` instead.\n */\nexport type AdapterConfig = AdapterFactoryConfig;\n\n/**\n * @deprecated Use `AdapterFactoryCustomizeAdapterCreator` instead.\n */\nexport type CreateCustomAdapter = AdapterFactoryCustomizeAdapterCreator;\n"],"mappings":";;;;;;;;AAyCA,MAAa,gBAAgB"}
|
package/dist/api/index.d.mts
CHANGED
|
@@ -102,6 +102,13 @@ declare function getEndpoints<Option extends BetterAuthOptions>(ctx: Awaitable<A
|
|
|
102
102
|
accessToken: zod.ZodOptional<zod.ZodString>;
|
|
103
103
|
refreshToken: zod.ZodOptional<zod.ZodString>;
|
|
104
104
|
expiresAt: zod.ZodOptional<zod.ZodNumber>;
|
|
105
|
+
user: zod.ZodOptional<zod.ZodObject<{
|
|
106
|
+
name: zod.ZodOptional<zod.ZodObject<{
|
|
107
|
+
firstName: zod.ZodOptional<zod.ZodString>;
|
|
108
|
+
lastName: zod.ZodOptional<zod.ZodString>;
|
|
109
|
+
}, zod_v4_core0.$strip>>;
|
|
110
|
+
email: zod.ZodOptional<zod.ZodString>;
|
|
111
|
+
}, zod_v4_core0.$strip>>;
|
|
105
112
|
}, zod_v4_core0.$strip>>;
|
|
106
113
|
scopes: zod.ZodOptional<zod.ZodArray<zod.ZodString>>;
|
|
107
114
|
requestSignUp: zod.ZodOptional<zod.ZodBoolean>;
|
|
@@ -122,6 +129,13 @@ declare function getEndpoints<Option extends BetterAuthOptions>(ctx: Awaitable<A
|
|
|
122
129
|
accessToken: zod.ZodOptional<zod.ZodString>;
|
|
123
130
|
refreshToken: zod.ZodOptional<zod.ZodString>;
|
|
124
131
|
expiresAt: zod.ZodOptional<zod.ZodNumber>;
|
|
132
|
+
user: zod.ZodOptional<zod.ZodObject<{
|
|
133
|
+
name: zod.ZodOptional<zod.ZodObject<{
|
|
134
|
+
firstName: zod.ZodOptional<zod.ZodString>;
|
|
135
|
+
lastName: zod.ZodOptional<zod.ZodString>;
|
|
136
|
+
}, zod_v4_core0.$strip>>;
|
|
137
|
+
email: zod.ZodOptional<zod.ZodString>;
|
|
138
|
+
}, zod_v4_core0.$strip>>;
|
|
125
139
|
}, zod_v4_core0.$strip>>;
|
|
126
140
|
scopes: zod.ZodOptional<zod.ZodArray<zod.ZodString>>;
|
|
127
141
|
requestSignUp: zod.ZodOptional<zod.ZodBoolean>;
|
|
@@ -1265,6 +1279,7 @@ declare function getEndpoints<Option extends BetterAuthOptions>(ctx: Awaitable<A
|
|
|
1265
1279
|
};
|
|
1266
1280
|
};
|
|
1267
1281
|
};
|
|
1282
|
+
use: ((inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<void>)[];
|
|
1268
1283
|
}, {
|
|
1269
1284
|
status: boolean;
|
|
1270
1285
|
message: string;
|
|
@@ -2073,6 +2088,13 @@ declare const router: <Option extends BetterAuthOptions>(ctx: AuthContext, optio
|
|
|
2073
2088
|
accessToken: zod.ZodOptional<zod.ZodString>;
|
|
2074
2089
|
refreshToken: zod.ZodOptional<zod.ZodString>;
|
|
2075
2090
|
expiresAt: zod.ZodOptional<zod.ZodNumber>;
|
|
2091
|
+
user: zod.ZodOptional<zod.ZodObject<{
|
|
2092
|
+
name: zod.ZodOptional<zod.ZodObject<{
|
|
2093
|
+
firstName: zod.ZodOptional<zod.ZodString>;
|
|
2094
|
+
lastName: zod.ZodOptional<zod.ZodString>;
|
|
2095
|
+
}, zod_v4_core0.$strip>>;
|
|
2096
|
+
email: zod.ZodOptional<zod.ZodString>;
|
|
2097
|
+
}, zod_v4_core0.$strip>>;
|
|
2076
2098
|
}, zod_v4_core0.$strip>>;
|
|
2077
2099
|
scopes: zod.ZodOptional<zod.ZodArray<zod.ZodString>>;
|
|
2078
2100
|
requestSignUp: zod.ZodOptional<zod.ZodBoolean>;
|
|
@@ -2093,6 +2115,13 @@ declare const router: <Option extends BetterAuthOptions>(ctx: AuthContext, optio
|
|
|
2093
2115
|
accessToken: zod.ZodOptional<zod.ZodString>;
|
|
2094
2116
|
refreshToken: zod.ZodOptional<zod.ZodString>;
|
|
2095
2117
|
expiresAt: zod.ZodOptional<zod.ZodNumber>;
|
|
2118
|
+
user: zod.ZodOptional<zod.ZodObject<{
|
|
2119
|
+
name: zod.ZodOptional<zod.ZodObject<{
|
|
2120
|
+
firstName: zod.ZodOptional<zod.ZodString>;
|
|
2121
|
+
lastName: zod.ZodOptional<zod.ZodString>;
|
|
2122
|
+
}, zod_v4_core0.$strip>>;
|
|
2123
|
+
email: zod.ZodOptional<zod.ZodString>;
|
|
2124
|
+
}, zod_v4_core0.$strip>>;
|
|
2096
2125
|
}, zod_v4_core0.$strip>>;
|
|
2097
2126
|
scopes: zod.ZodOptional<zod.ZodArray<zod.ZodString>>;
|
|
2098
2127
|
requestSignUp: zod.ZodOptional<zod.ZodBoolean>;
|
|
@@ -3236,6 +3265,7 @@ declare const router: <Option extends BetterAuthOptions>(ctx: AuthContext, optio
|
|
|
3236
3265
|
};
|
|
3237
3266
|
};
|
|
3238
3267
|
};
|
|
3268
|
+
use: ((inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<void>)[];
|
|
3239
3269
|
}, {
|
|
3240
3270
|
status: boolean;
|
|
3241
3271
|
message: string;
|
|
@@ -38,7 +38,8 @@ const requestPasswordReset = createAuthEndpoint("/request-password-reset", {
|
|
|
38
38
|
}
|
|
39
39
|
} } }
|
|
40
40
|
} }
|
|
41
|
-
} }
|
|
41
|
+
} },
|
|
42
|
+
use: [originCheck((ctx) => ctx.body.redirectTo)]
|
|
42
43
|
}, async (ctx) => {
|
|
43
44
|
if (!ctx.context.options.emailAndPassword?.sendResetPassword) {
|
|
44
45
|
ctx.context.logger.error("Reset password isn't enabled.Please pass an emailAndPassword.sendResetPassword function in your auth config!");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"password.mjs","names":[],"sources":["../../../src/api/routes/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 { generateId } from \"@better-auth/core/utils/id\";\nimport * as z from \"zod\";\nimport { getDate } from \"../../utils/date\";\nimport { validatePassword } from \"../../utils/password\";\nimport { originCheck } from \"../middlewares\";\nimport { sensitiveSessionMiddleware } from \"./session\";\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.deleteVerificationByIdentifier(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\nexport const verifyPassword = createAuthEndpoint(\n\t\"/verify-password\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The password to verify\n\t\t\t */\n\t\t\tpassword: z.string().meta({\n\t\t\t\tdescription: \"The password to verify\",\n\t\t\t}),\n\t\t}),\n\t\tmetadata: {\n\t\t\tscope: \"server\",\n\t\t\topenapi: {\n\t\t\t\toperationId: \"verifyPassword\",\n\t\t\t\tdescription: \"Verify the current user's password\",\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\tuse: [sensitiveSessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst { password } = ctx.body;\n\t\tconst session = ctx.context.session;\n\n\t\tconst isValid = await validatePassword(ctx, {\n\t\t\tpassword,\n\t\t\tuserId: session.user.id,\n\t\t});\n\n\t\tif (!isValid) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_PASSWORD);\n\t\t}\n\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":"password.mjs","names":[],"sources":["../../../src/api/routes/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 { generateId } from \"@better-auth/core/utils/id\";\nimport * as z from \"zod\";\nimport { getDate } from \"../../utils/date\";\nimport { validatePassword } from \"../../utils/password\";\nimport { originCheck } from \"../middlewares\";\nimport { sensitiveSessionMiddleware } from \"./session\";\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\tuse: [originCheck((ctx) => ctx.body.redirectTo)],\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.deleteVerificationByIdentifier(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\nexport const verifyPassword = createAuthEndpoint(\n\t\"/verify-password\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The password to verify\n\t\t\t */\n\t\t\tpassword: z.string().meta({\n\t\t\t\tdescription: \"The password to verify\",\n\t\t\t}),\n\t\t}),\n\t\tmetadata: {\n\t\t\tscope: \"server\",\n\t\t\topenapi: {\n\t\t\t\toperationId: \"verifyPassword\",\n\t\t\t\tdescription: \"Verify the current user's password\",\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\tuse: [sensitiveSessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst { password } = ctx.body;\n\t\tconst session = ctx.context.session;\n\n\t\tconst isValid = await validatePassword(ctx, {\n\t\t\tpassword,\n\t\t\tuserId: session.user.id,\n\t\t});\n\n\t\tif (!isValid) {\n\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_PASSWORD);\n\t\t}\n\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n"],"mappings":"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"}
|
|
@@ -16,6 +16,13 @@ declare const socialSignInBodySchema: z.ZodObject<{
|
|
|
16
16
|
accessToken: z.ZodOptional<z.ZodString>;
|
|
17
17
|
refreshToken: z.ZodOptional<z.ZodString>;
|
|
18
18
|
expiresAt: z.ZodOptional<z.ZodNumber>;
|
|
19
|
+
user: z.ZodOptional<z.ZodObject<{
|
|
20
|
+
name: z.ZodOptional<z.ZodObject<{
|
|
21
|
+
firstName: z.ZodOptional<z.ZodString>;
|
|
22
|
+
lastName: z.ZodOptional<z.ZodString>;
|
|
23
|
+
}, z.core.$strip>>;
|
|
24
|
+
email: z.ZodOptional<z.ZodString>;
|
|
25
|
+
}, z.core.$strip>>;
|
|
19
26
|
}, z.core.$strip>>;
|
|
20
27
|
scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
21
28
|
requestSignUp: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -37,6 +44,13 @@ declare const signInSocial: <O extends BetterAuthOptions>() => better_call0.Stri
|
|
|
37
44
|
accessToken: z.ZodOptional<z.ZodString>;
|
|
38
45
|
refreshToken: z.ZodOptional<z.ZodString>;
|
|
39
46
|
expiresAt: z.ZodOptional<z.ZodNumber>;
|
|
47
|
+
user: z.ZodOptional<z.ZodObject<{
|
|
48
|
+
name: z.ZodOptional<z.ZodObject<{
|
|
49
|
+
firstName: z.ZodOptional<z.ZodString>;
|
|
50
|
+
lastName: z.ZodOptional<z.ZodString>;
|
|
51
|
+
}, z.core.$strip>>;
|
|
52
|
+
email: z.ZodOptional<z.ZodString>;
|
|
53
|
+
}, z.core.$strip>>;
|
|
40
54
|
}, z.core.$strip>>;
|
|
41
55
|
scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
42
56
|
requestSignUp: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -23,7 +23,14 @@ const socialSignInBodySchema = z.object({
|
|
|
23
23
|
nonce: z.string().meta({ description: "Nonce used to generate the token" }).optional(),
|
|
24
24
|
accessToken: z.string().meta({ description: "Access token from the provider" }).optional(),
|
|
25
25
|
refreshToken: z.string().meta({ description: "Refresh token from the provider" }).optional(),
|
|
26
|
-
expiresAt: z.number().meta({ description: "Expiry date of the token" }).optional()
|
|
26
|
+
expiresAt: z.number().meta({ description: "Expiry date of the token" }).optional(),
|
|
27
|
+
user: z.object({
|
|
28
|
+
name: z.object({
|
|
29
|
+
firstName: z.string().optional(),
|
|
30
|
+
lastName: z.string().optional()
|
|
31
|
+
}).optional(),
|
|
32
|
+
email: z.string().optional()
|
|
33
|
+
}).meta({ description: "The user object from the provider. Only available for some providers like Apple." }).optional()
|
|
27
34
|
})),
|
|
28
35
|
scopes: z.array(z.string()).meta({ description: "Array of scopes to request from the provider. This will override the default scopes passed." }).optional(),
|
|
29
36
|
requestSignUp: z.boolean().meta({ description: "Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider" }).optional(),
|
|
@@ -87,7 +94,8 @@ const signInSocial = () => createAuthEndpoint("/sign-in/social", {
|
|
|
87
94
|
const userInfo = await provider.getUserInfo({
|
|
88
95
|
idToken: token,
|
|
89
96
|
accessToken: c.body.idToken.accessToken,
|
|
90
|
-
refreshToken: c.body.idToken.refreshToken
|
|
97
|
+
refreshToken: c.body.idToken.refreshToken,
|
|
98
|
+
user: c.body.idToken.user
|
|
91
99
|
});
|
|
92
100
|
if (!userInfo || !userInfo?.user) {
|
|
93
101
|
c.context.logger.error("Failed to get user info", { provider: c.body.provider });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sign-in.mjs","names":[],"sources":["../../../src/api/routes/sign-in.ts"],"sourcesContent":["import type { BetterAuthOptions } from \"@better-auth/core\";\nimport { createAuthEndpoint } from \"@better-auth/core/api\";\nimport type { User } from \"@better-auth/core/db\";\nimport { APIError, BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport { SocialProviderListEnum } from \"@better-auth/core/social-providers\";\nimport * as z from \"zod\";\nimport { getAwaitableValue } from \"../../context/helpers\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { parseUserOutput } from \"../../db/schema\";\nimport { handleOAuthUserInfo } from \"../../oauth2/link-account\";\nimport { generateState } from \"../../utils\";\nimport { formCsrfMiddleware } from \"../middlewares/origin-check\";\nimport { createEmailVerificationToken } from \"./email-verification\";\n\nconst socialSignInBodySchema = z.object({\n\t/**\n\t * Callback URL to redirect to after the user\n\t * has signed in.\n\t */\n\tcallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"Callback URL to redirect to after the user has signed in\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * callback url to redirect if the user is newly registered.\n\t *\n\t * useful if you have different routes for existing users and new users\n\t */\n\tnewUserCallbackURL: z.string().optional(),\n\t/**\n\t * Callback url to redirect to if an error happens\n\t *\n\t * If it's initiated from the client sdk this defaults to\n\t * the current url.\n\t */\n\terrorCallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"Callback URL to redirect to if an error happens\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * OAuth2 provider to use`\n\t */\n\tprovider: SocialProviderListEnum,\n\t/**\n\t * Disable automatic redirection to the provider\n\t *\n\t * This is useful if you want to handle the redirection\n\t * yourself like in a popup or a different tab.\n\t */\n\tdisableRedirect: z\n\t\t.boolean()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"Disable automatic redirection to the provider. Useful for handling the redirection yourself\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * ID token from the provider\n\t *\n\t * This is used to sign in the user\n\t * if the user is already signed in with the\n\t * provider in the frontend.\n\t *\n\t * Only applicable if the provider supports\n\t * it. Currently only `apple` and `google` is\n\t * supported out of the box.\n\t */\n\tidToken: z.optional(\n\t\tz.object({\n\t\t\t/**\n\t\t\t * ID token from the provider\n\t\t\t */\n\t\t\ttoken: z.string().meta({\n\t\t\t\tdescription: \"ID token from the provider\",\n\t\t\t}),\n\t\t\t/**\n\t\t\t * The nonce used to generate the token\n\t\t\t */\n\t\t\tnonce: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"Nonce used to generate the token\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\t/**\n\t\t\t * Access token from the provider\n\t\t\t */\n\t\t\taccessToken: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"Access token from the provider\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\t/**\n\t\t\t * Refresh token from the provider\n\t\t\t */\n\t\t\trefreshToken: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"Refresh token from the provider\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\t/**\n\t\t\t * Expiry date of the token\n\t\t\t */\n\t\t\texpiresAt: z\n\t\t\t\t.number()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"Expiry date of the token\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t),\n\tscopes: z\n\t\t.array(z.string())\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"Array of scopes to request from the provider. This will override the default scopes passed.\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Explicitly request sign-up\n\t *\n\t * Should be used to allow sign up when\n\t * disableImplicitSignUp for this provider is\n\t * true\n\t */\n\trequestSignUp: z\n\t\t.boolean()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * The login hint to use for the authorization code request\n\t */\n\tloginHint: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"The login hint to use for the authorization code request\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Additional data to be passed through the OAuth flow\n\t */\n\tadditionalData: z.record(z.string(), z.any()).optional().meta({\n\t\tdescription: \"Additional data to be passed through the OAuth flow\",\n\t}),\n});\n\nexport const signInSocial = <O extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/sign-in/social\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\toperationId: \"socialSignIn\",\n\t\t\tbody: socialSignInBodySchema,\n\t\t\tmetadata: {\n\t\t\t\t$Infer: {\n\t\t\t\t\tbody: {} as z.infer<typeof socialSignInBodySchema>,\n\t\t\t\t\treturned: {} as {\n\t\t\t\t\t\tredirect: boolean;\n\t\t\t\t\t\ttoken?: string | undefined;\n\t\t\t\t\t\turl?: string | undefined;\n\t\t\t\t\t\tuser?: User<O[\"user\"], O[\"plugins\"]> | undefined;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\topenapi: {\n\t\t\t\t\tdescription: \"Sign in with a social provider\",\n\t\t\t\t\toperationId: \"socialSignIn\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\"Success - Returns either session details or redirect URL\",\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\t// todo: we need support for multiple schema\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tdescription: \"Session response when idToken is provided\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\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\ttype: \"object\",\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\turl: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tredirect: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\tenum: [false],\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: [\"redirect\", \"token\", \"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\tc,\n\t\t): Promise<\n\t\t\t| { redirect: boolean; url: string }\n\t\t\t| {\n\t\t\t\t\tredirect: boolean;\n\t\t\t\t\ttoken: string;\n\t\t\t\t\turl: undefined;\n\t\t\t\t\tuser: User<O[\"user\"], O[\"plugins\"]>;\n\t\t\t }\n\t\t> => {\n\t\t\tconst provider = await getAwaitableValue(c.context.socialProviders, {\n\t\t\t\tvalue: c.body.provider,\n\t\t\t});\n\t\t\tif (!provider) {\n\t\t\t\tc.context.logger.error(\n\t\t\t\t\t\"Provider not found. Make sure to add the provider in your auth config\",\n\t\t\t\t\t{\n\t\t\t\t\t\tprovider: c.body.provider,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tthrow APIError.from(\"NOT_FOUND\", BASE_ERROR_CODES.PROVIDER_NOT_FOUND);\n\t\t\t}\n\n\t\t\tif (c.body.idToken) {\n\t\t\t\tif (!provider.verifyIdToken) {\n\t\t\t\t\tc.context.logger.error(\n\t\t\t\t\t\t\"Provider does not support id token verification\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tprovider: c.body.provider,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"NOT_FOUND\",\n\t\t\t\t\t\tBASE_ERROR_CODES.ID_TOKEN_NOT_SUPPORTED,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst { token, nonce } = c.body.idToken;\n\t\t\t\tconst valid = await provider.verifyIdToken(token, nonce);\n\t\t\t\tif (!valid) {\n\t\t\t\t\tc.context.logger.error(\"Invalid id token\", {\n\t\t\t\t\t\tprovider: c.body.provider,\n\t\t\t\t\t});\n\t\t\t\t\tthrow APIError.from(\"UNAUTHORIZED\", BASE_ERROR_CODES.INVALID_TOKEN);\n\t\t\t\t}\n\t\t\t\tconst userInfo = await provider.getUserInfo({\n\t\t\t\t\tidToken: token,\n\t\t\t\t\taccessToken: c.body.idToken.accessToken,\n\t\t\t\t\trefreshToken: c.body.idToken.refreshToken,\n\t\t\t\t});\n\t\t\t\tif (!userInfo || !userInfo?.user) {\n\t\t\t\t\tc.context.logger.error(\"Failed to get user info\", {\n\t\t\t\t\t\tprovider: c.body.provider,\n\t\t\t\t\t});\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"UNAUTHORIZED\",\n\t\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_GET_USER_INFO,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (!userInfo.user.email) {\n\t\t\t\t\tc.context.logger.error(\"User email not found\", {\n\t\t\t\t\t\tprovider: c.body.provider,\n\t\t\t\t\t});\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"UNAUTHORIZED\",\n\t\t\t\t\t\tBASE_ERROR_CODES.USER_EMAIL_NOT_FOUND,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst data = await handleOAuthUserInfo(c, {\n\t\t\t\t\tuserInfo: {\n\t\t\t\t\t\t...userInfo.user,\n\t\t\t\t\t\temail: userInfo.user.email,\n\t\t\t\t\t\tid: String(userInfo.user.id),\n\t\t\t\t\t\tname: userInfo.user.name || \"\",\n\t\t\t\t\t\timage: userInfo.user.image,\n\t\t\t\t\t\temailVerified: userInfo.user.emailVerified || false,\n\t\t\t\t\t},\n\t\t\t\t\taccount: {\n\t\t\t\t\t\tproviderId: provider.id,\n\t\t\t\t\t\taccountId: String(userInfo.user.id),\n\t\t\t\t\t\taccessToken: c.body.idToken.accessToken,\n\t\t\t\t\t},\n\t\t\t\t\tcallbackURL: c.body.callbackURL,\n\t\t\t\t\tdisableSignUp:\n\t\t\t\t\t\t(provider.disableImplicitSignUp && !c.body.requestSignUp) ||\n\t\t\t\t\t\tprovider.disableSignUp,\n\t\t\t\t});\n\t\t\t\tif (data.error) {\n\t\t\t\t\tthrow APIError.from(\"UNAUTHORIZED\", {\n\t\t\t\t\t\tmessage: data.error,\n\t\t\t\t\t\tcode: \"OAUTH_LINK_ERROR\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tawait setSessionCookie(c, data.data!);\n\t\t\t\treturn c.json({\n\t\t\t\t\tredirect: false,\n\t\t\t\t\ttoken: data.data!.session.token,\n\t\t\t\t\turl: undefined,\n\t\t\t\t\tuser: parseUserOutput(c.context.options, data.data!.user) as User<\n\t\t\t\t\t\tO[\"user\"],\n\t\t\t\t\t\tO[\"plugins\"]\n\t\t\t\t\t>,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst { codeVerifier, state } = await generateState(\n\t\t\t\tc,\n\t\t\t\tundefined,\n\t\t\t\tc.body.additionalData,\n\t\t\t);\n\t\t\tconst url = await provider.createAuthorizationURL({\n\t\t\t\tstate,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI: `${c.context.baseURL}/callback/${provider.id}`,\n\t\t\t\tscopes: c.body.scopes,\n\t\t\t\tloginHint: c.body.loginHint,\n\t\t\t});\n\n\t\t\tif (!c.body.disableRedirect) {\n\t\t\t\tc.setHeader(\"Location\", url.toString());\n\t\t\t}\n\n\t\t\treturn c.json({\n\t\t\t\turl: url.toString(),\n\t\t\t\tredirect: !c.body.disableRedirect,\n\t\t\t});\n\t\t},\n\t);\n\nexport const signInEmail = <O extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/sign-in/email\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\toperationId: \"signInEmail\",\n\t\t\tuse: [formCsrfMiddleware],\n\t\t\tbody: z.object({\n\t\t\t\t/**\n\t\t\t\t * Email of the user\n\t\t\t\t */\n\t\t\t\temail: z.string().meta({\n\t\t\t\t\tdescription: \"Email of the user\",\n\t\t\t\t}),\n\t\t\t\t/**\n\t\t\t\t * Password of the user\n\t\t\t\t */\n\t\t\t\tpassword: z.string().meta({\n\t\t\t\t\tdescription: \"Password of the user\",\n\t\t\t\t}),\n\t\t\t\t/**\n\t\t\t\t * Callback URL to use as a redirect for email\n\t\t\t\t * verification and for possible redirects\n\t\t\t\t */\n\t\t\t\tcallbackURL: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.meta({\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Callback URL to use as a redirect for email verification\",\n\t\t\t\t\t})\n\t\t\t\t\t.optional(),\n\t\t\t\t/**\n\t\t\t\t * If this is false, the session will not be remembered\n\t\t\t\t * @default true\n\t\t\t\t */\n\t\t\t\trememberMe: z\n\t\t\t\t\t.boolean()\n\t\t\t\t\t.meta({\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"If this is false, the session will not be remembered. Default is `true`.\",\n\t\t\t\t\t})\n\t\t\t\t\t.default(true)\n\t\t\t\t\t.optional(),\n\t\t\t}),\n\t\t\tmetadata: {\n\t\t\t\tallowedMediaTypes: [\n\t\t\t\t\t\"application/x-www-form-urlencoded\",\n\t\t\t\t\t\"application/json\",\n\t\t\t\t],\n\t\t\t\t$Infer: {\n\t\t\t\t\tbody: {} as {\n\t\t\t\t\t\temail: string;\n\t\t\t\t\t\tpassword: string;\n\t\t\t\t\t\tcallbackURL?: string | undefined;\n\t\t\t\t\t\trememberMe?: boolean | undefined;\n\t\t\t\t\t},\n\t\t\t\t\treturned: {} as {\n\t\t\t\t\t\tredirect: boolean;\n\t\t\t\t\t\ttoken: string;\n\t\t\t\t\t\turl?: string | undefined;\n\t\t\t\t\t\tuser: User<O[\"user\"], O[\"plugins\"]>;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"signInEmail\",\n\t\t\t\t\tdescription: \"Sign in with email and password\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\"Success - Returns either session details or redirect URL\",\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\t// todo: we need support for multiple schema\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tdescription: \"Session response when idToken is provided\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tredirect: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\tenum: [false],\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"Session token\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\turl: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\tnullable: true,\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\ttype: \"object\",\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: [\"redirect\", \"token\", \"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\tredirect: boolean;\n\t\t\ttoken: string;\n\t\t\turl?: string | undefined;\n\t\t\tuser: User<O[\"user\"], O[\"plugins\"]>;\n\t\t}> => {\n\t\t\tif (!ctx.context.options?.emailAndPassword?.enabled) {\n\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\"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!\",\n\t\t\t\t);\n\t\t\t\tthrow APIError.from(\"BAD_REQUEST\", {\n\t\t\t\t\tcode: \"EMAIL_PASSWORD_DISABLED\",\n\t\t\t\t\tmessage: \"Email and password is not enabled\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst { email, password } = ctx.body;\n\t\t\tconst isValidEmail = z.email().safeParse(email);\n\t\t\tif (!isValidEmail.success) {\n\t\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_EMAIL);\n\t\t\t}\n\t\t\tconst user = await ctx.context.internalAdapter.findUserByEmail(email, {\n\t\t\t\tincludeAccounts: true,\n\t\t\t});\n\n\t\t\tif (!user) {\n\t\t\t\t// Hash password to prevent timing attacks from revealing valid email addresses\n\t\t\t\t// By hashing passwords for invalid emails, we ensure consistent response times\n\t\t\t\tawait ctx.context.password.hash(password);\n\t\t\t\tctx.context.logger.error(\"User not found\", { email });\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"UNAUTHORIZED\",\n\t\t\t\t\tBASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst credentialAccount = user.accounts.find(\n\t\t\t\t(a) => a.providerId === \"credential\",\n\t\t\t);\n\t\t\tif (!credentialAccount) {\n\t\t\t\tawait ctx.context.password.hash(password);\n\t\t\t\tctx.context.logger.error(\"Credential account not found\", { email });\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"UNAUTHORIZED\",\n\t\t\t\t\tBASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst currentPassword = credentialAccount?.password;\n\t\t\tif (!currentPassword) {\n\t\t\t\tawait ctx.context.password.hash(password);\n\t\t\t\tctx.context.logger.error(\"Password not found\", { email });\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"UNAUTHORIZED\",\n\t\t\t\t\tBASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst validPassword = await ctx.context.password.verify({\n\t\t\t\thash: currentPassword,\n\t\t\t\tpassword,\n\t\t\t});\n\t\t\tif (!validPassword) {\n\t\t\t\tctx.context.logger.error(\"Invalid password\");\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"UNAUTHORIZED\",\n\t\t\t\t\tBASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tctx.context.options?.emailAndPassword?.requireEmailVerification &&\n\t\t\t\t!user.user.emailVerified\n\t\t\t) {\n\t\t\t\tif (!ctx.context.options?.emailVerification?.sendVerificationEmail) {\n\t\t\t\t\tthrow APIError.from(\"FORBIDDEN\", BASE_ERROR_CODES.EMAIL_NOT_VERIFIED);\n\t\t\t\t}\n\n\t\t\t\tif (ctx.context.options?.emailVerification?.sendOnSignIn) {\n\t\t\t\t\tconst token = await createEmailVerificationToken(\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\tuser.user.email,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tctx.context.options.emailVerification?.expiresIn,\n\t\t\t\t\t);\n\t\t\t\t\tconst callbackURL = ctx.body.callbackURL\n\t\t\t\t\t\t? encodeURIComponent(ctx.body.callbackURL)\n\t\t\t\t\t\t: encodeURIComponent(\"/\");\n\t\t\t\t\tconst url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`;\n\t\t\t\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\t\t\t\tctx.context.options.emailVerification.sendVerificationEmail(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tuser: user.user,\n\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\ttoken,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tctx.request,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tthrow APIError.from(\"FORBIDDEN\", BASE_ERROR_CODES.EMAIL_NOT_VERIFIED);\n\t\t\t}\n\n\t\t\tconst session = await ctx.context.internalAdapter.createSession(\n\t\t\t\tuser.user.id,\n\t\t\t\tctx.body.rememberMe === false,\n\t\t\t);\n\n\t\t\tif (!session) {\n\t\t\t\tctx.context.logger.error(\"Failed to create session\");\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"UNAUTHORIZED\",\n\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_CREATE_SESSION,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tawait setSessionCookie(\n\t\t\t\tctx,\n\t\t\t\t{\n\t\t\t\t\tsession,\n\t\t\t\t\tuser: user.user,\n\t\t\t\t},\n\t\t\t\tctx.body.rememberMe === false,\n\t\t\t);\n\n\t\t\tif (ctx.body.callbackURL) {\n\t\t\t\tctx.setHeader(\"Location\", ctx.body.callbackURL);\n\t\t\t}\n\n\t\t\treturn ctx.json({\n\t\t\t\tredirect: !!ctx.body.callbackURL,\n\t\t\t\ttoken: session.token,\n\t\t\t\turl: ctx.body.callbackURL,\n\t\t\t\tuser: parseUserOutput(ctx.context.options, user.user) as User<\n\t\t\t\t\tO[\"user\"],\n\t\t\t\t\tO[\"plugins\"]\n\t\t\t\t>,\n\t\t\t});\n\t\t},\n\t);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sign-in.mjs","names":[],"sources":["../../../src/api/routes/sign-in.ts"],"sourcesContent":["import type { BetterAuthOptions } from \"@better-auth/core\";\nimport { createAuthEndpoint } from \"@better-auth/core/api\";\nimport type { User } from \"@better-auth/core/db\";\nimport { APIError, BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport { SocialProviderListEnum } from \"@better-auth/core/social-providers\";\nimport * as z from \"zod\";\nimport { getAwaitableValue } from \"../../context/helpers\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { parseUserOutput } from \"../../db/schema\";\nimport { handleOAuthUserInfo } from \"../../oauth2/link-account\";\nimport { generateState } from \"../../utils\";\nimport { formCsrfMiddleware } from \"../middlewares/origin-check\";\nimport { createEmailVerificationToken } from \"./email-verification\";\n\nconst socialSignInBodySchema = z.object({\n\t/**\n\t * Callback URL to redirect to after the user\n\t * has signed in.\n\t */\n\tcallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"Callback URL to redirect to after the user has signed in\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * callback url to redirect if the user is newly registered.\n\t *\n\t * useful if you have different routes for existing users and new users\n\t */\n\tnewUserCallbackURL: z.string().optional(),\n\t/**\n\t * Callback url to redirect to if an error happens\n\t *\n\t * If it's initiated from the client sdk this defaults to\n\t * the current url.\n\t */\n\terrorCallbackURL: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"Callback URL to redirect to if an error happens\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * OAuth2 provider to use`\n\t */\n\tprovider: SocialProviderListEnum,\n\t/**\n\t * Disable automatic redirection to the provider\n\t *\n\t * This is useful if you want to handle the redirection\n\t * yourself like in a popup or a different tab.\n\t */\n\tdisableRedirect: z\n\t\t.boolean()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"Disable automatic redirection to the provider. Useful for handling the redirection yourself\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * ID token from the provider\n\t *\n\t * This is used to sign in the user\n\t * if the user is already signed in with the\n\t * provider in the frontend.\n\t *\n\t * Only applicable if the provider supports\n\t * it. Currently only `apple` and `google` is\n\t * supported out of the box.\n\t */\n\tidToken: z.optional(\n\t\tz.object({\n\t\t\t/**\n\t\t\t * ID token from the provider\n\t\t\t */\n\t\t\ttoken: z.string().meta({\n\t\t\t\tdescription: \"ID token from the provider\",\n\t\t\t}),\n\t\t\t/**\n\t\t\t * The nonce used to generate the token\n\t\t\t */\n\t\t\tnonce: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"Nonce used to generate the token\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\t/**\n\t\t\t * Access token from the provider\n\t\t\t */\n\t\t\taccessToken: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"Access token from the provider\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\t/**\n\t\t\t * Refresh token from the provider\n\t\t\t */\n\t\t\trefreshToken: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"Refresh token from the provider\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\t/**\n\t\t\t * Expiry date of the token\n\t\t\t */\n\t\t\texpiresAt: z\n\t\t\t\t.number()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"Expiry date of the token\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\t/**\n\t\t\t * The user object from the provider.\n\t\t\t * This is only available for some providers like Apple.\n\t\t\t */\n\t\t\tuser: z\n\t\t\t\t.object({\n\t\t\t\t\tname: z\n\t\t\t\t\t\t.object({\n\t\t\t\t\t\t\tfirstName: z.string().optional(),\n\t\t\t\t\t\t\tlastName: z.string().optional(),\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.optional(),\n\t\t\t\t\temail: z.string().optional(),\n\t\t\t\t})\n\t\t\t\t.meta({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The user object from the provider. Only available for some providers like Apple.\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t),\n\tscopes: z\n\t\t.array(z.string())\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"Array of scopes to request from the provider. This will override the default scopes passed.\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Explicitly request sign-up\n\t *\n\t * Should be used to allow sign up when\n\t * disableImplicitSignUp for this provider is\n\t * true\n\t */\n\trequestSignUp: z\n\t\t.boolean()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * The login hint to use for the authorization code request\n\t */\n\tloginHint: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"The login hint to use for the authorization code request\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Additional data to be passed through the OAuth flow\n\t */\n\tadditionalData: z.record(z.string(), z.any()).optional().meta({\n\t\tdescription: \"Additional data to be passed through the OAuth flow\",\n\t}),\n});\n\nexport const signInSocial = <O extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/sign-in/social\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\toperationId: \"socialSignIn\",\n\t\t\tbody: socialSignInBodySchema,\n\t\t\tmetadata: {\n\t\t\t\t$Infer: {\n\t\t\t\t\tbody: {} as z.infer<typeof socialSignInBodySchema>,\n\t\t\t\t\treturned: {} as {\n\t\t\t\t\t\tredirect: boolean;\n\t\t\t\t\t\ttoken?: string | undefined;\n\t\t\t\t\t\turl?: string | undefined;\n\t\t\t\t\t\tuser?: User<O[\"user\"], O[\"plugins\"]> | undefined;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\topenapi: {\n\t\t\t\t\tdescription: \"Sign in with a social provider\",\n\t\t\t\t\toperationId: \"socialSignIn\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\"Success - Returns either session details or redirect URL\",\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\t// todo: we need support for multiple schema\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tdescription: \"Session response when idToken is provided\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\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\ttype: \"object\",\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\turl: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tredirect: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\tenum: [false],\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: [\"redirect\", \"token\", \"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\tc,\n\t\t): Promise<\n\t\t\t| { redirect: boolean; url: string }\n\t\t\t| {\n\t\t\t\t\tredirect: boolean;\n\t\t\t\t\ttoken: string;\n\t\t\t\t\turl: undefined;\n\t\t\t\t\tuser: User<O[\"user\"], O[\"plugins\"]>;\n\t\t\t }\n\t\t> => {\n\t\t\tconst provider = await getAwaitableValue(c.context.socialProviders, {\n\t\t\t\tvalue: c.body.provider,\n\t\t\t});\n\t\t\tif (!provider) {\n\t\t\t\tc.context.logger.error(\n\t\t\t\t\t\"Provider not found. Make sure to add the provider in your auth config\",\n\t\t\t\t\t{\n\t\t\t\t\t\tprovider: c.body.provider,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tthrow APIError.from(\"NOT_FOUND\", BASE_ERROR_CODES.PROVIDER_NOT_FOUND);\n\t\t\t}\n\n\t\t\tif (c.body.idToken) {\n\t\t\t\tif (!provider.verifyIdToken) {\n\t\t\t\t\tc.context.logger.error(\n\t\t\t\t\t\t\"Provider does not support id token verification\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tprovider: c.body.provider,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"NOT_FOUND\",\n\t\t\t\t\t\tBASE_ERROR_CODES.ID_TOKEN_NOT_SUPPORTED,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst { token, nonce } = c.body.idToken;\n\t\t\t\tconst valid = await provider.verifyIdToken(token, nonce);\n\t\t\t\tif (!valid) {\n\t\t\t\t\tc.context.logger.error(\"Invalid id token\", {\n\t\t\t\t\t\tprovider: c.body.provider,\n\t\t\t\t\t});\n\t\t\t\t\tthrow APIError.from(\"UNAUTHORIZED\", BASE_ERROR_CODES.INVALID_TOKEN);\n\t\t\t\t}\n\t\t\t\tconst userInfo = await provider.getUserInfo({\n\t\t\t\t\tidToken: token,\n\t\t\t\t\taccessToken: c.body.idToken.accessToken,\n\t\t\t\t\trefreshToken: c.body.idToken.refreshToken,\n\t\t\t\t\tuser: c.body.idToken.user,\n\t\t\t\t});\n\t\t\t\tif (!userInfo || !userInfo?.user) {\n\t\t\t\t\tc.context.logger.error(\"Failed to get user info\", {\n\t\t\t\t\t\tprovider: c.body.provider,\n\t\t\t\t\t});\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"UNAUTHORIZED\",\n\t\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_GET_USER_INFO,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (!userInfo.user.email) {\n\t\t\t\t\tc.context.logger.error(\"User email not found\", {\n\t\t\t\t\t\tprovider: c.body.provider,\n\t\t\t\t\t});\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"UNAUTHORIZED\",\n\t\t\t\t\t\tBASE_ERROR_CODES.USER_EMAIL_NOT_FOUND,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst data = await handleOAuthUserInfo(c, {\n\t\t\t\t\tuserInfo: {\n\t\t\t\t\t\t...userInfo.user,\n\t\t\t\t\t\temail: userInfo.user.email,\n\t\t\t\t\t\tid: String(userInfo.user.id),\n\t\t\t\t\t\tname: userInfo.user.name || \"\",\n\t\t\t\t\t\timage: userInfo.user.image,\n\t\t\t\t\t\temailVerified: userInfo.user.emailVerified || false,\n\t\t\t\t\t},\n\t\t\t\t\taccount: {\n\t\t\t\t\t\tproviderId: provider.id,\n\t\t\t\t\t\taccountId: String(userInfo.user.id),\n\t\t\t\t\t\taccessToken: c.body.idToken.accessToken,\n\t\t\t\t\t},\n\t\t\t\t\tcallbackURL: c.body.callbackURL,\n\t\t\t\t\tdisableSignUp:\n\t\t\t\t\t\t(provider.disableImplicitSignUp && !c.body.requestSignUp) ||\n\t\t\t\t\t\tprovider.disableSignUp,\n\t\t\t\t});\n\t\t\t\tif (data.error) {\n\t\t\t\t\tthrow APIError.from(\"UNAUTHORIZED\", {\n\t\t\t\t\t\tmessage: data.error,\n\t\t\t\t\t\tcode: \"OAUTH_LINK_ERROR\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tawait setSessionCookie(c, data.data!);\n\t\t\t\treturn c.json({\n\t\t\t\t\tredirect: false,\n\t\t\t\t\ttoken: data.data!.session.token,\n\t\t\t\t\turl: undefined,\n\t\t\t\t\tuser: parseUserOutput(c.context.options, data.data!.user) as User<\n\t\t\t\t\t\tO[\"user\"],\n\t\t\t\t\t\tO[\"plugins\"]\n\t\t\t\t\t>,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst { codeVerifier, state } = await generateState(\n\t\t\t\tc,\n\t\t\t\tundefined,\n\t\t\t\tc.body.additionalData,\n\t\t\t);\n\t\t\tconst url = await provider.createAuthorizationURL({\n\t\t\t\tstate,\n\t\t\t\tcodeVerifier,\n\t\t\t\tredirectURI: `${c.context.baseURL}/callback/${provider.id}`,\n\t\t\t\tscopes: c.body.scopes,\n\t\t\t\tloginHint: c.body.loginHint,\n\t\t\t});\n\n\t\t\tif (!c.body.disableRedirect) {\n\t\t\t\tc.setHeader(\"Location\", url.toString());\n\t\t\t}\n\n\t\t\treturn c.json({\n\t\t\t\turl: url.toString(),\n\t\t\t\tredirect: !c.body.disableRedirect,\n\t\t\t});\n\t\t},\n\t);\n\nexport const signInEmail = <O extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/sign-in/email\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\toperationId: \"signInEmail\",\n\t\t\tuse: [formCsrfMiddleware],\n\t\t\tbody: z.object({\n\t\t\t\t/**\n\t\t\t\t * Email of the user\n\t\t\t\t */\n\t\t\t\temail: z.string().meta({\n\t\t\t\t\tdescription: \"Email of the user\",\n\t\t\t\t}),\n\t\t\t\t/**\n\t\t\t\t * Password of the user\n\t\t\t\t */\n\t\t\t\tpassword: z.string().meta({\n\t\t\t\t\tdescription: \"Password of the user\",\n\t\t\t\t}),\n\t\t\t\t/**\n\t\t\t\t * Callback URL to use as a redirect for email\n\t\t\t\t * verification and for possible redirects\n\t\t\t\t */\n\t\t\t\tcallbackURL: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.meta({\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Callback URL to use as a redirect for email verification\",\n\t\t\t\t\t})\n\t\t\t\t\t.optional(),\n\t\t\t\t/**\n\t\t\t\t * If this is false, the session will not be remembered\n\t\t\t\t * @default true\n\t\t\t\t */\n\t\t\t\trememberMe: z\n\t\t\t\t\t.boolean()\n\t\t\t\t\t.meta({\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"If this is false, the session will not be remembered. Default is `true`.\",\n\t\t\t\t\t})\n\t\t\t\t\t.default(true)\n\t\t\t\t\t.optional(),\n\t\t\t}),\n\t\t\tmetadata: {\n\t\t\t\tallowedMediaTypes: [\n\t\t\t\t\t\"application/x-www-form-urlencoded\",\n\t\t\t\t\t\"application/json\",\n\t\t\t\t],\n\t\t\t\t$Infer: {\n\t\t\t\t\tbody: {} as {\n\t\t\t\t\t\temail: string;\n\t\t\t\t\t\tpassword: string;\n\t\t\t\t\t\tcallbackURL?: string | undefined;\n\t\t\t\t\t\trememberMe?: boolean | undefined;\n\t\t\t\t\t},\n\t\t\t\t\treturned: {} as {\n\t\t\t\t\t\tredirect: boolean;\n\t\t\t\t\t\ttoken: string;\n\t\t\t\t\t\turl?: string | undefined;\n\t\t\t\t\t\tuser: User<O[\"user\"], O[\"plugins\"]>;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"signInEmail\",\n\t\t\t\t\tdescription: \"Sign in with email and password\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\"Success - Returns either session details or redirect URL\",\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\t// todo: we need support for multiple schema\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tdescription: \"Session response when idToken is provided\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tredirect: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\tenum: [false],\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"Session token\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\turl: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\tnullable: true,\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\ttype: \"object\",\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: [\"redirect\", \"token\", \"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\tredirect: boolean;\n\t\t\ttoken: string;\n\t\t\turl?: string | undefined;\n\t\t\tuser: User<O[\"user\"], O[\"plugins\"]>;\n\t\t}> => {\n\t\t\tif (!ctx.context.options?.emailAndPassword?.enabled) {\n\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\"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!\",\n\t\t\t\t);\n\t\t\t\tthrow APIError.from(\"BAD_REQUEST\", {\n\t\t\t\t\tcode: \"EMAIL_PASSWORD_DISABLED\",\n\t\t\t\t\tmessage: \"Email and password is not enabled\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst { email, password } = ctx.body;\n\t\t\tconst isValidEmail = z.email().safeParse(email);\n\t\t\tif (!isValidEmail.success) {\n\t\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_EMAIL);\n\t\t\t}\n\t\t\tconst user = await ctx.context.internalAdapter.findUserByEmail(email, {\n\t\t\t\tincludeAccounts: true,\n\t\t\t});\n\n\t\t\tif (!user) {\n\t\t\t\t// Hash password to prevent timing attacks from revealing valid email addresses\n\t\t\t\t// By hashing passwords for invalid emails, we ensure consistent response times\n\t\t\t\tawait ctx.context.password.hash(password);\n\t\t\t\tctx.context.logger.error(\"User not found\", { email });\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"UNAUTHORIZED\",\n\t\t\t\t\tBASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst credentialAccount = user.accounts.find(\n\t\t\t\t(a) => a.providerId === \"credential\",\n\t\t\t);\n\t\t\tif (!credentialAccount) {\n\t\t\t\tawait ctx.context.password.hash(password);\n\t\t\t\tctx.context.logger.error(\"Credential account not found\", { email });\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"UNAUTHORIZED\",\n\t\t\t\t\tBASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst currentPassword = credentialAccount?.password;\n\t\t\tif (!currentPassword) {\n\t\t\t\tawait ctx.context.password.hash(password);\n\t\t\t\tctx.context.logger.error(\"Password not found\", { email });\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"UNAUTHORIZED\",\n\t\t\t\t\tBASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst validPassword = await ctx.context.password.verify({\n\t\t\t\thash: currentPassword,\n\t\t\t\tpassword,\n\t\t\t});\n\t\t\tif (!validPassword) {\n\t\t\t\tctx.context.logger.error(\"Invalid password\");\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"UNAUTHORIZED\",\n\t\t\t\t\tBASE_ERROR_CODES.INVALID_EMAIL_OR_PASSWORD,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tctx.context.options?.emailAndPassword?.requireEmailVerification &&\n\t\t\t\t!user.user.emailVerified\n\t\t\t) {\n\t\t\t\tif (!ctx.context.options?.emailVerification?.sendVerificationEmail) {\n\t\t\t\t\tthrow APIError.from(\"FORBIDDEN\", BASE_ERROR_CODES.EMAIL_NOT_VERIFIED);\n\t\t\t\t}\n\n\t\t\t\tif (ctx.context.options?.emailVerification?.sendOnSignIn) {\n\t\t\t\t\tconst token = await createEmailVerificationToken(\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\tuser.user.email,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tctx.context.options.emailVerification?.expiresIn,\n\t\t\t\t\t);\n\t\t\t\t\tconst callbackURL = ctx.body.callbackURL\n\t\t\t\t\t\t? encodeURIComponent(ctx.body.callbackURL)\n\t\t\t\t\t\t: encodeURIComponent(\"/\");\n\t\t\t\t\tconst url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`;\n\t\t\t\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\t\t\t\tctx.context.options.emailVerification.sendVerificationEmail(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tuser: user.user,\n\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\ttoken,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tctx.request,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tthrow APIError.from(\"FORBIDDEN\", BASE_ERROR_CODES.EMAIL_NOT_VERIFIED);\n\t\t\t}\n\n\t\t\tconst session = await ctx.context.internalAdapter.createSession(\n\t\t\t\tuser.user.id,\n\t\t\t\tctx.body.rememberMe === false,\n\t\t\t);\n\n\t\t\tif (!session) {\n\t\t\t\tctx.context.logger.error(\"Failed to create session\");\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"UNAUTHORIZED\",\n\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_CREATE_SESSION,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tawait setSessionCookie(\n\t\t\t\tctx,\n\t\t\t\t{\n\t\t\t\t\tsession,\n\t\t\t\t\tuser: user.user,\n\t\t\t\t},\n\t\t\t\tctx.body.rememberMe === false,\n\t\t\t);\n\n\t\t\tif (ctx.body.callbackURL) {\n\t\t\t\tctx.setHeader(\"Location\", ctx.body.callbackURL);\n\t\t\t}\n\n\t\t\treturn ctx.json({\n\t\t\t\tredirect: !!ctx.body.callbackURL,\n\t\t\t\ttoken: session.token,\n\t\t\t\turl: ctx.body.callbackURL,\n\t\t\t\tuser: parseUserOutput(ctx.context.options, user.user) as User<\n\t\t\t\t\tO[\"user\"],\n\t\t\t\t\tO[\"plugins\"]\n\t\t\t\t>,\n\t\t\t});\n\t\t},\n\t);\n"],"mappings":"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"}
|
|
@@ -159,7 +159,8 @@ const signUpEmail = () => createAuthEndpoint("/sign-up/email", {
|
|
|
159
159
|
ctx.context.logger.error("Password is too long");
|
|
160
160
|
throw APIError.from("BAD_REQUEST", BASE_ERROR_CODES.PASSWORD_TOO_LONG);
|
|
161
161
|
}
|
|
162
|
-
const shouldReturnGenericDuplicateResponse = ctx.context.options.emailAndPassword.
|
|
162
|
+
const shouldReturnGenericDuplicateResponse = ctx.context.options.emailAndPassword.requireEmailVerification;
|
|
163
|
+
const shouldSkipAutoSignIn = ctx.context.options.emailAndPassword.autoSignIn === false || shouldReturnGenericDuplicateResponse;
|
|
163
164
|
const additionalUserFields = parseUserInput(ctx.context.options, rest, "create");
|
|
164
165
|
const normalizedEmail = email.toLowerCase();
|
|
165
166
|
const dbUser = await ctx.context.internalAdapter.findUserByEmail(normalizedEmail);
|
|
@@ -247,7 +248,7 @@ const signUpEmail = () => createAuthEndpoint("/sign-up/email", {
|
|
|
247
248
|
token
|
|
248
249
|
}, ctx.request));
|
|
249
250
|
}
|
|
250
|
-
if (
|
|
251
|
+
if (shouldSkipAutoSignIn) return ctx.json({
|
|
251
252
|
token: null,
|
|
252
253
|
user: parseUserOutput(ctx.context.options, createdUser)
|
|
253
254
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sign-up.mjs","names":[],"sources":["../../../src/api/routes/sign-up.ts"],"sourcesContent":["import type { BetterAuthOptions } from \"@better-auth/core\";\nimport { createAuthEndpoint } from \"@better-auth/core/api\";\nimport { runWithTransaction } from \"@better-auth/core/context\";\nimport { isDevelopment } from \"@better-auth/core/env\";\nimport { APIError, BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport { generateId } from \"@better-auth/core/utils/id\";\nimport * as z from \"zod\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { parseUserInput } from \"../../db\";\nimport { parseUserOutput } from \"../../db/schema\";\nimport type { AdditionalUserFieldsInput, User } from \"../../types\";\nimport { isAPIError } from \"../../utils/is-api-error\";\nimport { formCsrfMiddleware } from \"../middlewares/origin-check\";\nimport { createEmailVerificationToken } from \"./email-verification\";\n\nconst signUpEmailBodySchema = z\n\t.object({\n\t\tname: z.string(),\n\t\temail: z.email(),\n\t\tpassword: z.string().nonempty(),\n\t\timage: z.string().optional(),\n\t\tcallbackURL: z.string().optional(),\n\t\trememberMe: z.boolean().optional(),\n\t})\n\t.and(z.record(z.string(), z.any()));\n\nexport const signUpEmail = <O extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/sign-up/email\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\toperationId: \"signUpWithEmailAndPassword\",\n\t\t\tuse: [formCsrfMiddleware],\n\t\t\tbody: signUpEmailBodySchema,\n\t\t\tmetadata: {\n\t\t\t\tallowedMediaTypes: [\n\t\t\t\t\t\"application/x-www-form-urlencoded\",\n\t\t\t\t\t\"application/json\",\n\t\t\t\t],\n\t\t\t\t$Infer: {\n\t\t\t\t\tbody: {} as {\n\t\t\t\t\t\tname: string;\n\t\t\t\t\t\temail: string;\n\t\t\t\t\t\tpassword: string;\n\t\t\t\t\t\timage?: string | undefined;\n\t\t\t\t\t\tcallbackURL?: string | undefined;\n\t\t\t\t\t\trememberMe?: boolean | undefined;\n\t\t\t\t\t} & AdditionalUserFieldsInput<O>,\n\t\t\t\t\treturned: {} as {\n\t\t\t\t\t\ttoken: string | null;\n\t\t\t\t\t\tuser: User<O[\"user\"], O[\"plugins\"]>;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"signUpWithEmailAndPassword\",\n\t\t\t\t\tdescription: \"Sign up a user using email and password\",\n\t\t\t\t\trequestBody: {\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\tname: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"The name of the user\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\temail: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"The email of the user\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tpassword: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"The password of the user\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\timage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"The profile image URL of the user\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tcallbackURL: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\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\"The URL to use for email verification callback\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\trememberMe: {\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\"If this is false, the session will not be remembered. Default is `true`.\",\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: [\"name\", \"email\", \"password\"],\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\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"Successfully created user\",\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\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"Authentication token for the 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\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\t\t\tid: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The unique identifier of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\temail: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"email\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The email address of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\tname: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The name of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\timage: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"uri\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The profile image URL of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\temailVerified: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"Whether the email has been verified\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\tcreatedAt: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"date-time\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"When the user was created\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\tupdatedAt: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"date-time\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"When the user was last updated\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\trequired: [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"email\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"emailVerified\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"createdAt\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"updatedAt\",\n\t\t\t\t\t\t\t\t\t\t\t\t],\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: [\"user\"], // token is optional\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\t\"422\": {\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\"Unprocessable Entity. User already exists or failed to create user.\",\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\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\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},\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\treturn runWithTransaction(ctx.context.adapter, async () => {\n\t\t\t\tif (\n\t\t\t\t\t!ctx.context.options.emailAndPassword?.enabled ||\n\t\t\t\t\tctx.context.options.emailAndPassword?.disableSignUp\n\t\t\t\t) {\n\t\t\t\t\tthrow APIError.from(\"BAD_REQUEST\", {\n\t\t\t\t\t\tmessage: \"Email and password sign up is not enabled\",\n\t\t\t\t\t\tcode: \"EMAIL_PASSWORD_SIGN_UP_DISABLED\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst body = ctx.body as any as User & {\n\t\t\t\t\tpassword: string;\n\t\t\t\t\tcallbackURL?: string | undefined;\n\t\t\t\t\trememberMe?: boolean | undefined;\n\t\t\t\t} & {\n\t\t\t\t\t[key: string]: any;\n\t\t\t\t};\n\t\t\t\tconst {\n\t\t\t\t\tname,\n\t\t\t\t\temail,\n\t\t\t\t\tpassword,\n\t\t\t\t\timage,\n\t\t\t\t\tcallbackURL: _callbackURL,\n\t\t\t\t\trememberMe,\n\t\t\t\t\t...rest\n\t\t\t\t} = body;\n\t\t\t\tconst isValidEmail = z.email().safeParse(email);\n\n\t\t\t\tif (!isValidEmail.success) {\n\t\t\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_EMAIL);\n\t\t\t\t}\n\n\t\t\t\tif (!password || typeof password !== \"string\") {\n\t\t\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_PASSWORD);\n\t\t\t\t}\n\n\t\t\t\tconst minPasswordLength = ctx.context.password.config.minPasswordLength;\n\t\t\t\tif (password.length < minPasswordLength) {\n\t\t\t\t\tctx.context.logger.error(\"Password is too short\");\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\tBASE_ERROR_CODES.PASSWORD_TOO_SHORT,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst maxPasswordLength = ctx.context.password.config.maxPasswordLength;\n\t\t\t\tif (password.length > maxPasswordLength) {\n\t\t\t\t\tctx.context.logger.error(\"Password is too long\");\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\tBASE_ERROR_CODES.PASSWORD_TOO_LONG,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst shouldReturnGenericDuplicateResponse =\n\t\t\t\t\tctx.context.options.emailAndPassword.autoSignIn === false ||\n\t\t\t\t\tctx.context.options.emailAndPassword.requireEmailVerification;\n\t\t\t\tconst additionalUserFields = parseUserInput(\n\t\t\t\t\tctx.context.options,\n\t\t\t\t\trest,\n\t\t\t\t\t\"create\",\n\t\t\t\t);\n\t\t\t\tconst normalizedEmail = email.toLowerCase();\n\t\t\t\tconst dbUser =\n\t\t\t\t\tawait ctx.context.internalAdapter.findUserByEmail(normalizedEmail);\n\t\t\t\tif (dbUser?.user) {\n\t\t\t\t\tctx.context.logger.info(\n\t\t\t\t\t\t`Sign-up attempt for existing email: ${email}`,\n\t\t\t\t\t);\n\t\t\t\t\tif (shouldReturnGenericDuplicateResponse) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Hash the password to reduce timing differences\n\t\t\t\t\t\t * between existing and non-existing emails.\n\t\t\t\t\t\t */\n\t\t\t\t\t\tawait ctx.context.password.hash(password);\n\t\t\t\t\t\tif (ctx.context.options.emailAndPassword?.onExistingUserSignUp) {\n\t\t\t\t\t\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\t\t\t\t\t\tctx.context.options.emailAndPassword.onExistingUserSignUp(\n\t\t\t\t\t\t\t\t\t{ user: dbUser.user },\n\t\t\t\t\t\t\t\t\tctx.request,\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\tconst now = new Date();\n\t\t\t\t\t\tconst generatedId =\n\t\t\t\t\t\t\tctx.context.generateId({ model: \"user\" }) || generateId();\n\t\t\t\t\t\tconst coreFields = {\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\temail: normalizedEmail,\n\t\t\t\t\t\t\temailVerified: false,\n\t\t\t\t\t\t\timage: image || null,\n\t\t\t\t\t\t\tcreatedAt: now,\n\t\t\t\t\t\t\tupdatedAt: now,\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst customSyntheticUser =\n\t\t\t\t\t\t\tctx.context.options.emailAndPassword?.customSyntheticUser;\n\n\t\t\t\t\t\tlet syntheticUser: Record<string, unknown>;\n\t\t\t\t\t\tif (customSyntheticUser) {\n\t\t\t\t\t\t\t// Extract only user-defined additionalFields (not plugin fields)\n\t\t\t\t\t\t\tconst additionalFieldKeys = Object.keys(\n\t\t\t\t\t\t\t\tctx.context.options.user?.additionalFields ?? {},\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tconst additionalFields: Record<string, unknown> = {};\n\t\t\t\t\t\t\tfor (const key of additionalFieldKeys) {\n\t\t\t\t\t\t\t\tif (key in additionalUserFields) {\n\t\t\t\t\t\t\t\t\tadditionalFields[key] = additionalUserFields[key];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsyntheticUser = customSyntheticUser({\n\t\t\t\t\t\t\t\tcoreFields,\n\t\t\t\t\t\t\t\tadditionalFields,\n\t\t\t\t\t\t\t\tid: generatedId,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsyntheticUser = {\n\t\t\t\t\t\t\t\t...coreFields,\n\t\t\t\t\t\t\t\t...additionalUserFields,\n\t\t\t\t\t\t\t\tid: generatedId,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\ttoken: null,\n\t\t\t\t\t\t\tuser: parseUserOutput(\n\t\t\t\t\t\t\t\tctx.context.options,\n\t\t\t\t\t\t\t\tsyntheticUser as User,\n\t\t\t\t\t\t\t) as User<O[\"user\"], O[\"plugins\"]>,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"UNPROCESSABLE_ENTITY\",\n\t\t\t\t\t\tBASE_ERROR_CODES.USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * Hash the password\n\t\t\t\t *\n\t\t\t\t * This is done prior to creating the user\n\t\t\t\t * to ensure that any plugin that\n\t\t\t\t * may break the hashing should break\n\t\t\t\t * before the user is created.\n\t\t\t\t */\n\t\t\t\tconst hash = await ctx.context.password.hash(password);\n\t\t\t\tlet createdUser: User;\n\t\t\t\ttry {\n\t\t\t\t\tcreatedUser = await ctx.context.internalAdapter.createUser({\n\t\t\t\t\t\temail: normalizedEmail,\n\t\t\t\t\t\tname,\n\t\t\t\t\t\timage,\n\t\t\t\t\t\t...additionalUserFields,\n\t\t\t\t\t\temailVerified: false,\n\t\t\t\t\t});\n\t\t\t\t\tif (!createdUser) {\n\t\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_CREATE_USER,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tif (isDevelopment()) {\n\t\t\t\t\t\tctx.context.logger.error(\"Failed to create user\", e);\n\t\t\t\t\t}\n\t\t\t\t\tif (isAPIError(e)) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t\tctx.context.logger?.error(\"Failed to create user\", e);\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"UNPROCESSABLE_ENTITY\",\n\t\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_CREATE_USER,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (!createdUser) {\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"UNPROCESSABLE_ENTITY\",\n\t\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_CREATE_USER,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tawait ctx.context.internalAdapter.linkAccount({\n\t\t\t\t\tuserId: createdUser.id,\n\t\t\t\t\tproviderId: \"credential\",\n\t\t\t\t\taccountId: createdUser.id,\n\t\t\t\t\tpassword: hash,\n\t\t\t\t});\n\t\t\t\tconst shouldSendVerificationEmail =\n\t\t\t\t\tctx.context.options.emailVerification?.sendOnSignUp ??\n\t\t\t\t\tctx.context.options.emailAndPassword.requireEmailVerification;\n\t\t\t\tif (shouldSendVerificationEmail) {\n\t\t\t\t\tconst token = await createEmailVerificationToken(\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\tcreatedUser.email,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tctx.context.options.emailVerification?.expiresIn,\n\t\t\t\t\t);\n\t\t\t\t\tconst callbackURL = body.callbackURL\n\t\t\t\t\t\t? encodeURIComponent(body.callbackURL)\n\t\t\t\t\t\t: encodeURIComponent(\"/\");\n\t\t\t\t\tconst url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`;\n\n\t\t\t\t\tif (ctx.context.options.emailVerification?.sendVerificationEmail) {\n\t\t\t\t\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\t\t\t\t\tctx.context.options.emailVerification.sendVerificationEmail(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tuser: createdUser,\n\t\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\t\ttoken,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tctx.request,\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\tif (shouldReturnGenericDuplicateResponse) {\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\ttoken: null,\n\t\t\t\t\t\tuser: parseUserOutput(ctx.context.options, createdUser) as User<\n\t\t\t\t\t\t\tO[\"user\"],\n\t\t\t\t\t\t\tO[\"plugins\"]\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 = await ctx.context.internalAdapter.createSession(\n\t\t\t\t\tcreatedUser.id,\n\t\t\t\t\trememberMe === false,\n\t\t\t\t);\n\t\t\t\tif (!session) {\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_CREATE_SESSION,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tawait setSessionCookie(\n\t\t\t\t\tctx,\n\t\t\t\t\t{\n\t\t\t\t\t\tsession,\n\t\t\t\t\t\tuser: createdUser,\n\t\t\t\t\t},\n\t\t\t\t\trememberMe === false,\n\t\t\t\t);\n\t\t\t\treturn ctx.json({\n\t\t\t\t\ttoken: session.token,\n\t\t\t\t\tuser: parseUserOutput(ctx.context.options, createdUser) as User<\n\t\t\t\t\t\tO[\"user\"],\n\t\t\t\t\t\tO[\"plugins\"]\n\t\t\t\t\t>,\n\t\t\t\t});\n\t\t\t});\n\t\t},\n\t);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sign-up.mjs","names":[],"sources":["../../../src/api/routes/sign-up.ts"],"sourcesContent":["import type { BetterAuthOptions } from \"@better-auth/core\";\nimport { createAuthEndpoint } from \"@better-auth/core/api\";\nimport { runWithTransaction } from \"@better-auth/core/context\";\nimport { isDevelopment } from \"@better-auth/core/env\";\nimport { APIError, BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport { generateId } from \"@better-auth/core/utils/id\";\nimport * as z from \"zod\";\nimport { setSessionCookie } from \"../../cookies\";\nimport { parseUserInput } from \"../../db\";\nimport { parseUserOutput } from \"../../db/schema\";\nimport type { AdditionalUserFieldsInput, User } from \"../../types\";\nimport { isAPIError } from \"../../utils/is-api-error\";\nimport { formCsrfMiddleware } from \"../middlewares/origin-check\";\nimport { createEmailVerificationToken } from \"./email-verification\";\n\nconst signUpEmailBodySchema = z\n\t.object({\n\t\tname: z.string(),\n\t\temail: z.email(),\n\t\tpassword: z.string().nonempty(),\n\t\timage: z.string().optional(),\n\t\tcallbackURL: z.string().optional(),\n\t\trememberMe: z.boolean().optional(),\n\t})\n\t.and(z.record(z.string(), z.any()));\n\nexport const signUpEmail = <O extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/sign-up/email\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\toperationId: \"signUpWithEmailAndPassword\",\n\t\t\tuse: [formCsrfMiddleware],\n\t\t\tbody: signUpEmailBodySchema,\n\t\t\tmetadata: {\n\t\t\t\tallowedMediaTypes: [\n\t\t\t\t\t\"application/x-www-form-urlencoded\",\n\t\t\t\t\t\"application/json\",\n\t\t\t\t],\n\t\t\t\t$Infer: {\n\t\t\t\t\tbody: {} as {\n\t\t\t\t\t\tname: string;\n\t\t\t\t\t\temail: string;\n\t\t\t\t\t\tpassword: string;\n\t\t\t\t\t\timage?: string | undefined;\n\t\t\t\t\t\tcallbackURL?: string | undefined;\n\t\t\t\t\t\trememberMe?: boolean | undefined;\n\t\t\t\t\t} & AdditionalUserFieldsInput<O>,\n\t\t\t\t\treturned: {} as {\n\t\t\t\t\t\ttoken: string | null;\n\t\t\t\t\t\tuser: User<O[\"user\"], O[\"plugins\"]>;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"signUpWithEmailAndPassword\",\n\t\t\t\t\tdescription: \"Sign up a user using email and password\",\n\t\t\t\t\trequestBody: {\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\tname: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"The name of the user\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\temail: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"The email of the user\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tpassword: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"The password of the user\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\timage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"The profile image URL of the user\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tcallbackURL: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\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\"The URL to use for email verification callback\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\trememberMe: {\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\"If this is false, the session will not be remembered. Default is `true`.\",\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: [\"name\", \"email\", \"password\"],\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\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"Successfully created user\",\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\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"Authentication token for the 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\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\t\t\tid: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The unique identifier of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\temail: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"email\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The email address of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\tname: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The name of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\timage: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"uri\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The profile image URL of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\temailVerified: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"Whether the email has been verified\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\tcreatedAt: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"date-time\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"When the user was created\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\tupdatedAt: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"date-time\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"When the user was last updated\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\trequired: [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"email\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"emailVerified\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"createdAt\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"updatedAt\",\n\t\t\t\t\t\t\t\t\t\t\t\t],\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: [\"user\"], // token is optional\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\t\"422\": {\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\"Unprocessable Entity. User already exists or failed to create user.\",\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\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\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},\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\treturn runWithTransaction(ctx.context.adapter, async () => {\n\t\t\t\tif (\n\t\t\t\t\t!ctx.context.options.emailAndPassword?.enabled ||\n\t\t\t\t\tctx.context.options.emailAndPassword?.disableSignUp\n\t\t\t\t) {\n\t\t\t\t\tthrow APIError.from(\"BAD_REQUEST\", {\n\t\t\t\t\t\tmessage: \"Email and password sign up is not enabled\",\n\t\t\t\t\t\tcode: \"EMAIL_PASSWORD_SIGN_UP_DISABLED\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst body = ctx.body as any as User & {\n\t\t\t\t\tpassword: string;\n\t\t\t\t\tcallbackURL?: string | undefined;\n\t\t\t\t\trememberMe?: boolean | undefined;\n\t\t\t\t} & {\n\t\t\t\t\t[key: string]: any;\n\t\t\t\t};\n\t\t\t\tconst {\n\t\t\t\t\tname,\n\t\t\t\t\temail,\n\t\t\t\t\tpassword,\n\t\t\t\t\timage,\n\t\t\t\t\tcallbackURL: _callbackURL,\n\t\t\t\t\trememberMe,\n\t\t\t\t\t...rest\n\t\t\t\t} = body;\n\t\t\t\tconst isValidEmail = z.email().safeParse(email);\n\n\t\t\t\tif (!isValidEmail.success) {\n\t\t\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_EMAIL);\n\t\t\t\t}\n\n\t\t\t\tif (!password || typeof password !== \"string\") {\n\t\t\t\t\tthrow APIError.from(\"BAD_REQUEST\", BASE_ERROR_CODES.INVALID_PASSWORD);\n\t\t\t\t}\n\n\t\t\t\tconst minPasswordLength = ctx.context.password.config.minPasswordLength;\n\t\t\t\tif (password.length < minPasswordLength) {\n\t\t\t\t\tctx.context.logger.error(\"Password is too short\");\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\tBASE_ERROR_CODES.PASSWORD_TOO_SHORT,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst maxPasswordLength = ctx.context.password.config.maxPasswordLength;\n\t\t\t\tif (password.length > maxPasswordLength) {\n\t\t\t\t\tctx.context.logger.error(\"Password is too long\");\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\tBASE_ERROR_CODES.PASSWORD_TOO_LONG,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst shouldReturnGenericDuplicateResponse =\n\t\t\t\t\tctx.context.options.emailAndPassword.requireEmailVerification;\n\t\t\t\tconst shouldSkipAutoSignIn =\n\t\t\t\t\tctx.context.options.emailAndPassword.autoSignIn === false ||\n\t\t\t\t\tshouldReturnGenericDuplicateResponse;\n\t\t\t\tconst additionalUserFields = parseUserInput(\n\t\t\t\t\tctx.context.options,\n\t\t\t\t\trest,\n\t\t\t\t\t\"create\",\n\t\t\t\t);\n\t\t\t\tconst normalizedEmail = email.toLowerCase();\n\t\t\t\tconst dbUser =\n\t\t\t\t\tawait ctx.context.internalAdapter.findUserByEmail(normalizedEmail);\n\t\t\t\tif (dbUser?.user) {\n\t\t\t\t\tctx.context.logger.info(\n\t\t\t\t\t\t`Sign-up attempt for existing email: ${email}`,\n\t\t\t\t\t);\n\t\t\t\t\tif (shouldReturnGenericDuplicateResponse) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Hash the password to reduce timing differences\n\t\t\t\t\t\t * between existing and non-existing emails.\n\t\t\t\t\t\t */\n\t\t\t\t\t\tawait ctx.context.password.hash(password);\n\t\t\t\t\t\tif (ctx.context.options.emailAndPassword?.onExistingUserSignUp) {\n\t\t\t\t\t\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\t\t\t\t\t\tctx.context.options.emailAndPassword.onExistingUserSignUp(\n\t\t\t\t\t\t\t\t\t{ user: dbUser.user },\n\t\t\t\t\t\t\t\t\tctx.request,\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\tconst now = new Date();\n\t\t\t\t\t\tconst generatedId =\n\t\t\t\t\t\t\tctx.context.generateId({ model: \"user\" }) || generateId();\n\t\t\t\t\t\tconst coreFields = {\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\temail: normalizedEmail,\n\t\t\t\t\t\t\temailVerified: false,\n\t\t\t\t\t\t\timage: image || null,\n\t\t\t\t\t\t\tcreatedAt: now,\n\t\t\t\t\t\t\tupdatedAt: now,\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst customSyntheticUser =\n\t\t\t\t\t\t\tctx.context.options.emailAndPassword?.customSyntheticUser;\n\n\t\t\t\t\t\tlet syntheticUser: Record<string, unknown>;\n\t\t\t\t\t\tif (customSyntheticUser) {\n\t\t\t\t\t\t\t// Extract only user-defined additionalFields (not plugin fields)\n\t\t\t\t\t\t\tconst additionalFieldKeys = Object.keys(\n\t\t\t\t\t\t\t\tctx.context.options.user?.additionalFields ?? {},\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tconst additionalFields: Record<string, unknown> = {};\n\t\t\t\t\t\t\tfor (const key of additionalFieldKeys) {\n\t\t\t\t\t\t\t\tif (key in additionalUserFields) {\n\t\t\t\t\t\t\t\t\tadditionalFields[key] = additionalUserFields[key];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsyntheticUser = customSyntheticUser({\n\t\t\t\t\t\t\t\tcoreFields,\n\t\t\t\t\t\t\t\tadditionalFields,\n\t\t\t\t\t\t\t\tid: generatedId,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsyntheticUser = {\n\t\t\t\t\t\t\t\t...coreFields,\n\t\t\t\t\t\t\t\t...additionalUserFields,\n\t\t\t\t\t\t\t\tid: generatedId,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\ttoken: null,\n\t\t\t\t\t\t\tuser: parseUserOutput(\n\t\t\t\t\t\t\t\tctx.context.options,\n\t\t\t\t\t\t\t\tsyntheticUser as User,\n\t\t\t\t\t\t\t) as User<O[\"user\"], O[\"plugins\"]>,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"UNPROCESSABLE_ENTITY\",\n\t\t\t\t\t\tBASE_ERROR_CODES.USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * Hash the password\n\t\t\t\t *\n\t\t\t\t * This is done prior to creating the user\n\t\t\t\t * to ensure that any plugin that\n\t\t\t\t * may break the hashing should break\n\t\t\t\t * before the user is created.\n\t\t\t\t */\n\t\t\t\tconst hash = await ctx.context.password.hash(password);\n\t\t\t\tlet createdUser: User;\n\t\t\t\ttry {\n\t\t\t\t\tcreatedUser = await ctx.context.internalAdapter.createUser({\n\t\t\t\t\t\temail: normalizedEmail,\n\t\t\t\t\t\tname,\n\t\t\t\t\t\timage,\n\t\t\t\t\t\t...additionalUserFields,\n\t\t\t\t\t\temailVerified: false,\n\t\t\t\t\t});\n\t\t\t\t\tif (!createdUser) {\n\t\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_CREATE_USER,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tif (isDevelopment()) {\n\t\t\t\t\t\tctx.context.logger.error(\"Failed to create user\", e);\n\t\t\t\t\t}\n\t\t\t\t\tif (isAPIError(e)) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t\tctx.context.logger?.error(\"Failed to create user\", e);\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"UNPROCESSABLE_ENTITY\",\n\t\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_CREATE_USER,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (!createdUser) {\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"UNPROCESSABLE_ENTITY\",\n\t\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_CREATE_USER,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tawait ctx.context.internalAdapter.linkAccount({\n\t\t\t\t\tuserId: createdUser.id,\n\t\t\t\t\tproviderId: \"credential\",\n\t\t\t\t\taccountId: createdUser.id,\n\t\t\t\t\tpassword: hash,\n\t\t\t\t});\n\t\t\t\tconst shouldSendVerificationEmail =\n\t\t\t\t\tctx.context.options.emailVerification?.sendOnSignUp ??\n\t\t\t\t\tctx.context.options.emailAndPassword.requireEmailVerification;\n\t\t\t\tif (shouldSendVerificationEmail) {\n\t\t\t\t\tconst token = await createEmailVerificationToken(\n\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\tcreatedUser.email,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tctx.context.options.emailVerification?.expiresIn,\n\t\t\t\t\t);\n\t\t\t\t\tconst callbackURL = body.callbackURL\n\t\t\t\t\t\t? encodeURIComponent(body.callbackURL)\n\t\t\t\t\t\t: encodeURIComponent(\"/\");\n\t\t\t\t\tconst url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${callbackURL}`;\n\n\t\t\t\t\tif (ctx.context.options.emailVerification?.sendVerificationEmail) {\n\t\t\t\t\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\t\t\t\t\tctx.context.options.emailVerification.sendVerificationEmail(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tuser: createdUser,\n\t\t\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\t\t\ttoken,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tctx.request,\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\tif (shouldSkipAutoSignIn) {\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\ttoken: null,\n\t\t\t\t\t\tuser: parseUserOutput(ctx.context.options, createdUser) as User<\n\t\t\t\t\t\t\tO[\"user\"],\n\t\t\t\t\t\t\tO[\"plugins\"]\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 = await ctx.context.internalAdapter.createSession(\n\t\t\t\t\tcreatedUser.id,\n\t\t\t\t\trememberMe === false,\n\t\t\t\t);\n\t\t\t\tif (!session) {\n\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_CREATE_SESSION,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tawait setSessionCookie(\n\t\t\t\t\tctx,\n\t\t\t\t\t{\n\t\t\t\t\t\tsession,\n\t\t\t\t\t\tuser: createdUser,\n\t\t\t\t\t},\n\t\t\t\t\trememberMe === false,\n\t\t\t\t);\n\t\t\t\treturn ctx.json({\n\t\t\t\t\ttoken: session.token,\n\t\t\t\t\tuser: parseUserOutput(ctx.context.options, createdUser) as User<\n\t\t\t\t\t\tO[\"user\"],\n\t\t\t\t\t\tO[\"plugins\"]\n\t\t\t\t\t>,\n\t\t\t\t});\n\t\t\t});\n\t\t},\n\t);\n"],"mappings":"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"}
|
package/dist/client/index.d.mts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { HasRequiredKeys, Prettify, PrettifyDeep, RequiredKeysOf, StripEmptyObjects, UnionToIntersection } from "../types/helper.mjs";
|
|
2
|
+
import { CamelCase, InferCtx, InferRoute, InferRoutes, InferSignUpEmailCtx, InferUserUpdateCtx, MergeRoutes, PathToObject, ProxyRequest } from "./path-to-object.mjs";
|
|
2
3
|
import { BetterAuthClientOptions, BetterAuthClientPlugin, ClientAtomListener, ClientStore, InferActions, InferAdditionalFromClient, InferClientAPI, InferErrorCodes, InferSessionFromClient, InferUserFromClient, IsSignal, SessionQueryParams } from "./types.mjs";
|
|
3
4
|
import { BroadcastChannel, BroadcastListener, BroadcastMessage, getGlobalBroadcastChannel, kBroadcastChannel } from "./broadcast-channel.mjs";
|
|
4
5
|
import { FocusListener, FocusManager, kFocusManager } from "./focus-manager.mjs";
|
|
5
6
|
import { OnlineListener, OnlineManager, kOnlineManager } from "./online-manager.mjs";
|
|
6
7
|
import { parseJSON } from "./parser.mjs";
|
|
7
8
|
import { AuthQueryAtom, useAuthQuery } from "./query.mjs";
|
|
8
|
-
import { SessionRefreshOptions, createSessionRefreshManager } from "./session-refresh.mjs";
|
|
9
|
+
import { SessionRefreshOptions, SessionResponse, createSessionRefreshManager } from "./session-refresh.mjs";
|
|
9
10
|
import { AuthClient, createAuthClient } from "./vanilla.mjs";
|
|
10
11
|
import { AccessControl, ArrayElement, Role, Statements, SubArray, Subset } from "../plugins/access/types.mjs";
|
|
11
12
|
import { AuthorizeResponse, createAccessControl, role } from "../plugins/access/access.mjs";
|
|
@@ -31,5 +32,5 @@ declare function InferAuth<O extends {
|
|
|
31
32
|
options: BetterAuthOptions;
|
|
32
33
|
}>(): O["options"];
|
|
33
34
|
//#endregion
|
|
34
|
-
export { AccessControl, ArrayElement, AuthClient, AuthQueryAtom, AuthorizeResponse, BetterAuthClientOptions, BetterAuthClientPlugin, BroadcastChannel, BroadcastListener, BroadcastMessage, ClientAtomListener, ClientStore, type DBPrimitive, DefaultOrganizationPlugin, DynamicAccessControlEndpoints, type FocusListener, type FocusManager, HasRequiredKeys, InferActions, InferAdditionalFromClient, InferAuth, InferClientAPI, InferErrorCodes, InferInvitation, InferMember, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPlugin, InferSessionFromClient, InferTeam, InferUserFromClient, Invitation, InvitationInput, InvitationStatus, IsSignal, Member, MemberInput, type OnlineListener, type OnlineManager, Organization, OrganizationCreator, OrganizationEndpoints, OrganizationInput, OrganizationOptions, OrganizationPlugin, OrganizationRole, OrganizationSchema, Prettify, PrettifyDeep, RequiredKeysOf, Role, SessionQueryParams, SessionRefreshOptions, Statements, StripEmptyObjects, SubArray, Subset, Team, TeamEndpoints, TeamInput, TeamMember, TeamMemberInput, type UnionToIntersection, createAccessControl, createAuthClient, createSessionRefreshManager, defaultRolesSchema, getGlobalBroadcastChannel, getOrgAdapter, hasPermission, invitationSchema, invitationStatus, kBroadcastChannel, kFocusManager, kOnlineManager, memberSchema, organization, organizationRoleSchema, organizationSchema, parseJSON, parseRoles, role, roleSchema, teamMemberSchema, teamSchema, useAuthQuery };
|
|
35
|
+
export { AccessControl, ArrayElement, AuthClient, AuthQueryAtom, AuthorizeResponse, BetterAuthClientOptions, BetterAuthClientPlugin, BroadcastChannel, BroadcastListener, BroadcastMessage, CamelCase, ClientAtomListener, ClientStore, type DBPrimitive, DefaultOrganizationPlugin, DynamicAccessControlEndpoints, type FocusListener, type FocusManager, HasRequiredKeys, InferActions, InferAdditionalFromClient, InferAuth, InferClientAPI, InferCtx, InferErrorCodes, InferInvitation, InferMember, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPlugin, InferRoute, InferRoutes, InferSessionFromClient, InferSignUpEmailCtx, InferTeam, InferUserFromClient, InferUserUpdateCtx, Invitation, InvitationInput, InvitationStatus, IsSignal, Member, MemberInput, MergeRoutes, type OnlineListener, type OnlineManager, Organization, OrganizationCreator, OrganizationEndpoints, OrganizationInput, OrganizationOptions, OrganizationPlugin, OrganizationRole, OrganizationSchema, PathToObject, Prettify, PrettifyDeep, ProxyRequest, RequiredKeysOf, Role, SessionQueryParams, SessionRefreshOptions, SessionResponse, Statements, StripEmptyObjects, SubArray, Subset, Team, TeamEndpoints, TeamInput, TeamMember, TeamMemberInput, type UnionToIntersection, createAccessControl, createAuthClient, createSessionRefreshManager, defaultRolesSchema, getGlobalBroadcastChannel, getOrgAdapter, hasPermission, invitationSchema, invitationStatus, kBroadcastChannel, kFocusManager, kOnlineManager, memberSchema, organization, organizationRoleSchema, organizationSchema, parseJSON, parseRoles, role, roleSchema, teamMemberSchema, teamSchema, useAuthQuery };
|
|
35
36
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/client/index.ts"],"sourcesContent":["import type {\n\tBetterAuthClientPlugin,\n\tBetterAuthOptions,\n\tBetterAuthPlugin,\n} from \"@better-auth/core\";\n\nexport * from \"./broadcast-channel\";\nexport {\n\ttype FocusListener,\n\ttype FocusManager,\n\tkFocusManager,\n} from \"./focus-manager\";\nexport {\n\tkOnlineManager,\n\ttype OnlineListener,\n\ttype OnlineManager,\n} from \"./online-manager\";\nexport * from \"./parser\";\nexport * from \"./query\";\nexport * from \"./session-refresh\";\nexport * from \"./types\";\nexport * from \"./vanilla\";\n\nexport const InferPlugin = <T extends BetterAuthPlugin>() => {\n\treturn {\n\t\tid: \"infer-server-plugin\",\n\t\t$InferServerPlugin: {} as T,\n\t} satisfies BetterAuthClientPlugin;\n};\n\nexport function InferAuth<O extends { options: BetterAuthOptions }>() {\n\treturn {} as O[\"options\"];\n}\n\n//#region Necessary re-exports\nexport type * from \"@better-auth/core/db\";\nexport type { DBPrimitive } from \"@better-auth/core/db\";\nexport type * from \"@better-fetch/fetch\";\nexport type * from \"nanostores\";\nexport type * from \"../plugins/access\";\nexport type * from \"../plugins/organization\";\nexport type * from \"../types/helper\";\nexport type { UnionToIntersection } from \"../types/helper\";\n//#endregion\n"],"mappings":";;;;;;;;;AAuBA,MAAa,oBAAgD;AAC5D,QAAO;EACN,IAAI;EACJ,oBAAoB,EAAE;EACtB;;AAGF,SAAgB,YAAsD;AACrE,QAAO,EAAE"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/client/index.ts"],"sourcesContent":["import type {\n\tBetterAuthClientPlugin,\n\tBetterAuthOptions,\n\tBetterAuthPlugin,\n} from \"@better-auth/core\";\n\nexport * from \"./broadcast-channel\";\nexport {\n\ttype FocusListener,\n\ttype FocusManager,\n\tkFocusManager,\n} from \"./focus-manager\";\nexport {\n\tkOnlineManager,\n\ttype OnlineListener,\n\ttype OnlineManager,\n} from \"./online-manager\";\nexport * from \"./parser\";\nexport * from \"./query\";\nexport * from \"./session-refresh\";\nexport * from \"./types\";\nexport * from \"./vanilla\";\n\nexport const InferPlugin = <T extends BetterAuthPlugin>() => {\n\treturn {\n\t\tid: \"infer-server-plugin\",\n\t\t$InferServerPlugin: {} as T,\n\t} satisfies BetterAuthClientPlugin;\n};\n\nexport function InferAuth<O extends { options: BetterAuthOptions }>() {\n\treturn {} as O[\"options\"];\n}\n\n//#region Necessary re-exports\nexport type * from \"@better-auth/core/db\";\nexport type { DBPrimitive } from \"@better-auth/core/db\";\nexport type * from \"@better-fetch/fetch\";\nexport type * from \"nanostores\";\nexport type * from \"../plugins/access\";\nexport type * from \"../plugins/organization\";\nexport type * from \"../types/helper\";\nexport type { UnionToIntersection } from \"../types/helper\";\nexport type * from \"./path-to-object\";\n//#endregion\n"],"mappings":";;;;;;;;;AAuBA,MAAa,oBAAgD;AAC5D,QAAO;EACN,IAAI;EACJ,oBAAoB,EAAE;EACtB;;AAGF,SAAgB,YAAsD;AACrE,QAAO,EAAE"}
|
|
@@ -60,6 +60,11 @@ type InferRoute<API, COpts extends BetterAuthClientOptions> = API extends Record
|
|
|
60
60
|
throw: true;
|
|
61
61
|
} ? true : false>> : never : never> : {} : never;
|
|
62
62
|
type InferRoutes<API extends Record<string, Endpoint>, ClientOpts extends BetterAuthClientOptions> = MergeRoutes<InferRoute<API, ClientOpts>>;
|
|
63
|
+
type ProxyRequest = {
|
|
64
|
+
options?: ClientFetchOption<any, any> | undefined;
|
|
65
|
+
query?: any | undefined;
|
|
66
|
+
[key: string]: any;
|
|
67
|
+
};
|
|
63
68
|
//#endregion
|
|
64
|
-
export { InferRoute, InferRoutes };
|
|
69
|
+
export { CamelCase, InferCtx, InferRoute, InferRoutes, InferSignUpEmailCtx, InferUserUpdateCtx, MergeRoutes, PathToObject, ProxyRequest };
|
|
65
70
|
//# sourceMappingURL=path-to-object.d.mts.map
|
package/dist/client/query.mjs
CHANGED
|
@@ -38,9 +38,10 @@ const useAuthQuery = (initializedAtom, path, $fetch, options) => {
|
|
|
38
38
|
const retryAttempts = typeof request.retry === "number" ? request.retry : request.retry?.attempts;
|
|
39
39
|
const retryAttempt = request.retryAttempt || 0;
|
|
40
40
|
if (retryAttempts && retryAttempt < retryAttempts) return;
|
|
41
|
+
const isUnauthorized = context.error.status === 401;
|
|
41
42
|
value.set({
|
|
42
43
|
error: context.error,
|
|
43
|
-
data: null,
|
|
44
|
+
data: isUnauthorized ? null : value.get().data,
|
|
44
45
|
isPending: false,
|
|
45
46
|
isRefetching: false,
|
|
46
47
|
refetch: value.value.refetch
|
|
@@ -61,7 +62,7 @@ const useAuthQuery = (initializedAtom, path, $fetch, options) => {
|
|
|
61
62
|
}).catch((error) => {
|
|
62
63
|
value.set({
|
|
63
64
|
error,
|
|
64
|
-
data:
|
|
65
|
+
data: value.get().data,
|
|
65
66
|
isPending: false,
|
|
66
67
|
isRefetching: false,
|
|
67
68
|
refetch: value.value.refetch
|