better-auth 1.6.12 → 1.6.13

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.
Files changed (33) hide show
  1. package/dist/api/index.d.mts +4 -46
  2. package/dist/api/routes/account.d.mts +2 -23
  3. package/dist/api/routes/account.mjs +94 -73
  4. package/dist/api/routes/callback.mjs +3 -2
  5. package/dist/api/routes/password.mjs +1 -1
  6. package/dist/api/routes/session.mjs +1 -1
  7. package/dist/api/routes/sign-in.mjs +1 -1
  8. package/dist/api/routes/update-user.mjs +3 -3
  9. package/dist/client/fetch-plugins.mjs +2 -1
  10. package/dist/context/create-context.mjs +10 -14
  11. package/dist/db/internal-adapter.mjs +19 -20
  12. package/dist/oauth2/index.d.mts +2 -2
  13. package/dist/oauth2/index.mjs +3 -3
  14. package/dist/oauth2/link-account.d.mts +27 -1
  15. package/dist/oauth2/link-account.mjs +24 -1
  16. package/dist/package.mjs +1 -1
  17. package/dist/plugins/admin/routes.mjs +3 -3
  18. package/dist/plugins/anonymous/index.mjs +2 -2
  19. package/dist/plugins/email-otp/routes.mjs +1 -1
  20. package/dist/plugins/generic-oauth/routes.mjs +3 -2
  21. package/dist/plugins/mcp/index.mjs +2 -1
  22. package/dist/plugins/oauth-proxy/index.mjs +1 -1
  23. package/dist/plugins/oidc-provider/index.mjs +2 -1
  24. package/dist/plugins/one-tap/client.mjs +9 -2
  25. package/dist/plugins/one-tap/index.mjs +16 -39
  26. package/dist/plugins/organization/routes/crud-org.d.mts +4 -4
  27. package/dist/plugins/organization/routes/crud-org.mjs +2 -2
  28. package/dist/plugins/organization/types.d.mts +3 -3
  29. package/dist/plugins/phone-number/routes.mjs +1 -1
  30. package/dist/plugins/two-factor/backup-codes/index.d.mts +4 -3
  31. package/dist/plugins/two-factor/client.mjs +2 -1
  32. package/dist/test-utils/test-instance.d.mts +12 -138
  33. package/package.json +8 -8
package/dist/package.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "1.6.12";
2
+ var version = "1.6.13";
3
3
  //#endregion
4
4
  export { version };
@@ -462,7 +462,7 @@ const banUser = (opts) => createAuthEndpoint("/admin/ban-user", {
462
462
  banExpires: ctx.body.banExpiresIn ? getDate(ctx.body.banExpiresIn, "sec") : opts?.defaultBanExpiresIn ? getDate(opts.defaultBanExpiresIn, "sec") : void 0,
463
463
  updatedAt: /* @__PURE__ */ new Date()
464
464
  });
465
- await ctx.context.internalAdapter.deleteSessions(ctx.body.userId);
465
+ await ctx.context.internalAdapter.deleteUserSessions(ctx.body.userId);
466
466
  return ctx.json({ user: parseUserOutput(ctx.context.options, user) });
467
467
  });
468
468
  const impersonateUserBodySchema = z.object({ userId: z.coerce.string().meta({ description: "The user id" }) });
@@ -658,7 +658,7 @@ const revokeUserSessions = (opts) => createAuthEndpoint("/admin/revoke-user-sess
658
658
  options: opts,
659
659
  permissions: { session: ["revoke"] }
660
660
  })) throw APIError.from("FORBIDDEN", ADMIN_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS);
661
- await ctx.context.internalAdapter.deleteSessions(ctx.body.userId);
661
+ await ctx.context.internalAdapter.deleteUserSessions(ctx.body.userId);
662
662
  return ctx.json({ success: true });
663
663
  });
664
664
  const removeUserBodySchema = z.object({ userId: z.coerce.string().meta({ description: "The user id" }) });
@@ -703,7 +703,7 @@ const removeUser = (opts) => createAuthEndpoint("/admin/remove-user", {
703
703
  })) throw APIError.from("FORBIDDEN", ADMIN_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS);
704
704
  if (ctx.body.userId === ctx.context.session.user.id) throw APIError.from("BAD_REQUEST", ADMIN_ERROR_CODES.YOU_CANNOT_REMOVE_YOURSELF);
705
705
  if (!await ctx.context.internalAdapter.findUserById(ctx.body.userId)) throw APIError.from("NOT_FOUND", BASE_ERROR_CODES.USER_NOT_FOUND);
