better-auth 1.7.1 → 1.7.3

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 (77) hide show
  1. package/dist/api/index.d.mts +6 -22
  2. package/dist/api/index.mjs +2 -0
  3. package/dist/api/middlewares/origin-check.mjs +9 -5
  4. package/dist/api/routes/account.d.mts +1 -9
  5. package/dist/api/routes/account.mjs +0 -6
  6. package/dist/api/routes/callback.mjs +7 -7
  7. package/dist/api/routes/email-verification.mjs +4 -2
  8. package/dist/api/routes/error.mjs +12 -8
  9. package/dist/api/routes/password.mjs +0 -2
  10. package/dist/api/routes/session.mjs +12 -5
  11. package/dist/api/routes/sign-in.d.mts +2 -2
  12. package/dist/api/routes/sign-in.mjs +1 -4
  13. package/dist/api/routes/sign-up.mjs +0 -2
  14. package/dist/api/routes/update-user.mjs +0 -2
  15. package/dist/api/to-auth-endpoints.mjs +2 -0
  16. package/dist/auth/base.mjs +13 -1
  17. package/dist/auth/trusted-origins.mjs +24 -5
  18. package/dist/client/config.d.mts +2 -0
  19. package/dist/client/config.mjs +1 -0
  20. package/dist/client/lynx/index.d.mts +1 -1
  21. package/dist/client/react/index.d.mts +1 -1
  22. package/dist/client/solid/index.d.mts +1 -1
  23. package/dist/client/svelte/index.d.mts +1 -1
  24. package/dist/client/vanilla.d.mts +1 -1
  25. package/dist/client/vue/index.d.mts +32 -21
  26. package/dist/client/vue/index.mjs +23 -5
  27. package/dist/context/create-context.mjs +2 -0
  28. package/dist/cookies/cache.mjs +10 -2
  29. package/dist/cookies/session-store.d.mts +0 -1
  30. package/dist/cookies/session-store.mjs +16 -5
  31. package/dist/db/adapter-kysely.mjs +1 -2
  32. package/dist/db/get-migration.d.mts +1 -0
  33. package/dist/db/get-migration.mjs +49 -56
  34. package/dist/db/internal-adapter.mjs +17 -20
  35. package/dist/db/schema.d.mts +0 -1
  36. package/dist/db/with-hooks.mjs +7 -7
  37. package/dist/oauth2/account-key.mjs +1 -5
  38. package/dist/oauth2/errors.mjs +4 -3
  39. package/dist/oauth2/link-account.d.mts +0 -1
  40. package/dist/oauth2/link-account.mjs +5 -11
  41. package/dist/oauth2/state.mjs +1 -1
  42. package/dist/package.mjs +1 -1
  43. package/dist/plugins/admin/routes.mjs +1 -4
  44. package/dist/plugins/anonymous/index.mjs +5 -1
  45. package/dist/plugins/anonymous/types.d.mts +2 -3
  46. package/dist/plugins/device-authorization/index.d.mts +11 -11
  47. package/dist/plugins/email-otp/routes.mjs +0 -2
  48. package/dist/plugins/generic-oauth/index.mjs +14 -10
  49. package/dist/plugins/generic-oauth/providers/auth0.mjs +2 -4
  50. package/dist/plugins/generic-oauth/providers/keycloak.mjs +6 -9
  51. package/dist/plugins/generic-oauth/providers/line.mjs +0 -1
  52. package/dist/plugins/generic-oauth/providers/microsoft-entra-id.mjs +15 -5
  53. package/dist/plugins/generic-oauth/providers/okta.mjs +6 -9
  54. package/dist/plugins/generic-oauth/providers/slack.mjs +0 -1
  55. package/dist/plugins/generic-oauth/types.d.mts +0 -9
  56. package/dist/plugins/haveibeenpwned/index.d.mts +9 -1
  57. package/dist/plugins/haveibeenpwned/index.mjs +33 -13
  58. package/dist/plugins/index.d.mts +2 -2
  59. package/dist/plugins/index.mjs +2 -2
  60. package/dist/plugins/jwt/verify.mjs +2 -2
  61. package/dist/plugins/last-login-method/index.mjs +1 -0
  62. package/dist/plugins/oauth-proxy/index.d.mts +17 -0
  63. package/dist/plugins/oauth-proxy/index.mjs +145 -99
  64. package/dist/plugins/one-tap/index.mjs +0 -1
  65. package/dist/plugins/open-api/generator.mjs +15 -1
  66. package/dist/plugins/organization/has-permission.mjs +4 -2
  67. package/dist/plugins/phone-number/routes.mjs +0 -2
  68. package/dist/plugins/siwe/index.mjs +5 -6
  69. package/dist/plugins/two-factor/client.d.mts +1 -0
  70. package/dist/plugins/two-factor/error-code.d.mts +1 -0
  71. package/dist/plugins/two-factor/error-code.mjs +1 -0
  72. package/dist/plugins/two-factor/index.d.mts +1 -0
  73. package/dist/plugins/two-factor/index.mjs +3 -2
  74. package/dist/state.d.mts +0 -13
  75. package/dist/test-utils/http-test-instance.d.mts +1 -1
  76. package/dist/test-utils/test-instance.mjs +27 -10
  77. package/package.json +10 -10
