better-auth 1.6.1 → 1.6.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 +0 -2
- package/dist/api/routes/account.mjs +1 -1
- package/dist/api/routes/callback.mjs +2 -2
- package/dist/api/routes/email-verification.mjs +1 -1
- package/dist/api/routes/password.mjs +1 -1
- package/dist/api/routes/session.d.mts +0 -1
- package/dist/api/routes/session.mjs +3 -4
- package/dist/api/routes/sign-in.mjs +1 -1
- package/dist/api/to-auth-endpoints.mjs +27 -3
- package/dist/auth/base.mjs +5 -24
- package/dist/client/plugins/index.d.mts +2 -2
- package/dist/client/query.mjs +4 -4
- package/dist/context/create-context.mjs +2 -2
- package/dist/context/helpers.mjs +61 -3
- package/dist/cookies/index.mjs +3 -3
- package/dist/crypto/index.mjs +2 -2
- package/dist/db/index.mjs +1 -1
- package/dist/db/internal-adapter.mjs +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/integrations/next-js.mjs +21 -12
- package/dist/oauth2/state.d.mts +1 -0
- package/dist/package.mjs +1 -1
- package/dist/plugins/admin/admin.d.mts +1 -3
- package/dist/plugins/admin/routes.mjs +2 -8
- package/dist/plugins/device-authorization/routes.mjs +1 -1
- package/dist/plugins/email-otp/routes.mjs +1 -1
- package/dist/plugins/index.d.mts +2 -2
- package/dist/plugins/jwt/utils.mjs +1 -1
- package/dist/plugins/mcp/index.mjs +20 -8
- package/dist/plugins/oauth-proxy/index.mjs +5 -1
- package/dist/plugins/oidc-provider/index.mjs +2 -2
- package/dist/plugins/organization/organization.d.mts +1 -3
- package/dist/plugins/organization/organization.mjs +1 -7
- package/dist/plugins/organization/routes/crud-invites.mjs +1 -1
- package/dist/plugins/organization/routes/crud-org.mjs +1 -1
- package/dist/plugins/organization/routes/crud-team.mjs +1 -1
- package/dist/plugins/phone-number/routes.mjs +1 -1
- package/dist/plugins/two-factor/backup-codes/index.d.mts +2 -1
- package/dist/plugins/two-factor/backup-codes/index.mjs +12 -17
- package/dist/plugins/two-factor/client.d.mts +12 -2
- package/dist/plugins/two-factor/client.mjs +1 -1
- package/dist/plugins/two-factor/index.d.mts +9 -2
- package/dist/plugins/two-factor/index.mjs +35 -3
- package/dist/plugins/two-factor/otp/index.mjs +1 -1
- package/dist/plugins/two-factor/schema.d.mts +6 -0
- package/dist/plugins/two-factor/schema.mjs +6 -0
- package/dist/plugins/two-factor/totp/index.mjs +19 -10
- package/dist/plugins/two-factor/types.d.mts +1 -1
- package/dist/state.d.mts +6 -0
- package/dist/state.mjs +18 -2
- package/dist/test-utils/test-instance.d.mts +0 -6
- package/dist/test-utils/test-instance.mjs +7 -1
- package/dist/utils/index.d.mts +1 -1
- package/dist/utils/url.d.mts +22 -15
- package/dist/utils/url.mjs +54 -28
- package/package.json +9 -9
package/dist/utils/url.d.mts
CHANGED
|
@@ -10,22 +10,29 @@ declare function getHost(url: string): string | null;
|
|
|
10
10
|
*/
|
|
11
11
|
declare function isDynamicBaseURLConfig(config: BaseURLConfig | undefined): config is DynamicBaseURLConfig;
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* Check if a value is a `Request`
|
|
14
|
+
* - `instanceof`: works for native Request instances
|
|
15
|
+
* - `toString`: handles where instanceof check fails but the object is still a
|
|
16
|
+
* valid Request (e.g. cross-realm, polyfills). Paired with a shape check so
|
|
17
|
+
* an object that only spoofs `Symbol.toStringTag` without the real shape is
|
|
18
|
+
* rejected before downstream code tries to read `.headers` / `.url`.
|
|
15
19
|
*
|
|
16
|
-
* @param
|
|
17
|
-
* @returns
|
|
20
|
+
* @param value The value to check
|
|
21
|
+
* @returns `true` if the value is a Request instance
|
|
18
22
|
*/
|
|
19
|
-
declare function
|
|
23
|
+
declare function isRequestLike(value: unknown): value is Request;
|
|
20
24
|
/**
|
|
21
|
-
* Extracts the
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
* Extracts the host from a `Request` or `Headers`.
|
|
26
|
+
* Honors `x-forwarded-host` only when `trustedProxyHeaders` is enabled,
|
|
27
|
+
* then falls back to the `host` header and finally the request URL.
|
|
28
|
+
*/
|
|
29
|
+
declare function getHostFromSource(source: Request | Headers, trustedProxyHeaders?: boolean): string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Extracts the protocol from a `Request` or `Headers`.
|
|
32
|
+
* Honors `x-forwarded-proto` only when `trustedProxyHeaders` is enabled,
|
|
33
|
+
* then falls back to the request URL, then to "https".
|
|
27
34
|
*/
|
|
28
|
-
declare function
|
|
35
|
+
declare function getProtocolFromSource(source: Request | Headers, configProtocol?: "http" | "https" | "auto" | undefined, trustedProxyHeaders?: boolean): "http" | "https";
|
|
29
36
|
/**
|
|
30
37
|
* Matches a hostname against a host pattern.
|
|
31
38
|
* Supports wildcard patterns like `*.vercel.app` or `preview-*.myapp.com`.
|
|
@@ -53,7 +60,7 @@ declare const matchesHostPattern: (host: string, pattern: string) => boolean;
|
|
|
53
60
|
* @returns The resolved base URL with path
|
|
54
61
|
* @throws BetterAuthError if host is not in allowedHosts and no fallback is set
|
|
55
62
|
*/
|
|
56
|
-
declare function resolveDynamicBaseURL(config: DynamicBaseURLConfig,
|
|
63
|
+
declare function resolveDynamicBaseURL(config: DynamicBaseURLConfig, source: Request | Headers, basePath: string, trustedProxyHeaders?: boolean): string;
|
|
57
64
|
/**
|
|
58
65
|
* Resolves the base URL from any config type (static string or dynamic object).
|
|
59
66
|
* This is the main entry point for base URL resolution.
|
|
@@ -65,6 +72,6 @@ declare function resolveDynamicBaseURL(config: DynamicBaseURLConfig, request: Re
|
|
|
65
72
|
* @param trustedProxyHeaders Whether to trust proxy headers (for legacy behavior)
|
|
66
73
|
* @returns The resolved base URL with path
|
|
67
74
|
*/
|
|
68
|
-
declare function resolveBaseURL(config: BaseURLConfig | undefined, basePath: string,
|
|
75
|
+
declare function resolveBaseURL(config: BaseURLConfig | undefined, basePath: string, source?: Request | Headers, loadEnv?: boolean, trustedProxyHeaders?: boolean): string | undefined;
|
|
69
76
|
//#endregion
|
|
70
|
-
export { getBaseURL, getHost,
|
|
77
|
+
export { getBaseURL, getHost, getHostFromSource, getOrigin, getProtocol, getProtocolFromSource, isDynamicBaseURLConfig, isRequestLike, matchesHostPattern, resolveBaseURL, resolveDynamicBaseURL };
|
package/dist/utils/url.mjs
CHANGED
|
@@ -93,41 +93,66 @@ function isDynamicBaseURLConfig(config) {
|
|
|
93
93
|
return typeof config === "object" && config !== null && "allowedHosts" in config && Array.isArray(config.allowedHosts);
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
96
|
+
* Check if a value is a `Request`
|
|
97
|
+
* - `instanceof`: works for native Request instances
|
|
98
|
+
* - `toString`: handles where instanceof check fails but the object is still a
|
|
99
|
+
* valid Request (e.g. cross-realm, polyfills). Paired with a shape check so
|
|
100
|
+
* an object that only spoofs `Symbol.toStringTag` without the real shape is
|
|
101
|
+
* rejected before downstream code tries to read `.headers` / `.url`.
|
|
98
102
|
*
|
|
99
|
-
* @param
|
|
100
|
-
* @returns
|
|
103
|
+
* @param value The value to check
|
|
104
|
+
* @returns `true` if the value is a Request instance
|
|
105
|
+
*/
|
|
106
|
+
function isRequestLike(value) {
|
|
107
|
+
if (value instanceof Request) return true;
|
|
108
|
+
if (typeof value !== "object" || value === null || Object.prototype.toString.call(value) !== "[object Request]") return false;
|
|
109
|
+
const v = value;
|
|
110
|
+
return typeof v.url === "string" && typeof v.headers === "object" && v.headers !== null && typeof v.headers.get === "function";
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Extracts the host from a `Request` or `Headers`.
|
|
114
|
+
* Honors `x-forwarded-host` only when `trustedProxyHeaders` is enabled,
|
|
115
|
+
* then falls back to the `host` header and finally the request URL.
|
|
101
116
|
*/
|
|
102
|
-
function
|
|
103
|
-
const
|
|
104
|
-
if (
|
|
105
|
-
|
|
117
|
+
function getHostFromSource(source, trustedProxyHeaders) {
|
|
118
|
+
const headers = isRequestLike(source) ? source.headers : source;
|
|
119
|
+
if (trustedProxyHeaders) {
|
|
120
|
+
const forwardedHost = headers.get("x-forwarded-host");
|
|
121
|
+
if (forwardedHost && validateProxyHeader(forwardedHost, "host")) return forwardedHost;
|
|
122
|
+
}
|
|
123
|
+
const host = headers.get("host");
|
|
106
124
|
if (host && validateProxyHeader(host, "host")) return host;
|
|
107
|
-
try {
|
|
108
|
-
return new URL(
|
|
125
|
+
if (isRequestLike(source)) try {
|
|
126
|
+
return new URL(source.url).host;
|
|
109
127
|
} catch {
|
|
110
128
|
return null;
|
|
111
129
|
}
|
|
130
|
+
return null;
|
|
112
131
|
}
|
|
113
132
|
/**
|
|
114
|
-
* Extracts the protocol from
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* @param request The incoming request
|
|
118
|
-
* @param configProtocol Protocol override from config
|
|
119
|
-
* @returns The protocol ("http" or "https")
|
|
133
|
+
* Extracts the protocol from a `Request` or `Headers`.
|
|
134
|
+
* Honors `x-forwarded-proto` only when `trustedProxyHeaders` is enabled,
|
|
135
|
+
* then falls back to the request URL, then to "https".
|
|
120
136
|
*/
|
|
121
|
-
function
|
|
137
|
+
function getProtocolFromSource(source, configProtocol, trustedProxyHeaders) {
|
|
122
138
|
if (configProtocol === "http" || configProtocol === "https") return configProtocol;
|
|
123
|
-
const
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
139
|
+
const headers = isRequestLike(source) ? source.headers : source;
|
|
140
|
+
if (trustedProxyHeaders) {
|
|
141
|
+
const forwardedProto = headers.get("x-forwarded-proto");
|
|
142
|
+
if (forwardedProto && validateProxyHeader(forwardedProto, "proto")) return forwardedProto;
|
|
143
|
+
}
|
|
144
|
+
if (isRequestLike(source)) try {
|
|
145
|
+
const url = new URL(source.url);
|
|
127
146
|
if (url.protocol === "http:" || url.protocol === "https:") return url.protocol.slice(0, -1);
|
|
128
147
|
} catch {}
|
|
148
|
+
const host = getHostFromSource(source, trustedProxyHeaders);
|
|
149
|
+
if (host && isLoopbackHost(host)) return "http";
|
|
129
150
|
return "https";
|
|
130
151
|
}
|
|
152
|
+
function isLoopbackHost(host) {
|
|
153
|
+
const h = host.toLowerCase();
|
|
154
|
+
return h === "localhost" || h.startsWith("localhost:") || h === "127.0.0.1" || h.startsWith("127.0.0.1:") || h === "[::1]" || h.startsWith("[::1]:") || h === "0.0.0.0" || h.startsWith("0.0.0.0:");
|
|
155
|
+
}
|
|
131
156
|
/**
|
|
132
157
|
* Matches a hostname against a host pattern.
|
|
133
158
|
* Supports wildcard patterns like `*.vercel.app` or `preview-*.myapp.com`.
|
|
@@ -161,13 +186,13 @@ const matchesHostPattern = (host, pattern) => {
|
|
|
161
186
|
* @returns The resolved base URL with path
|
|
162
187
|
* @throws BetterAuthError if host is not in allowedHosts and no fallback is set
|
|
163
188
|
*/
|
|
164
|
-
function resolveDynamicBaseURL(config,
|
|
165
|
-
const host =
|
|
189
|
+
function resolveDynamicBaseURL(config, source, basePath, trustedProxyHeaders) {
|
|
190
|
+
const host = getHostFromSource(source, trustedProxyHeaders);
|
|
166
191
|
if (!host) {
|
|
167
192
|
if (config.fallback) return withPath(config.fallback, basePath);
|
|
168
193
|
throw new BetterAuthError("Could not determine host from request headers. Please provide a fallback URL in your baseURL config.");
|
|
169
194
|
}
|
|
170
|
-
if (config.allowedHosts.some((pattern) => matchesHostPattern(host, pattern))) return withPath(`${
|
|
195
|
+
if (config.allowedHosts.some((pattern) => matchesHostPattern(host, pattern))) return withPath(`${getProtocolFromSource(source, config.protocol, trustedProxyHeaders)}://${host}`, basePath);
|
|
171
196
|
if (config.fallback) return withPath(config.fallback, basePath);
|
|
172
197
|
throw new BetterAuthError(`Host "${host}" is not in the allowed hosts list. Allowed hosts: ${config.allowedHosts.join(", ")}. Add this host to your allowedHosts config or provide a fallback URL.`);
|
|
173
198
|
}
|
|
@@ -182,14 +207,15 @@ function resolveDynamicBaseURL(config, request, basePath) {
|
|
|
182
207
|
* @param trustedProxyHeaders Whether to trust proxy headers (for legacy behavior)
|
|
183
208
|
* @returns The resolved base URL with path
|
|
184
209
|
*/
|
|
185
|
-
function resolveBaseURL(config, basePath,
|
|
210
|
+
function resolveBaseURL(config, basePath, source, loadEnv, trustedProxyHeaders) {
|
|
186
211
|
if (isDynamicBaseURLConfig(config)) {
|
|
187
|
-
if (
|
|
212
|
+
if (source) return resolveDynamicBaseURL(config, source, basePath, trustedProxyHeaders);
|
|
188
213
|
if (config.fallback) return withPath(config.fallback, basePath);
|
|
189
|
-
return getBaseURL(void 0, basePath,
|
|
214
|
+
return getBaseURL(void 0, basePath, void 0, loadEnv, trustedProxyHeaders);
|
|
190
215
|
}
|
|
216
|
+
const request = isRequestLike(source) ? source : void 0;
|
|
191
217
|
if (typeof config === "string") return getBaseURL(config, basePath, request, loadEnv, trustedProxyHeaders);
|
|
192
218
|
return getBaseURL(void 0, basePath, request, loadEnv, trustedProxyHeaders);
|
|
193
219
|
}
|
|
194
220
|
//#endregion
|
|
195
|
-
export { getBaseURL, getHost,
|
|
221
|
+
export { getBaseURL, getHost, getHostFromSource, getOrigin, getProtocol, getProtocolFromSource, isDynamicBaseURLConfig, isRequestLike, matchesHostPattern, resolveBaseURL, resolveDynamicBaseURL };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "better-auth",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.3",
|
|
4
4
|
"description": "The most comprehensive authentication framework for TypeScript.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -489,17 +489,17 @@
|
|
|
489
489
|
"kysely": "^0.28.14",
|
|
490
490
|
"nanostores": "^1.1.1",
|
|
491
491
|
"zod": "^4.3.6",
|
|
492
|
-
"@better-auth/core": "1.6.
|
|
493
|
-
"@better-auth/drizzle-adapter": "1.6.
|
|
494
|
-
"@better-auth/kysely-adapter": "1.6.
|
|
495
|
-
"@better-auth/memory-adapter": "1.6.
|
|
496
|
-
"@better-auth/mongo-adapter": "1.6.
|
|
497
|
-
"@better-auth/prisma-adapter": "1.6.
|
|
498
|
-
"@better-auth/telemetry": "1.6.
|
|
492
|
+
"@better-auth/core": "1.6.3",
|
|
493
|
+
"@better-auth/drizzle-adapter": "1.6.3",
|
|
494
|
+
"@better-auth/kysely-adapter": "1.6.3",
|
|
495
|
+
"@better-auth/memory-adapter": "1.6.3",
|
|
496
|
+
"@better-auth/mongo-adapter": "1.6.3",
|
|
497
|
+
"@better-auth/prisma-adapter": "1.6.3",
|
|
498
|
+
"@better-auth/telemetry": "1.6.3"
|
|
499
499
|
},
|
|
500
500
|
"devDependencies": {
|
|
501
501
|
"@lynx-js/react": "^0.116.3",
|
|
502
|
-
"@sveltejs/kit": "^2.
|
|
502
|
+
"@sveltejs/kit": "^2.57.1",
|
|
503
503
|
"@tanstack/react-start": "^1.163.2",
|
|
504
504
|
"@tanstack/solid-start": "^1.163.2",
|
|
505
505
|
"@types/bun": "^1.3.9",
|