706
- await ctx.context.internalAdapter.deleteSessions(ctx.body.userId);
706
+ await ctx.context.internalAdapter.deleteUserSessions(ctx.body.userId);
707
707
  await ctx.context.internalAdapter.deleteUser(ctx.body.userId);
708
708
  return ctx.json({ success: true });
709
709
  });
@@ -102,7 +102,7 @@ const anonymous = (options) => {
102
102
  if (options?.disableDeleteAnonymousUser) throw APIError.from("BAD_REQUEST", ANONYMOUS_ERROR_CODES.DELETE_ANONYMOUS_USER_DISABLED);
103
103
  if (!session.user.isAnonymous) throw APIError.from("FORBIDDEN", ANONYMOUS_ERROR_CODES.USER_IS_NOT_ANONYMOUS);
104
104
  try {
105
- await ctx.context.internalAdapter.deleteSessions(session.user.id);
105
+ await ctx.context.internalAdapter.deleteUserSessions(session.user.id);
106
106
  } catch (error) {
107
107
  ctx.context.logger.error("Failed to delete anonymous user sessions", error);
108
108
  throw APIError.from("INTERNAL_SERVER_ERROR", ANONYMOUS_ERROR_CODES.FAILED_TO_DELETE_ANONYMOUS_USER_SESSIONS);
@@ -154,7 +154,7 @@ const anonymous = (options) => {
154
154
  const newSessionIsAnonymous = Boolean(newSessionUser?.isAnonymous);
155
155
  if (options?.disableDeleteAnonymousUser || isSameUser || newSessionIsAnonymous) return;
156
156
  try {
157
- await ctx.context.internalAdapter.deleteSessions(session.user.id);
157
+ await ctx.context.internalAdapter.deleteUserSessions(session.user.id);
158
158
  await ctx.context.internalAdapter.deleteUser(session.user.id);
159
159
  } catch (error) {
160
160
  ctx.context.logger.error("Failed to clean up anonymous user during post-link cleanup", {
@@ -585,7 +585,7 @@ const resetPasswordEmailOTP = (opts) => createAuthEndpoint("/email-otp/reset-pas
585
585
  else await ctx.context.internalAdapter.updatePassword(user.user.id, passwordHash);
586
586
  if (ctx.context.options.emailAndPassword?.onPasswordReset) await ctx.context.options.emailAndPassword.onPasswordReset({ user: user.user }, ctx.request);
587
587
  if (!user.user.emailVerified) await ctx.context.internalAdapter.updateUser(user.user.id, { emailVerified: true });
588
- if (ctx.context.options.emailAndPassword?.revokeSessionsOnPasswordReset) await ctx.context.internalAdapter.deleteSessions(user.user.id);
588
+ if (ctx.context.options.emailAndPassword?.revokeSessionsOnPasswordReset) await ctx.context.internalAdapter.deleteUserSessions(user.user.id);
589
589
  return ctx.json({ success: true });
590
590
  });
591
591
  const requestEmailChangeEmailOTPBodySchema = z.object({
@@ -1,10 +1,10 @@
1
1
  import { isAPIError } from "../../utils/is-api-error.mjs";
2
2
  import { setSessionCookie } from "../../cookies/index.mjs";
3
3
  import { missingEmailLogMessage, redirectOnError } from "../../oauth2/errors.mjs";
4
- import { generateState, parseState } from "../../oauth2/state.mjs";
5
4
  import { setTokenUtil } from "../../oauth2/utils.mjs";
5
+ import { applyUpdateUserInfoOnLink, handleOAuthUserInfo } from "../../oauth2/link-account.mjs";
6
+ import { generateState, parseState } from "../../oauth2/state.mjs";
6
7
  import { sessionMiddleware } from "../../api/routes/session.mjs";
7
- import { handleOAuthUserInfo } from "../../oauth2/link-account.mjs";
8
8
  import { HIDE_METADATA } from "../../utils/hide-metadata.mjs";
9
9
  import { APIError as APIError$1 } from "../../api/index.mjs";
10
10
  import { GENERIC_OAUTH_ERROR_CODES } from "./error-codes.mjs";
@@ -248,6 +248,7 @@ const oAuth2Callback = (options) => createAuthEndpoint("/oauth2/callback/:provid
248
248
  refreshToken: await setTokenUtil(tokens.refreshToken, ctx.context),
249
249
  idToken: tokens.idToken
250
250
  })) redirectOnError(ctx, resolvedErrorURL, "unable_to_link_account");
251
+ await applyUpdateUserInfoOnLink(ctx, link.userId, userInfo);
251
252
  let toRedirectTo;
252
253
  try {
253
254
  toRedirectTo = callbackURL.toString();
@@ -14,6 +14,7 @@ import { oidcProvider } from "../oidc-provider/index.mjs";
14
14
  import { authorizeMCPOAuth } from "./authorize.mjs";
15
15
  import { isProduction, logger } from "@better-auth/core/env";
16
16
  import { safeJSONParse } from "@better-auth/core/utils/json";
17
+ import { isSafeUrlScheme } from "@better-auth/core/utils/url";
17
18
  import { createAuthEndpoint, createAuthMiddleware } from "@better-auth/core/api";
18
19
  import * as z from "zod";
19
20
  import { base64 } from "@better-auth/utils/base64";
@@ -86,7 +87,7 @@ const getMCPProtectedResourceMetadata = (ctx, options) => {
86
87
  };
87
88
  };
88
89
  const registerMcpClientBodySchema = z.object({
89
- redirect_uris: z.array(z.string()),
90
+ redirect_uris: z.array(z.string().refine(isSafeUrlScheme, { message: "redirect_uri cannot use a javascript:, data:, or vbscript: scheme" })),
90
91
  token_endpoint_auth_method: z.enum([
91
92
  "none",
92
93
  "client_secret_basic",
@@ -5,8 +5,8 @@ import { parseSetCookieHeader } from "../../cookies/cookie-utils.mjs";
5
5
  import { symmetricDecrypt, symmetricEncrypt } from "../../crypto/index.mjs";
6
6
  import { setSessionCookie } from "../../cookies/index.mjs";
7
7
  import { redirectOnError } from "../../oauth2/errors.mjs";
8
- import { parseGenericState } from "../../state.mjs";
9
8
  import { handleOAuthUserInfo } from "../../oauth2/link-account.mjs";
9
+ import { parseGenericState } from "../../state.mjs";
10
10
  import { PACKAGE_VERSION } from "../../version.mjs";
11
11
  import { parseJSON } from "../../client/parser.mjs";
12
12
  import { checkSkipProxy, resolveCurrentURL, stripTrailingSlash } from "./utils.mjs";
@@ -15,6 +15,7 @@ import { authorize } from "./authorize.mjs";
15
15
  import { schema } from "./schema.mjs";
16
16
  import { defaultClientSecretHasher } from "./utils.mjs";
17
17
  import { getCurrentAuthContext } from "@better-auth/core/context";
18
+ import { isSafeUrlScheme } from "@better-auth/core/utils/url";
18
19
  import { createAuthEndpoint, createAuthMiddleware } from "@better-auth/core/api";
19
20
  import { deprecate } from "@better-auth/core/utils/deprecate";
20
21
  import * as z from "zod";
@@ -101,7 +102,7 @@ const oAuthConsentBodySchema = z.object({
101
102
  });
102
103
  const oAuth2TokenBodySchema = z.record(z.any(), z.any());
103
104
  const registerOAuthApplicationBodySchema = z.object({
104
- redirect_uris: z.array(z.string()).meta({ description: "A list of redirect URIs. Eg: [\"https://client.example.com/callback\"]" }),
105
+ redirect_uris: z.array(z.string().refine(isSafeUrlScheme, { message: "redirect_uri cannot use a javascript:, data:, or vbscript: scheme" })).meta({ description: "A list of redirect URIs. Eg: [\"https://client.example.com/callback\"]" }),
105
106
  token_endpoint_auth_method: z.enum([
106
107
  "none",
107
108
  "client_secret_basic",
@@ -1,4 +1,5 @@
1
1
  import { PACKAGE_VERSION } from "../../version.mjs";
2
+ import { isSafeUrlScheme } from "@better-auth/core/utils/url";
2
3
  //#region src/plugins/one-tap/client.ts
3
4
  let isRequestInProgress = false;
4
5
  function isFedCMSupported() {
@@ -49,7 +50,10 @@ const oneTapClient = (options) => {
49
50
  ...opts?.fetchOptions,
50
51
  ...fetchOptions
51
52
  });
52
- if (!opts?.fetchOptions && !fetchOptions || opts?.callbackURL) window.location.href = opts?.callbackURL ?? "/";
53
+ if (!opts?.fetchOptions && !fetchOptions || opts?.callbackURL) {
54
+ const target = opts?.callbackURL ?? "/";
55
+ if (isSafeUrlScheme(target)) window.location.href = target;
56
+ }
53
57
  }
54
58
  const { autoSelect, cancelOnTapOutside, context } = opts ?? {};
55
59
  const contextValue = context ?? options.context ?? "signin";
@@ -82,7 +86,10 @@ const oneTapClient = (options) => {
82
86
  ...opts?.fetchOptions,
83
87
  ...fetchOptions
84
88
  });
85
- if (!opts?.fetchOptions && !fetchOptions || opts?.callbackURL) window.location.href = opts?.callbackURL ?? "/";
89
+ if (!opts?.fetchOptions && !fetchOptions || opts?.callbackURL) {
90
+ const target = opts?.callbackURL ?? "/";
91
+ if (isSafeUrlScheme(target)) window.location.href = target;
92
+ }
86
93
  }
87
94
  const { autoSelect, cancelOnTapOutside, context } = opts ?? {};
88
95
  const contextValue = context ?? options.context ?? "signin";
@@ -1,5 +1,6 @@
1
1
  import { parseUserOutput } from "../../db/schema.mjs";
2
2
  import { setSessionCookie } from "../../cookies/index.mjs";
3
+ import { handleOAuthUserInfo } from "../../oauth2/link-account.mjs";
3
4
  import { APIError } from "../../api/index.mjs";
4
5
  import { PACKAGE_VERSION } from "../../version.mjs";
5
6
  import { toBoolean } from "../../utils/boolean.mjs";
@@ -47,51 +48,27 @@ const oneTap = (options) => ({
47
48
  }
48
49
  const { email: rawEmail, email_verified, name, picture, sub } = payload;
49
50
  if (!rawEmail) return ctx.json({ error: "Email not available in token" });
50
- const email = rawEmail.toLowerCase();
51
- const user = await ctx.context.internalAdapter.findUserByEmail(email);
52
- if (!user) {
53
- if (options?.disableSignup) throw new APIError("BAD_GATEWAY", { message: "User not found" });
54
- const newUser = await ctx.context.internalAdapter.createOAuthUser({
55
- email,
51
+ const result = await handleOAuthUserInfo(ctx, {
52
+ userInfo: {
53
+ id: sub,
54
+ email: rawEmail.toLowerCase(),
56
55
  emailVerified: typeof email_verified === "boolean" ? email_verified : toBoolean(email_verified),
57
- name,
56
+ name: name ?? "",
58
57
  image: picture
59
- }, {
60
- providerId: "google",
61
- accountId: sub
62
- });
63
- if (!newUser) throw new APIError("INTERNAL_SERVER_ERROR", { message: "Could not create user" });
64
- const session = await ctx.context.internalAdapter.createSession(newUser.user.id);
65
- await setSessionCookie(ctx, {
66
- user: newUser.user,
67
- session
68
- });
69
- return ctx.json({
70
- token: session.token,
71
- user: parseUserOutput(ctx.context.options, newUser.user)
72
- });
73
- }
74
- if (!await ctx.context.internalAdapter.findAccount(sub)) {
75
- const accountLinking = ctx.context.options.account?.accountLinking;
76
- const providerEmailVerified = typeof email_verified === "boolean" ? email_verified : toBoolean(email_verified);
77
- const requireLocalEmailVerified = accountLinking?.requireLocalEmailVerified ?? true;
78
- if (accountLinking?.enabled !== false && accountLinking?.disableImplicitLinking !== true && (!requireLocalEmailVerified || user.user.emailVerified) && (ctx.context.trustedProviders.includes("google") || providerEmailVerified)) await ctx.context.internalAdapter.linkAccount({
79
- userId: user.user.id,
58
+ },
59
+ account: {
80
60
  providerId: "google",
81
61
  accountId: sub,
82
- scope: "openid,profile,email",
83
- idToken
84
- });
85
- else throw new APIError("UNAUTHORIZED", { message: "Google identity cannot be linked: implicit account-linking is disabled, the local email is not verified, or the Google email_verified claim is false and Google is not a trusted provider" });
86
- }
87
- const session = await ctx.context.internalAdapter.createSession(user.user.id);
88
- await setSessionCookie(ctx, {
89
- user: user.user,
90
- session
62
+ idToken,
63
+ scope: "openid,profile,email"
64
+ },
65
+ disableSignUp: options?.disableSignup
91
66
  });
67
+ if (result.error) throw new APIError("UNAUTHORIZED", { message: result.error });
68
+ await setSessionCookie(ctx, result.data);
92
69
  return ctx.json({
93
- token: session.token,
94
- user: parseUserOutput(ctx.context.options, user.user)
70
+ token: result.data.session.token,
71
+ user: parseUserOutput(ctx.context.options, result.data.user)
95
72
  });
96
73
  }) },
97
74
  options
@@ -15,7 +15,7 @@ declare const createOrganization: <O extends OrganizationOptions>(options?: O |
15
15
  name: z.ZodString;
16
16
  slug: z.ZodString;
17
17
  userId: z.ZodOptional<z.ZodCoercedString<unknown>>;
18
- logo: z.ZodOptional<z.ZodString>;
18
+ logo: z.ZodOptional<z.ZodNullable<z.ZodString>>;
19
19
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
20
20
  keepCurrentActiveOrganization: z.ZodOptional<z.ZodBoolean>;
21
21
  }, z.core.$strip>;
@@ -55,7 +55,7 @@ declare const createOrganization: <O extends OrganizationOptions>(options?: O |
55
55
  name: string;
56
56
  slug: string;
57
57
  userId?: string | undefined;
58
- logo?: string | undefined;
58
+ logo?: string | null | undefined;
59
59
  metadata?: Record<string, any> | undefined;
60
60
  keepCurrentActiveOrganization?: boolean | undefined;
61
61
  };
@@ -165,7 +165,7 @@ declare const updateOrganization: <O extends OrganizationOptions>(options?: O |
165
165
  data: z.ZodObject<{
166
166
  name: z.ZodOptional<z.ZodOptional<z.ZodString>>;
167
167
  slug: z.ZodOptional<z.ZodOptional<z.ZodString>>;
168
- logo: z.ZodOptional<z.ZodOptional<z.ZodString>>;
168
+ logo: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
169
169
  metadata: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>>;
170
170
  }, z.core.$strip>;
171
171
  organizationId: z.ZodOptional<z.ZodString>;
@@ -207,7 +207,7 @@ declare const updateOrganization: <O extends OrganizationOptions>(options?: O |
207
207
  data: {
208
208
  name?: string | undefined;
209
209
  slug?: string | undefined;
210
- logo?: string | undefined;
210
+ logo?: string | null | undefined;
211
211
  metadata?: Record<string, any> | undefined;
212
212
  } & Partial<InferAdditionalFieldsFromPluginOptions<"organization", O>>;
213
213
  organizationId?: string | undefined;
@@ -13,7 +13,7 @@ const baseOrganizationSchema = z.object({
13
13
  name: z.string().min(1).meta({ description: "The name of the organization" }),
14
14
  slug: z.string().min(1).meta({ description: "The slug of the organization" }),
15
15
  userId: z.coerce.string().meta({ description: "The user id of the organization creator. If not provided, the current user will be used. Should only be used by admins or when called by the server. server-only. Eg: \"user-id\"" }).optional(),
16
- logo: z.string().meta({ description: "The logo of the organization" }).optional(),
16
+ logo: z.string().meta({ description: "The logo of the organization" }).nullish(),
17
17
  metadata: z.record(z.string(), z.any()).meta({ description: "The metadata of the organization" }).optional(),
18
18
  keepCurrentActiveOrganization: z.boolean().meta({ description: "Whether to keep the current active organization active after creating a new one. Eg: true" }).optional()
19
19
  });
@@ -160,7 +160,7 @@ const checkOrganizationSlug = (options) => createAuthEndpoint("/organization/che
160
160
  const baseUpdateOrganizationSchema = z.object({
161
161
  name: z.string().min(1).meta({ description: "The name of the organization" }).optional(),
162
162
  slug: z.string().min(1).meta({ description: "The slug of the organization" }).optional(),
163
- logo: z.string().meta({ description: "The logo of the organization" }).optional(),
163
+ logo: z.string().meta({ description: "The logo of the organization" }).nullish(),
164
164
  metadata: z.record(z.string(), z.any()).meta({ description: "The metadata of the organization" }).optional()
165
165
  });
166
166
  const updateOrganization = (options) => {
@@ -317,7 +317,7 @@ interface OrganizationOptions {
317
317
  organization: {
318
318
  name?: string;
319
319
  slug?: string;
320
- logo?: string;
320
+ logo?: string | null;
321
321
  metadata?: Record<string, any>;
322
322
  [key: string]: any;
323
323
  };
@@ -348,7 +348,7 @@ interface OrganizationOptions {
348
348
  organization: {
349
349
  name?: string;
350
350
  slug?: string;
351
- logo?: string;
351
+ logo?: string | null;
352
352
  metadata?: Record<string, any>;
353
353
  [key: string]: any;
354
354
  };
@@ -358,7 +358,7 @@ interface OrganizationOptions {
358
358
  data: {
359
359
  name?: string;
360
360
  slug?: string;
361
- logo?: string;
361
+ logo?: string | null;
362
362
  metadata?: Record<string, any>;
363
363
  [key: string]: any;
364
364
  };
@@ -470,7 +470,7 @@ const resetPasswordPhoneNumber = (opts) => createAuthEndpoint("/phone-number/res
470
470
  else await ctx.context.internalAdapter.updatePassword(user.id, hashedPassword);
471
471
  await ctx.context.internalAdapter.deleteVerificationByIdentifier(phoneResetIdentifier);
472
472
  if (ctx.context.options.emailAndPassword?.onPasswordReset) await ctx.context.options.emailAndPassword.onPasswordReset({ user }, ctx.request);
473
- if (ctx.context.options.emailAndPassword?.revokeSessionsOnPasswordReset) await ctx.context.internalAdapter.deleteSessions(user.id);
473
+ if (ctx.context.options.emailAndPassword?.revokeSessionsOnPasswordReset) await ctx.context.internalAdapter.deleteUserSessions(user.id);
474
474
  return ctx.json({ status: true });
475
475
  });
476
476
  function generateOTP(size) {
@@ -264,9 +264,10 @@ declare const backupCode2fa: (opts: BackupCodeOptions) => {
264
264
  backupCodes: string[];
265
265
  }>;
266
266
  /**
267
- * ### Endpoint
268
- *
269
- * POST `/two-factor/view-backup-codes`
267
+ * A server-only function that returns a user's decrypted two-factor
268
+ * backup codes. It is not exposed over HTTP and has no client method;
269
+ * call it from trusted server code with a `userId` taken from an
270
+ * authenticated session.
270
271
  *
271
272
  * ### API Methods
272
273
  *
@@ -1,5 +1,6 @@
1
1
  import { PACKAGE_VERSION } from "../../version.mjs";
2
2
  import { TWO_FACTOR_ERROR_CODES } from "./error-code.mjs";
3
+ import { isSafeUrlScheme } from "@better-auth/core/utils/url";
3
4
  //#region src/plugins/two-factor/client.ts
4
5
  const twoFactorClient = (options) => {
5
6
  return {
@@ -29,7 +30,7 @@ const twoFactorClient = (options) => {
29
30
  await options.onTwoFactorRedirect({ twoFactorMethods: context.data.twoFactorMethods });
30
31
  return;
31
32
  }
32
- if (options?.twoFactorPage && typeof window !== "undefined") window.location.href = options.twoFactorPage;
33
+ if (options?.twoFactorPage && typeof window !== "undefined" && isSafeUrlScheme(options.twoFactorPage)) window.location.href = options.twoFactorPage;
33
34
  }
34
35
  } }
35
36
  }],
@@ -1943,29 +1943,6 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
1943
1943
  }>;
1944
1944
  readonly accountInfo: better_call0.StrictEndpoint<"/account-info", {
1945
1945
  method: "GET";
1946
- use: ((inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<{
1947
- session: {
1948
- session: Record<string, any> & {
1949
- id: string;
1950
- createdAt: Date;
1951
- updatedAt: Date;
1952
- userId: string;
1953
- expiresAt: Date;
1954
- token: string;
1955
- ipAddress?: string | null | undefined;
1956
- userAgent?: string | null | undefined;
1957
- };
1958
- user: Record<string, any> & {
1959
- id: string;
1960
- createdAt: Date;
1961
- updatedAt: Date;
1962
- email: string;
1963
- emailVerified: boolean;
1964
- name: string;
1965
- image?: string | null | undefined;
1966
- };
1967
- };
1968
- }>)[];
1969
1946
  metadata: {
1970
1947
  openapi: {
1971
1948
  description: string;
@@ -2015,6 +1992,8 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
2015
1992
  };
2016
1993
  query: zod.ZodOptional<zod.ZodObject<{
2017
1994
  accountId: zod.ZodOptional<zod.ZodString>;
1995
+ providerId: zod.ZodOptional<zod.ZodString>;
1996
+ userId: zod.ZodOptional<zod.ZodString>;
2018
1997
  }, zod_v4_core0.$strip>>;
2019
1998
  }, {
2020
1999
  user: _better_auth_core_oauth20.OAuth2UserInfo;
@@ -3948,29 +3927,6 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
3948
3927
  }>;
3949
3928
  readonly accountInfo: better_call0.StrictEndpoint<"/account-info", {
3950
3929
  method: "GET";
3951
- use: ((inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<{
3952
- session: {
3953
- session: Record<string, any> & {
3954
- id: string;
3955
- createdAt: Date;
3956
- updatedAt: Date;
3957
- userId: string;
3958
- expiresAt: Date;
3959
- token: string;
3960
- ipAddress?: string | null | undefined;
3961
- userAgent?: string | null | undefined;
3962
- };
3963
- user: Record<string, any> & {
3964
- id: string;
3965
- createdAt: Date;
3966
- updatedAt: Date;
3967
- email: string;
3968
- emailVerified: boolean;
3969
- name: string;
3970
- image?: string | null | undefined;
3971
- };
3972
- };
3973
- }>)[];
3974
3930
  metadata: {
3975
3931
  openapi: {
3976
3932
  description: string;
@@ -4020,6 +3976,8 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
4020
3976
  };
4021
3977
  query: zod.ZodOptional<zod.ZodObject<{
4022
3978
  accountId: zod.ZodOptional<zod.ZodString>;
3979
+ providerId: zod.ZodOptional<zod.ZodString>;
3980
+ userId: zod.ZodOptional<zod.ZodString>;
4023
3981
  }, zod_v4_core0.$strip>>;
4024
3982
  }, {
4025
3983
  user: _better_auth_core_oauth20.OAuth2UserInfo;
@@ -5956,29 +5914,6 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
5956
5914
  }>;
5957
5915
  readonly accountInfo: better_call0.StrictEndpoint<"/account-info", {
5958
5916
  method: "GET";
5959
- use: ((inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<{
5960
- session: {
5961
- session: Record<string, any> & {
5962
- id: string;
5963
- createdAt: Date;
5964
- updatedAt: Date;
5965
- userId: string;
5966
- expiresAt: Date;
5967
- token: string;
5968
- ipAddress?: string | null | undefined;
5969
- userAgent?: string | null | undefined;
5970
- };
5971
- user: Record<string, any> & {
5972
- id: string;
5973
- createdAt: Date;
5974
- updatedAt: Date;
5975
- email: string;
5976
- emailVerified: boolean;
5977
- name: string;
5978
- image?: string | null | undefined;
5979
- };
5980
- };
5981
- }>)[];
5982
5917
  metadata: {
5983
5918
  openapi: {
5984
5919
  description: string;
@@ -6028,6 +5963,8 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
6028
5963
  };
6029
5964
  query: zod.ZodOptional<zod.ZodObject<{
6030
5965
  accountId: zod.ZodOptional<zod.ZodString>;
5966
+ providerId: zod.ZodOptional<zod.ZodString>;
5967
+ userId: zod.ZodOptional<zod.ZodString>;
6031
5968
  }, zod_v4_core0.$strip>>;
6032
5969
  }, {
6033
5970
  user: _better_auth_core_oauth20.OAuth2UserInfo;
@@ -7961,29 +7898,6 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
7961
7898
  }>;
7962
7899
  readonly accountInfo: better_call0.StrictEndpoint<"/account-info", {
7963
7900
  method: "GET";
7964
- use: ((inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<{
7965
- session: {
7966
- session: Record<string, any> & {
7967
- id: string;
7968
- createdAt: Date;
7969
- updatedAt: Date;
7970
- userId: string;
7971
- expiresAt: Date;
7972
- token: string;
7973
- ipAddress?: string | null | undefined;
7974
- userAgent?: string | null | undefined;
7975
- };
7976
- user: Record<string, any> & {
7977
- id: string;
7978
- createdAt: Date;
7979
- updatedAt: Date;
7980
- email: string;
7981
- emailVerified: boolean;
7982
- name: string;
7983
- image?: string | null | undefined;
7984
- };
7985
- };
7986
- }>)[];
7987
7901
  metadata: {
7988
7902
  openapi: {
7989
7903
  description: string;
@@ -8033,6 +7947,8 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
8033
7947
  };
8034
7948
  query: zod.ZodOptional<zod.ZodObject<{
8035
7949
  accountId: zod.ZodOptional<zod.ZodString>;
7950
+ providerId: zod.ZodOptional<zod.ZodString>;
7951
+ userId: zod.ZodOptional<zod.ZodString>;
8036
7952
  }, zod_v4_core0.$strip>>;
8037
7953
  }, {
8038
7954
  user: _better_auth_core_oauth20.OAuth2UserInfo;
@@ -10040,29 +9956,6 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
10040
9956
  }>;
10041
9957
  readonly accountInfo: better_call0.StrictEndpoint<"/account-info", {
10042
9958
  method: "GET";
10043
- use: ((inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<{
10044
- session: {
10045
- session: Record<string, any> & {
10046
- id: string;
10047
- createdAt: Date;
10048
- updatedAt: Date;
10049
- userId: string;
10050
- expiresAt: Date;
10051
- token: string;
10052
- ipAddress?: string | null | undefined;
10053
- userAgent?: string | null | undefined;
10054
- };
10055
- user: Record<string, any> & {
10056
- id: string;
10057
- createdAt: Date;
10058
- updatedAt: Date;
10059
- email: string;
10060
- emailVerified: boolean;
10061
- name: string;
10062
- image?: string | null | undefined;
10063
- };
10064
- };
10065
- }>)[];
10066
9959
  metadata: {
10067
9960
  openapi: {
10068
9961
  description: string;
@@ -10112,6 +10005,8 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
10112
10005
  };
10113
10006
  query: zod.ZodOptional<zod.ZodObject<{
10114
10007
  accountId: zod.ZodOptional<zod.ZodString>;
10008
+ providerId: zod.ZodOptional<zod.ZodString>;
10009
+ userId: zod.ZodOptional<zod.ZodString>;
10115
10010
  }, zod_v4_core0.$strip>>;
10116
10011
  }, {
10117
10012
  user: _better_auth_core_oauth20.OAuth2UserInfo;
@@ -12045,29 +11940,6 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
12045
11940
  }>;
12046
11941
  readonly accountInfo: better_call0.StrictEndpoint<"/account-info", {
12047
11942
  method: "GET";
12048
- use: ((inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<{
12049
- session: {
12050
- session: Record<string, any> & {
12051
- id: string;
12052
- createdAt: Date;
12053
- updatedAt: Date;
12054
- userId: string;
12055
- expiresAt: Date;
12056
- token: string;
12057
- ipAddress?: string | null | undefined;
12058
- userAgent?: string | null | undefined;
12059
- };
12060
- user: Record<string, any> & {
12061
- id: string;
12062
- createdAt: Date;
12063
- updatedAt: Date;
12064
- email: string;
12065
- emailVerified: boolean;
12066
- name: string;
12067
- image?: string | null | undefined;
12068
- };
12069
- };
12070
- }>)[];
12071
11943
  metadata: {
12072
11944
  openapi: {
12073
11945
  description: string;
@@ -12117,6 +11989,8 @@ declare function getTestInstance<O extends Partial<BetterAuthOptions>, C extends
12117
11989
  };
12118
11990
  query: zod.ZodOptional<zod.ZodObject<{
12119
11991
  accountId: zod.ZodOptional<zod.ZodString>;
11992
+ providerId: zod.ZodOptional<zod.ZodString>;
11993
+ userId: zod.ZodOptional<zod.ZodString>;
12120
11994
  }, zod_v4_core0.$strip>>;
12121
11995
  }, {
12122
11996
  user: _better_auth_core_oauth20.OAuth2UserInfo;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-auth",
3
- "version": "1.6.12",
3
+ "version": "1.6.13",
4
4
  "description": "The most comprehensive authentication framework for TypeScript.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -489,13 +489,13 @@
489
489
  "kysely": "^0.28.17 || ^0.29.0",
490
490
  "nanostores": "^1.1.1",
491
491
  "zod": "^4.3.6",
492
- "@better-auth/core": "1.6.12",
493
- "@better-auth/drizzle-adapter": "1.6.12",
494
- "@better-auth/memory-adapter": "1.6.12",
495
- "@better-auth/mongo-adapter": "1.6.12",
496
- "@better-auth/kysely-adapter": "1.6.12",
497
- "@better-auth/prisma-adapter": "1.6.12",
498
- "@better-auth/telemetry": "1.6.12"
492
+ "@better-auth/core": "1.6.13",
493
+ "@better-auth/drizzle-adapter": "1.6.13",
494
+ "@better-auth/kysely-adapter": "1.6.13",
495
+ "@better-auth/memory-adapter": "1.6.13",
496
+ "@better-auth/mongo-adapter": "1.6.13",
497
+ "@better-auth/prisma-adapter": "1.6.13",
498
+ "@better-auth/telemetry": "1.6.13"
499
499
  },
500
500
  "devDependencies": {
501
501
  "@lynx-js/react": "^0.116.3",