@@ -1,5 +1,4 @@
1
1
  import { isAPIError } from "../../utils/is-api-error.mjs";
2
- import { getOrigin } from "../../utils/url.mjs";
3
2
  import { mergeSchema } from "../../db/schema.mjs";
4
3
  import { setSessionCookie } from "../../cookies/index.mjs";
5
4
  import { APIError } from "../../api/index.mjs";
@@ -7,9 +6,9 @@ import { PACKAGE_VERSION } from "../../version.mjs";
7
6
  import { toChecksumAddress } from "../../utils/hashing.mjs";
8
7
  import { normalizeSiweDomain, parseSiweMessage } from "./parse-message.mjs";
9
8
  import { schema } from "./schema.mjs";
10
- import { createLocalAccountIssuer } from "@better-auth/core/db";
11
9
  import { createAuthEndpoint } from "@better-auth/core/api";
12
10
  import * as z from "zod";
11
+ import { createPlaceholderEmail } from "@better-auth/core/utils/email";
13
12
  //#region src/plugins/siwe/index.ts
14
13
  const signedWalletAddressSchema = z.string().regex(/^0x[a-fA-F0-9]{40}$/).length(42);
15
14
  const SIWE_VERIFICATION_IDENTIFIER_PREFIX = "siwe:";
@@ -162,9 +161,11 @@ const siwe = (options) => {
162
161
  });
163
162
  }
