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.
- package/dist/api/index.d.mts +6 -22
- package/dist/api/index.mjs +2 -0
- package/dist/api/middlewares/origin-check.mjs +9 -5
- package/dist/api/routes/account.d.mts +1 -9
- package/dist/api/routes/account.mjs +0 -6
- package/dist/api/routes/callback.mjs +7 -7
- package/dist/api/routes/email-verification.mjs +4 -2
- package/dist/api/routes/error.mjs +12 -8
- package/dist/api/routes/password.mjs +0 -2
- package/dist/api/routes/session.mjs +12 -5
- package/dist/api/routes/sign-in.d.mts +2 -2
- package/dist/api/routes/sign-in.mjs +1 -4
- package/dist/api/routes/sign-up.mjs +0 -2
- package/dist/api/routes/update-user.mjs +0 -2
- package/dist/api/to-auth-endpoints.mjs +2 -0
- package/dist/auth/base.mjs +13 -1
- package/dist/auth/trusted-origins.mjs +24 -5
- package/dist/client/config.d.mts +2 -0
- package/dist/client/config.mjs +1 -0
- package/dist/client/lynx/index.d.mts +1 -1
- package/dist/client/react/index.d.mts +1 -1
- package/dist/client/solid/index.d.mts +1 -1
- package/dist/client/svelte/index.d.mts +1 -1
- package/dist/client/vanilla.d.mts +1 -1
- package/dist/client/vue/index.d.mts +32 -21
- package/dist/client/vue/index.mjs +23 -5
- package/dist/context/create-context.mjs +2 -0
- package/dist/cookies/cache.mjs +10 -2
- package/dist/cookies/session-store.d.mts +0 -1
- package/dist/cookies/session-store.mjs +16 -5
- package/dist/db/adapter-kysely.mjs +1 -2
- package/dist/db/get-migration.d.mts +1 -0
- package/dist/db/get-migration.mjs +49 -56
- package/dist/db/internal-adapter.mjs +17 -20
- package/dist/db/schema.d.mts +0 -1
- package/dist/db/with-hooks.mjs +7 -7
- package/dist/oauth2/account-key.mjs +1 -5
- package/dist/oauth2/errors.mjs +4 -3
- package/dist/oauth2/link-account.d.mts +0 -1
- package/dist/oauth2/link-account.mjs +5 -11
- package/dist/oauth2/state.mjs +1 -1
- package/dist/package.mjs +1 -1
- package/dist/plugins/admin/routes.mjs +1 -4
- package/dist/plugins/anonymous/index.mjs +5 -1
- package/dist/plugins/anonymous/types.d.mts +2 -3
- package/dist/plugins/device-authorization/index.d.mts +11 -11
- package/dist/plugins/email-otp/routes.mjs +0 -2
- package/dist/plugins/generic-oauth/index.mjs +14 -10
- package/dist/plugins/generic-oauth/providers/auth0.mjs +2 -4
- package/dist/plugins/generic-oauth/providers/keycloak.mjs +6 -9
- package/dist/plugins/generic-oauth/providers/line.mjs +0 -1
- package/dist/plugins/generic-oauth/providers/microsoft-entra-id.mjs +15 -5
- package/dist/plugins/generic-oauth/providers/okta.mjs +6 -9
- package/dist/plugins/generic-oauth/providers/slack.mjs +0 -1
- package/dist/plugins/generic-oauth/types.d.mts +0 -9
- package/dist/plugins/haveibeenpwned/index.d.mts +9 -1
- package/dist/plugins/haveibeenpwned/index.mjs +33 -13
- package/dist/plugins/index.d.mts +2 -2
- package/dist/plugins/index.mjs +2 -2
- package/dist/plugins/jwt/verify.mjs +2 -2
- package/dist/plugins/last-login-method/index.mjs +1 -0
- package/dist/plugins/oauth-proxy/index.d.mts +17 -0
- package/dist/plugins/oauth-proxy/index.mjs +145 -99
- package/dist/plugins/one-tap/index.mjs +0 -1
- package/dist/plugins/open-api/generator.mjs +15 -1
- package/dist/plugins/organization/has-permission.mjs +4 -2
- package/dist/plugins/phone-number/routes.mjs +0 -2
- package/dist/plugins/siwe/index.mjs +5 -6
- package/dist/plugins/two-factor/client.d.mts +1 -0
- package/dist/plugins/two-factor/error-code.d.mts +1 -0
- package/dist/plugins/two-factor/error-code.mjs +1 -0
- package/dist/plugins/two-factor/index.d.mts +1 -0
- package/dist/plugins/two-factor/index.mjs +3 -2
- package/dist/state.d.mts +0 -13
- package/dist/test-utils/http-test-instance.d.mts +1 -1
- package/dist/test-utils/test-instance.mjs +27 -10
- 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}@${
|
|
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:
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
476
|
-
"@better-auth/core": "1.7.
|
|
477
|
-
"@better-auth/drizzle-adapter": "1.7.
|
|
478
|
-
"@better-auth/kysely-adapter": "1.7.
|
|
479
|
-
"@better-auth/memory-adapter": "1.7.
|
|
480
|
-
"@better-auth/mongo-adapter": "1.7.
|
|
481
|
-
"@better-auth/prisma-adapter": "1.7.
|
|
482
|
-
"@better-auth/telemetry": "1.7.
|
|
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.
|
|
507
|
+
"vitest": "^4.1.10",
|
|
508
508
|
"vue": "^3.5.29"
|
|
509
509
|
},
|
|
510
510
|
"peerDependencies": {
|