164
163
  if (!user) {
165
- const domain = options.emailDomainName ?? getOrigin(ctx.context.baseURL);
166
164
  const normalizedEmail = email?.toLowerCase();
167
- const walletEmail = `${walletAddress}@${domain}`;
165
+ const walletEmail = options.emailDomainName ? `${walletAddress}@${options.emailDomainName}` : createPlaceholderEmail({
166
+ identifier: walletAddress,
167
+ namespace: "siwe"
168
+ });
168
169
  let userEmail = walletEmail;
169
170
  let emailClaimIdentifier;
170
171
  if (!isAnon && normalizedEmail) {
@@ -213,7 +214,6 @@ const siwe = (options) => {
213
214
  await ctx.context.internalAdapter.createAccount({
214
215
  userId: user.id,
215
216
  providerId: "siwe",
216
- issuer: createLocalAccountIssuer("siwe"),
217
217
  accountId: `${walletAddress}:${chainId}`,
218
218
  createdAt: /* @__PURE__ */ new Date(),
219
219
  updatedAt: /* @__PURE__ */ new Date()
@@ -232,7 +232,6 @@ const siwe = (options) => {
232
232
  await ctx.context.internalAdapter.createAccount({
233
233
  userId: user.id,
234
234
  providerId: "siwe",
235
- issuer: createLocalAccountIssuer("siwe"),
236
235
  accountId: `${walletAddress}:${chainId}`,
237
236
  createdAt: /* @__PURE__ */ new Date(),
238
237
  updatedAt: /* @__PURE__ */ new Date()
@@ -61,6 +61,7 @@ declare const twoFactorClient: (options?: {
61
61
  OTP_NOT_CONFIGURED: _$_better_auth_core_utils_error_codes0.RawError<"OTP_NOT_CONFIGURED">;
62
62
  OTP_HAS_EXPIRED: _$_better_auth_core_utils_error_codes0.RawError<"OTP_HAS_EXPIRED">;
63
63
  TOTP_NOT_ENABLED: _$_better_auth_core_utils_error_codes0.RawError<"TOTP_NOT_ENABLED">;
64
+ TOTP_ALREADY_ENABLED: _$_better_auth_core_utils_error_codes0.RawError<"TOTP_ALREADY_ENABLED">;
64
65
  TOTP_NOT_CONFIGURED: _$_better_auth_core_utils_error_codes0.RawError<"TOTP_NOT_CONFIGURED">;
65
66
  TWO_FACTOR_NOT_ENABLED: _$_better_auth_core_utils_error_codes0.RawError<"TWO_FACTOR_NOT_ENABLED">;
66
67
  BACKUP_CODES_NOT_ENABLED: _$_better_auth_core_utils_error_codes0.RawError<"BACKUP_CODES_NOT_ENABLED">;
@@ -6,6 +6,7 @@ declare const TWO_FACTOR_ERROR_CODES: {
6
6
  OTP_NOT_CONFIGURED: _$_better_auth_core_utils_error_codes0.RawError<"OTP_NOT_CONFIGURED">;
7
7
  OTP_HAS_EXPIRED: _$_better_auth_core_utils_error_codes0.RawError<"OTP_HAS_EXPIRED">;
8
8
  TOTP_NOT_ENABLED: _$_better_auth_core_utils_error_codes0.RawError<"TOTP_NOT_ENABLED">;
9
+ TOTP_ALREADY_ENABLED: _$_better_auth_core_utils_error_codes0.RawError<"TOTP_ALREADY_ENABLED">;
9
10
  TOTP_NOT_CONFIGURED: _$_better_auth_core_utils_error_codes0.RawError<"TOTP_NOT_CONFIGURED">;
10
11
  TWO_FACTOR_NOT_ENABLED: _$_better_auth_core_utils_error_codes0.RawError<"TWO_FACTOR_NOT_ENABLED">;
11
12
  BACKUP_CODES_NOT_ENABLED: _$_better_auth_core_utils_error_codes0.RawError<"BACKUP_CODES_NOT_ENABLED">;
@@ -5,6 +5,7 @@ const TWO_FACTOR_ERROR_CODES = defineErrorCodes({
5
5
  OTP_NOT_CONFIGURED: "OTP is not available",
6
6
  OTP_HAS_EXPIRED: "OTP has expired",
7
7
  TOTP_NOT_ENABLED: "TOTP not enabled",
8
+ TOTP_ALREADY_ENABLED: "TOTP is already enabled",
8
9
  TOTP_NOT_CONFIGURED: "TOTP is not available",
9
10
  TWO_FACTOR_NOT_ENABLED: "Two factor isn't enabled",
10
11
  BACKUP_CODES_NOT_ENABLED: "Backup codes aren't enabled",
@@ -705,6 +705,7 @@ declare const twoFactor: <O extends TwoFactorOptions>(options?: O) => {
705
705
  OTP_NOT_CONFIGURED: _$_better_auth_core_utils_error_codes0.RawError<"OTP_NOT_CONFIGURED">;
706
706
  OTP_HAS_EXPIRED: _$_better_auth_core_utils_error_codes0.RawError<"OTP_HAS_EXPIRED">;
707
707
  TOTP_NOT_ENABLED: _$_better_auth_core_utils_error_codes0.RawError<"TOTP_NOT_ENABLED">;
708
+ TOTP_ALREADY_ENABLED: _$_better_auth_core_utils_error_codes0.RawError<"TOTP_ALREADY_ENABLED">;
708
709
  TOTP_NOT_CONFIGURED: _$_better_auth_core_utils_error_codes0.RawError<"TOTP_NOT_CONFIGURED">;
709
710
  TWO_FACTOR_NOT_ENABLED: _$_better_auth_core_utils_error_codes0.RawError<"TWO_FACTOR_NOT_ENABLED">;
710
711
  BACKUP_CODES_NOT_ENABLED: _$_better_auth_core_utils_error_codes0.RawError<"BACKUP_CODES_NOT_ENABLED">;
@@ -122,7 +122,6 @@ const twoFactor = (options) => {
122
122
  await ctx.context.internalAdapter.deleteSession(ctx.context.session.session.token);
123
123
  return ctx.json({ method: "otp" });
124
124
  }
125
- const backupCodes = await generateBackupCodes(ctx.context.secretConfig, backupCodeOptions);
126
125
  const existingTwoFactor = await ctx.context.adapter.findOne({
127
126
  model: opts.twoFactorTable,
128
127
  where: [{
@@ -130,6 +129,8 @@ const twoFactor = (options) => {
130
129
  value: user.id
131
130
  }]
132
131
  });
132
+ if (existingTwoFactor && existingTwoFactor.verified !== false) throw APIError.from("BAD_REQUEST", TWO_FACTOR_ERROR_CODES.TOTP_ALREADY_ENABLED);
133
+ const backupCodes = await generateBackupCodes(ctx.context.secretConfig, backupCodeOptions);
133
134
  const secret = generateRandomString(32);
134
135
  const encryptedSecret = await symmetricEncrypt({
135
136
  key: ctx.context.secretConfig,
@@ -146,7 +147,7 @@ const twoFactor = (options) => {
146
147
  const totpData = {
147
148
  secret: encryptedSecret,
148
149
  backupCodes: backupCodes.encryptedBackupCodes,
149
- verified: existingTwoFactor != null && existingTwoFactor.verified === true || !!options?.skipVerificationOnEnable
150
+ verified: !!options?.skipVerificationOnEnable
150
151
  };
151
152
  if (existingTwoFactor) await ctx.context.adapter.update({
152
153
  model: opts.twoFactorTable,
package/dist/state.d.mts CHANGED
@@ -9,26 +9,13 @@ declare const stateDataSchema: z.ZodObject<{
9
9
  errorURL: z.ZodOptional<z.ZodString>;
10
10
  newUserURL: z.ZodOptional<z.ZodString>;
11
11
  expiresAt: z.ZodNumber;
12
- /**
13
- * CSRF nonce returned to the OAuth provider. When using cookie state storage,
14
- * this must match the callback `state` query parameter.
15
- */
16
12
  oauthState: z.ZodOptional<z.ZodString>;
17
13
  link: z.ZodOptional<z.ZodObject<{
18
14
  email: z.ZodString;
19
15
  userId: z.ZodCoercedString<unknown>;
20
16
  }, z.core.$strip>>;
21
17
  requestSignUp: z.ZodOptional<z.ZodBoolean>;
22
- /**
23
- * OIDC nonce sent as the authorization request `nonce` parameter when the
24
- * provider requires an ID token to be bound to this redirect flow.
25
- */
26
18
  idTokenNonce: z.ZodOptional<z.ZodString>;
27
- /**
28
- * Server-controlled values that ride the state across the provider redirect.
29
- * Populated only by `generateState` from `addOAuthServerContext`, never from
30
- * the request body, so it is safe to trust on the callback.
31
- */
32
19
  serverContext: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
33
20
  }, z.core.$loose>;
34
21
  type StateData = z.infer<typeof stateDataSchema>;
@@ -61,7 +61,7 @@ declare function getHttpTestInstance<O extends Partial<BetterAuthOptions>, C ext
61
61
  port: number;
62
62
  auth: Auth<O>;
63
63
  client: {
64
- hydrateSession: (session: null) => void;
64
+ hydrateSession(session: null): void;
65
65
  useSession: _$nanostores.Atom<{
66
66
  data: never;
67
67
  error: _$_better_fetch_fetch0.BetterFetchError | null;
@@ -7,7 +7,7 @@ import { createAuthClient } from "../client/vanilla.mjs";
7
7
  import { bearer } from "../plugins/bearer/index.mjs";
8
8
  import { sql } from "kysely";
9
9
  import { AsyncLocalStorage } from "node:async_hooks";
10
- import { randomUUID } from "node:crypto";
10
+ import { createHash, randomUUID } from "node:crypto";
11
11
  import { afterAll } from "vitest";
12
12
  //#region src/test-utils/test-instance.ts
13
13
  const cleanupSet = /* @__PURE__ */ new Set();
@@ -18,6 +18,17 @@ afterAll(async () => {
18
18
  cleanupSet.delete(cleanup);
19
19
  }
20
20
  });
21
+ const TEST_PASSWORD_HASH_PREFIX = "$test$sha256$";
22
+ /**
23
+ * Intentionally fast for tests
24
+ */
25
+ function createTestPasswordHash(password) {
26
+ return `${TEST_PASSWORD_HASH_PREFIX}${createHash("sha256").update(password.normalize("NFKC")).digest("hex")}`;
27
+ }
28
+ const testPassword = {
29
+ hash: async (password) => createTestPasswordHash(password),
30
+ verify: async ({ hash, password }) => hash === createTestPasswordHash(password)
31
+ };
21
32
  async function getTestInstance(options, config) {
22
33
  const testWith = config?.testWith || "sqlite";
23
34
  const postgresSchema = testWith === "postgres" ? `ba_test_${randomUUID().replaceAll("-", "_")}` : void 0;
@@ -79,12 +90,25 @@ async function getTestInstance(options, config) {
79
90
  advanced: { cookies: {} },
80
91
  logger: { level: "debug" }
81
92
  };
82
- const auth = betterAuth({
93
+ const authOptions = {
83
94
  baseURL: "http://localhost:" + (config?.port || 3e3),
84
95
  ...opts,
85
96
  ...options,
97
+ emailAndPassword: {
98
+ ...opts.emailAndPassword,
99
+ ...options?.emailAndPassword,
100
+ password: options?.emailAndPassword?.password ?? testPassword
101
+ },
86
102
  plugins: [bearer(), ...options?.plugins || []]
87
- });
103
+ };
104
+ if (testWith !== "mongodb") {
105
+ const { runMigrations } = await getMigrations({
106
+ ...authOptions,
107
+ database: opts.database
108
+ });
109
+ await runMigrations();
110
+ }
111
+ const auth = betterAuth(authOptions);
88
112
  const testUser = {
89
113
  email: "test@test.com",
90
114
  password: "test123456",
@@ -101,13 +125,6 @@ async function getTestInstance(options, config) {
101
125
  headers
102
126
  });
103
127
  }
104
- if (testWith !== "mongodb") {
105
- const { runMigrations } = await getMigrations({
106
- ...auth.options,
107
- database: opts.database
108
- });
109
- await runMigrations();
110
- }
111
128
  await createTestUser();
112
129
  const cleanup = async () => {
113
130
  if (testWith === "mongodb") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-auth",
3
- "version": "1.7.1",
3
+ "version": "1.7.3",
4
4
  "description": "The most comprehensive authentication framework for TypeScript.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -472,14 +472,14 @@
472
472
  "jose": "^6.2.3",
473
473
  "kysely": "^0.28.17 || ^0.29.0",
474
474
  "nanostores": "^1.3.0",
475
- "zod": "^4.3.6",
476
- "@better-auth/core": "1.7.1",
477
- "@better-auth/drizzle-adapter": "1.7.1",
478
- "@better-auth/kysely-adapter": "1.7.1",
479
- "@better-auth/memory-adapter": "1.7.1",
480
- "@better-auth/mongo-adapter": "1.7.1",
481
- "@better-auth/prisma-adapter": "1.7.1",
482
- "@better-auth/telemetry": "1.7.1"
475
+ "zod": "^4.5.4",
476
+ "@better-auth/core": "1.7.3",
477
+ "@better-auth/drizzle-adapter": "1.7.3",
478
+ "@better-auth/kysely-adapter": "1.7.3",
479
+ "@better-auth/memory-adapter": "1.7.3",
480
+ "@better-auth/mongo-adapter": "1.7.3",
481
+ "@better-auth/prisma-adapter": "1.7.3",
482
+ "@better-auth/telemetry": "1.7.3"
483
483
  },
484
484
  "devDependencies": {
485
485
  "@lynx-js/react": "^0.121.2",
@@ -504,7 +504,7 @@
504
504
  "tsdown": "0.21.10",
505
505
  "type-fest": "^5.7.0",
506
506
  "typescript": "^6.0.3",
507
- "vitest": "^4.0.18",
507
+ "vitest": "^4.1.10",
508
508
  "vue": "^3.5.29"
509
509
  },
510
510
  "peerDependencies": {