better-auth 1.7.0-beta.0 → 1.7.0-beta.1
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 +4 -0
- package/dist/api/routes/account.mjs +1 -1
- package/dist/api/routes/callback.d.mts +2 -0
- package/dist/api/routes/callback.mjs +23 -14
- package/dist/api/routes/email-verification.mjs +1 -1
- package/dist/api/routes/session.mjs +2 -2
- 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/path-to-object.d.mts +35 -1
- package/dist/client/plugins/index.d.mts +4 -3
- package/dist/client/plugins/index.mjs +2 -1
- 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/oauth2/error-codes.d.mts +20 -0
- package/dist/oauth2/error-codes.mjs +20 -0
- package/dist/package.mjs +1 -1
- package/dist/plugins/admin/admin.mjs +1 -1
- package/dist/plugins/admin/routes.mjs +1 -1
- package/dist/plugins/anonymous/index.mjs +1 -1
- package/dist/plugins/device-authorization/routes.mjs +1 -1
- package/dist/plugins/email-otp/routes.mjs +1 -1
- package/dist/plugins/generic-oauth/client.d.mts +6 -6
- package/dist/plugins/generic-oauth/client.mjs +6 -0
- package/dist/plugins/generic-oauth/error-codes.d.mts +1 -6
- package/dist/plugins/generic-oauth/error-codes.mjs +2 -7
- package/dist/plugins/generic-oauth/index.d.mts +9 -156
- package/dist/plugins/generic-oauth/index.mjs +125 -74
- package/dist/plugins/generic-oauth/providers/auth0.d.mts +1 -1
- package/dist/plugins/generic-oauth/providers/gumroad.d.mts +1 -1
- package/dist/plugins/generic-oauth/providers/hubspot.d.mts +1 -1
- package/dist/plugins/generic-oauth/providers/keycloak.d.mts +1 -1
- package/dist/plugins/generic-oauth/providers/microsoft-entra-id.d.mts +1 -1
- package/dist/plugins/generic-oauth/providers/okta.d.mts +1 -1
- package/dist/plugins/generic-oauth/providers/patreon.d.mts +1 -1
- package/dist/plugins/generic-oauth/providers/slack.d.mts +1 -1
- package/dist/plugins/generic-oauth/types.d.mts +18 -25
- package/dist/plugins/index.d.mts +4 -4
- package/dist/plugins/index.mjs +2 -2
- package/dist/plugins/jwt/client.d.mts +1 -1
- package/dist/plugins/jwt/index.d.mts +3 -3
- package/dist/plugins/jwt/index.mjs +2 -2
- package/dist/plugins/jwt/sign.d.mts +15 -3
- package/dist/plugins/jwt/sign.mjs +31 -12
- package/dist/plugins/jwt/types.d.mts +13 -1
- package/dist/plugins/jwt/utils.mjs +1 -1
- package/dist/plugins/last-login-method/index.mjs +1 -1
- package/dist/plugins/mcp/index.mjs +20 -8
- package/dist/plugins/oauth-proxy/index.mjs +3 -3
- package/dist/plugins/oidc-provider/index.mjs +2 -2
- 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 +1 -1
- package/dist/plugins/two-factor/index.d.mts +2 -2
- package/dist/plugins/two-factor/index.mjs +16 -6
- package/dist/plugins/two-factor/types.d.mts +5 -0
- package/dist/test-utils/test-instance.d.mts +12 -0
- 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/plugins/generic-oauth/routes.mjs +0 -411
package/dist/api/index.d.mts
CHANGED
|
@@ -216,6 +216,7 @@ declare function getEndpoints<Option extends BetterAuthOptions>(ctx: Awaitable<A
|
|
|
216
216
|
error_description: zod.ZodOptional<zod.ZodString>;
|
|
217
217
|
state: zod.ZodOptional<zod.ZodString>;
|
|
218
218
|
user: zod.ZodOptional<zod.ZodString>;
|
|
219
|
+
iss: zod.ZodOptional<zod.ZodString>;
|
|
219
220
|
}, zod_v4_core0.$strip>>;
|
|
220
221
|
query: zod.ZodOptional<zod.ZodObject<{
|
|
221
222
|
code: zod.ZodOptional<zod.ZodString>;
|
|
@@ -224,6 +225,7 @@ declare function getEndpoints<Option extends BetterAuthOptions>(ctx: Awaitable<A
|
|
|
224
225
|
error_description: zod.ZodOptional<zod.ZodString>;
|
|
225
226
|
state: zod.ZodOptional<zod.ZodString>;
|
|
226
227
|
user: zod.ZodOptional<zod.ZodString>;
|
|
228
|
+
iss: zod.ZodOptional<zod.ZodString>;
|
|
227
229
|
}, zod_v4_core0.$strip>>;
|
|
228
230
|
metadata: {
|
|
229
231
|
allowedMediaTypes: string[];
|
|
@@ -2205,6 +2207,7 @@ declare const router: <Option extends BetterAuthOptions>(ctx: AuthContext, optio
|
|
|
2205
2207
|
error_description: zod.ZodOptional<zod.ZodString>;
|
|
2206
2208
|
state: zod.ZodOptional<zod.ZodString>;
|
|
2207
2209
|
user: zod.ZodOptional<zod.ZodString>;
|
|
2210
|
+
iss: zod.ZodOptional<zod.ZodString>;
|
|
2208
2211
|
}, zod_v4_core0.$strip>>;
|
|
2209
2212
|
query: zod.ZodOptional<zod.ZodObject<{
|
|
2210
2213
|
code: zod.ZodOptional<zod.ZodString>;
|
|
@@ -2213,6 +2216,7 @@ declare const router: <Option extends BetterAuthOptions>(ctx: AuthContext, optio
|
|
|
2213
2216
|
error_description: zod.ZodOptional<zod.ZodString>;
|
|
2214
2217
|
state: zod.ZodOptional<zod.ZodString>;
|
|
2215
2218
|
user: zod.ZodOptional<zod.ZodString>;
|
|
2219
|
+
iss: zod.ZodOptional<zod.ZodString>;
|
|
2216
2220
|
}, zod_v4_core0.$strip>>;
|
|
2217
2221
|
metadata: {
|
|
2218
2222
|
allowedMediaTypes: string[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseAccountOutput } from "../../db/schema.mjs";
|
|
2
|
-
import { getAwaitableValue } from "../../context/helpers.mjs";
|
|
3
2
|
import { getAccountCookie, setAccountCookie } from "../../cookies/session-store.mjs";
|
|
3
|
+
import { getAwaitableValue } from "../../context/helpers.mjs";
|
|
4
4
|
import { generateState } from "../../oauth2/state.mjs";
|
|
5
5
|
import { decryptOAuthToken, setTokenUtil } from "../../oauth2/utils.mjs";
|
|
6
6
|
import { freshSessionMiddleware, getSessionFromCtx, sessionMiddleware } from "./session.mjs";
|
|
@@ -12,6 +12,7 @@ declare const callbackOAuth: better_call0.StrictEndpoint<"/callback/:id", {
|
|
|
12
12
|
error_description: z.ZodOptional<z.ZodString>;
|
|
13
13
|
state: z.ZodOptional<z.ZodString>;
|
|
14
14
|
user: z.ZodOptional<z.ZodString>;
|
|
15
|
+
iss: z.ZodOptional<z.ZodString>;
|
|
15
16
|
}, z.core.$strip>>;
|
|
16
17
|
query: z.ZodOptional<z.ZodObject<{
|
|
17
18
|
code: z.ZodOptional<z.ZodString>;
|
|
@@ -20,6 +21,7 @@ declare const callbackOAuth: better_call0.StrictEndpoint<"/callback/:id", {
|
|
|
20
21
|
error_description: z.ZodOptional<z.ZodString>;
|
|
21
22
|
state: z.ZodOptional<z.ZodString>;
|
|
22
23
|
user: z.ZodOptional<z.ZodString>;
|
|
24
|
+
iss: z.ZodOptional<z.ZodString>;
|
|
23
25
|
}, z.core.$strip>>;
|
|
24
26
|
metadata: {
|
|
25
27
|
allowedMediaTypes: string[];
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { getAwaitableValue } from "../../context/helpers.mjs";
|
|
2
1
|
import { setSessionCookie } from "../../cookies/index.mjs";
|
|
2
|
+
import { getAwaitableValue } from "../../context/helpers.mjs";
|
|
3
3
|
import { parseState } from "../../oauth2/state.mjs";
|
|
4
4
|
import { setTokenUtil } from "../../oauth2/utils.mjs";
|
|
5
|
+
import { OAUTH_CALLBACK_ERROR_CODES } from "../../oauth2/error-codes.mjs";
|
|
5
6
|
import { handleOAuthUserInfo } from "../../oauth2/link-account.mjs";
|
|
6
7
|
import { HIDE_METADATA } from "../../utils/hide-metadata.mjs";
|
|
7
8
|
import { safeJSONParse } from "@better-auth/core/utils/json";
|
|
@@ -14,7 +15,8 @@ const schema = z.object({
|
|
|
14
15
|
device_id: z.string().optional(),
|
|
15
16
|
error_description: z.string().optional(),
|
|
16
17
|
state: z.string().optional(),
|
|
17
|
-
user: z.string().optional()
|
|
18
|
+
user: z.string().optional(),
|
|
19
|
+
iss: z.string().optional()
|
|
18
20
|
});
|
|
19
21
|
const callbackOAuth = createAuthEndpoint("/callback/:id", {
|
|
20
22
|
method: ["GET", "POST"],
|
|
@@ -48,7 +50,7 @@ const callbackOAuth = createAuthEndpoint("/callback/:id", {
|
|
|
48
50
|
c.context.logger.error("INVALID_CALLBACK_REQUEST", e);
|
|
49
51
|
throw c.redirect(`${defaultErrorURL}?error=invalid_callback_request`);
|
|
50
52
|
}
|
|
51
|
-
const { code, error, state, error_description, device_id, user: userData } = queryOrBody;
|
|
53
|
+
const { code, error, state, error_description, device_id, user: userData, iss } = queryOrBody;
|
|
52
54
|
if (!state) {
|
|
53
55
|
c.context.logger.error("State not found", error);
|
|
54
56
|
const url = `${defaultErrorURL}${defaultErrorURL.includes("?") ? "&" : "?"}state=state_not_found`;
|
|
@@ -65,12 +67,19 @@ const callbackOAuth = createAuthEndpoint("/callback/:id", {
|
|
|
65
67
|
if (error) redirectOnError(error, error_description);
|
|
66
68
|
if (!code) {
|
|
67
69
|
c.context.logger.error("Code not found");
|
|
68
|
-
throw redirectOnError(
|
|
70
|
+
throw redirectOnError(OAUTH_CALLBACK_ERROR_CODES.NO_CODE);
|
|
69
71
|
}
|
|
70
72
|
const provider = await getAwaitableValue(c.context.socialProviders, { value: c.params.id });
|
|
71
73
|
if (!provider) {
|
|
72
74
|
c.context.logger.error("Oauth provider with id", c.params.id, "not found");
|
|
73
|
-
throw redirectOnError(
|
|
75
|
+
throw redirectOnError(OAUTH_CALLBACK_ERROR_CODES.PROVIDER_NOT_FOUND);
|
|
76
|
+
}
|
|
77
|
+
if (iss && provider.issuer && iss !== provider.issuer) {
|
|
78
|
+
c.context.logger.error("OAuth issuer mismatch", {
|
|
79
|
+
expected: provider.issuer,
|
|
80
|
+
received: iss
|
|
81
|
+
});
|
|
82
|
+
throw redirectOnError(OAUTH_CALLBACK_ERROR_CODES.ISSUER_MISMATCH);
|
|
74
83
|
}
|
|
75
84
|
let tokens;
|
|
76
85
|
try {
|
|
@@ -82,9 +91,9 @@ const callbackOAuth = createAuthEndpoint("/callback/:id", {
|
|
|
82
91
|
});
|
|
83
92
|
} catch (e) {
|
|
84
93
|
c.context.logger.error("", e);
|
|
85
|
-
throw redirectOnError(
|
|
94
|
+
throw redirectOnError(OAUTH_CALLBACK_ERROR_CODES.INVALID_CODE);
|
|
86
95
|
}
|
|
87
|
-
if (!tokens) throw redirectOnError(
|
|
96
|
+
if (!tokens) throw redirectOnError(OAUTH_CALLBACK_ERROR_CODES.INVALID_CODE);
|
|
88
97
|
const parsedUserData = userData ? safeJSONParse(userData) : null;
|
|
89
98
|
const userInfo = await provider.getUserInfo({
|
|
90
99
|
...tokens,
|
|
@@ -92,21 +101,21 @@ const callbackOAuth = createAuthEndpoint("/callback/:id", {
|
|
|
92
101
|
}).then((res) => res?.user);
|
|
93
102
|
if (!userInfo) {
|
|
94
103
|
c.context.logger.error("Unable to get user info");
|
|
95
|
-
return redirectOnError(
|
|
104
|
+
return redirectOnError(OAUTH_CALLBACK_ERROR_CODES.UNABLE_TO_GET_USER_INFO);
|
|
96
105
|
}
|
|
97
106
|
if (!callbackURL) {
|
|
98
107
|
c.context.logger.error("No callback URL found");
|
|
99
|
-
throw redirectOnError(
|
|
108
|
+
throw redirectOnError(OAUTH_CALLBACK_ERROR_CODES.NO_CALLBACK_URL);
|
|
100
109
|
}
|
|
101
110
|
if (link) {
|
|
102
111
|
if (!c.context.trustedProviders.includes(provider.id) && !userInfo.emailVerified || c.context.options.account?.accountLinking?.enabled === false) {
|
|
103
112
|
c.context.logger.error("Unable to link account - untrusted provider");
|
|
104
|
-
return redirectOnError(
|
|
113
|
+
return redirectOnError(OAUTH_CALLBACK_ERROR_CODES.UNABLE_TO_LINK_ACCOUNT);
|
|
105
114
|
}
|
|
106
|
-
if (userInfo.email?.toLowerCase() !== link.email.toLowerCase() && c.context.options.account?.accountLinking?.allowDifferentEmails !== true) return redirectOnError(
|
|
115
|
+
if (userInfo.email?.toLowerCase() !== link.email.toLowerCase() && c.context.options.account?.accountLinking?.allowDifferentEmails !== true) return redirectOnError(OAUTH_CALLBACK_ERROR_CODES.EMAIL_DOES_NOT_MATCH);
|
|
107
116
|
const existingAccount = await c.context.internalAdapter.findAccountByProviderId(String(userInfo.id), provider.id);
|
|
108
117
|
if (existingAccount) {
|
|
109
|
-
if (existingAccount.userId.toString() !== link.userId.toString()) return redirectOnError(
|
|
118
|
+
if (existingAccount.userId.toString() !== link.userId.toString()) return redirectOnError(OAUTH_CALLBACK_ERROR_CODES.ACCOUNT_ALREADY_LINKED_TO_DIFFERENT_USER);
|
|
110
119
|
const updateData = Object.fromEntries(Object.entries({
|
|
111
120
|
accessToken: await setTokenUtil(tokens.accessToken, c.context),
|
|
112
121
|
refreshToken: await setTokenUtil(tokens.refreshToken, c.context),
|
|
@@ -124,7 +133,7 @@ const callbackOAuth = createAuthEndpoint("/callback/:id", {
|
|
|
124
133
|
accessToken: await setTokenUtil(tokens.accessToken, c.context),
|
|
125
134
|
refreshToken: await setTokenUtil(tokens.refreshToken, c.context),
|
|
126
135
|
scope: tokens.scopes?.join(",")
|
|
127
|
-
})) return redirectOnError(
|
|
136
|
+
})) return redirectOnError(OAUTH_CALLBACK_ERROR_CODES.UNABLE_TO_LINK_ACCOUNT);
|
|
128
137
|
let toRedirectTo;
|
|
129
138
|
try {
|
|
130
139
|
toRedirectTo = callbackURL.toString();
|
|
@@ -135,7 +144,7 @@ const callbackOAuth = createAuthEndpoint("/callback/:id", {
|
|
|
135
144
|
}
|
|
136
145
|
if (!userInfo.email) {
|
|
137
146
|
c.context.logger.error("Provider did not return email. This could be due to misconfiguration in the provider settings.");
|
|
138
|
-
return redirectOnError(
|
|
147
|
+
return redirectOnError(OAUTH_CALLBACK_ERROR_CODES.EMAIL_NOT_FOUND);
|
|
139
148
|
}
|
|
140
149
|
const accountData = {
|
|
141
150
|
providerId: provider.id,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { originCheck } from "../middlewares/origin-check.mjs";
|
|
2
|
-
import { parseUserOutput } from "../../db/schema.mjs";
|
|
3
2
|
import { signJWT } from "../../crypto/jwt.mjs";
|
|
3
|
+
import { parseUserOutput } from "../../db/schema.mjs";
|
|
4
4
|
import { setSessionCookie } from "../../cookies/index.mjs";
|
|
5
5
|
import { getSessionFromCtx } from "./session.mjs";
|
|
6
6
|
import { APIError, BASE_ERROR_CODES } from "@better-auth/core/error";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isAPIError } from "../../utils/is-api-error.mjs";
|
|
2
|
-
import { getDate } from "../../utils/date.mjs";
|
|
3
|
-
import { parseSessionOutput, parseUserOutput } from "../../db/schema.mjs";
|
|
4
2
|
import { symmetricDecodeJWT, verifyJWT } from "../../crypto/jwt.mjs";
|
|
3
|
+
import { parseSessionOutput, parseUserOutput } from "../../db/schema.mjs";
|
|
4
|
+
import { getDate } from "../../utils/date.mjs";
|
|
5
5
|
import { getChunkedCookie, getSessionQuerySchema } from "../../cookies/session-store.mjs";
|
|
6
6
|
import { deleteSessionCookie, expireCookie, setCookieCache, setSessionCookie } from "../../cookies/index.mjs";
|
|
7
7
|
import { getShouldSkipSessionRefresh } from "../state/should-session-refresh.mjs";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { formCsrfMiddleware } from "../middlewares/origin-check.mjs";
|
|
2
2
|
import { parseUserOutput } from "../../db/schema.mjs";
|
|
3
|
-
import { getAwaitableValue } from "../../context/helpers.mjs";
|
|
4
3
|
import { setSessionCookie } from "../../cookies/index.mjs";
|
|
4
|
+
import { getAwaitableValue } from "../../context/helpers.mjs";
|
|
5
5
|
import { generateState } from "../../oauth2/state.mjs";
|
|
6
6
|
import { handleOAuthUserInfo } from "../../oauth2/link-account.mjs";
|
|
7
7
|
import { createEmailVerificationToken } from "./email-verification.mjs";
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { isAPIError } from "../utils/is-api-error.mjs";
|
|
2
|
+
import { isDynamicBaseURLConfig, isRequestLike } from "../utils/url.mjs";
|
|
3
|
+
import { pickSource, resolveDynamicTrustedProxyHeaders, resolveRequestContext } from "../context/helpers.mjs";
|
|
2
4
|
import { hasRequestState, runWithEndpointContext, runWithRequestState } from "@better-auth/core/context";
|
|
3
5
|
import { shouldPublishLog } from "@better-auth/core/env";
|
|
4
|
-
import { APIError } from "@better-auth/core/error";
|
|
6
|
+
import { APIError, BetterAuthError } from "@better-auth/core/error";
|
|
5
7
|
import { createDefu } from "defu";
|
|
6
8
|
import { ATTR_CONTEXT, ATTR_HOOK_TYPE, ATTR_HTTP_ROUTE, ATTR_OPERATION_ID, withSpan } from "@better-auth/core/instrumentation";
|
|
7
9
|
import { kAPIErrorHeaderSymbol, toResponse } from "better-call";
|
|
@@ -18,6 +20,27 @@ function getOperationId(endpoint, key) {
|
|
|
18
20
|
const opts = endpoint.options;
|
|
19
21
|
return opts.operationId ?? opts.metadata?.openapi?.operationId ?? key;
|
|
20
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolves the per-call `AuthContext` for endpoints with a dynamic `baseURL`.
|
|
25
|
+
*
|
|
26
|
+
* - `rawCtx.baseURL` already set: HTTP handler rehydrated upstream; return as-is.
|
|
27
|
+
* - Direct `auth.api` call with a source or a configured `fallback`: resolve here.
|
|
28
|
+
* - Neither: throw `APIError` with a helpful message. Leaving `baseURL = ""`
|
|
29
|
+
* would let plugins build `new URL("")` and crash cryptically downstream.
|
|
30
|
+
*/
|
|
31
|
+
async function resolveDynamicContext(rawCtx, input) {
|
|
32
|
+
if (rawCtx.baseURL) return rawCtx;
|
|
33
|
+
const source = pickSource(input);
|
|
34
|
+
const config = rawCtx.options.baseURL;
|
|
35
|
+
const hasFallback = isDynamicBaseURLConfig(config) && Boolean(config.fallback);
|
|
36
|
+
if (source === void 0 && !hasFallback) throw new APIError("INTERNAL_SERVER_ERROR", { message: "Dynamic baseURL could not be resolved for this direct auth.api call. Pass `headers: request.headers` (or `request`) to the call, or add `fallback` to your baseURL config." });
|
|
37
|
+
try {
|
|
38
|
+
return await resolveRequestContext(rawCtx, source, resolveDynamicTrustedProxyHeaders(rawCtx.options));
|
|
39
|
+
} catch (err) {
|
|
40
|
+
if (err instanceof BetterAuthError) throw new APIError("INTERNAL_SERVER_ERROR", { message: err.message });
|
|
41
|
+
throw err;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
21
44
|
function toAuthEndpoints(endpoints, ctx) {
|
|
22
45
|
const api = {};
|
|
23
46
|
for (const [key, endpoint] of Object.entries(endpoints)) {
|
|
@@ -26,9 +49,10 @@ function toAuthEndpoints(endpoints, ctx) {
|
|
|
26
49
|
const endpointMethod = endpoint?.options?.method;
|
|
27
50
|
const defaultMethod = Array.isArray(endpointMethod) ? endpointMethod[0] : endpointMethod;
|
|
28
51
|
const run = async () => {
|
|
29
|
-
const
|
|
52
|
+
const rawContext = await ctx;
|
|
30
53
|
const methodName = context?.method ?? context?.request?.method ?? defaultMethod ?? "?";
|
|
31
54
|
const route = endpoint.path ?? "/:virtual";
|
|
55
|
+
const authContext = isDynamicBaseURLConfig(rawContext.options.baseURL) ? await resolveDynamicContext(rawContext, context) : rawContext;
|
|
32
56
|
let internalContext = {
|
|
33
57
|
...context,
|
|
34
58
|
context: {
|
|
@@ -40,7 +64,7 @@ function toAuthEndpoints(endpoints, ctx) {
|
|
|
40
64
|
path: endpoint.path,
|
|
41
65
|
headers: context?.headers ? new Headers(context?.headers) : void 0
|
|
42
66
|
};
|
|
43
|
-
const hasRequest = context?.request
|
|
67
|
+
const hasRequest = isRequestLike(context?.request);
|
|
44
68
|
const shouldReturnResponse = context?.asResponse ?? hasRequest;
|
|
45
69
|
return withSpan(`${methodName} ${route}`, {
|
|
46
70
|
[ATTR_HTTP_ROUTE]: route,
|
package/dist/auth/base.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { getBaseURL, getOrigin, isDynamicBaseURLConfig
|
|
2
|
-
import { getTrustedOrigins, getTrustedProviders } from "../context/helpers.mjs";
|
|
3
|
-
import { createCookieGetter, getCookies } from "../cookies/index.mjs";
|
|
1
|
+
import { getBaseURL, getOrigin, isDynamicBaseURLConfig } from "../utils/url.mjs";
|
|
2
|
+
import { getTrustedOrigins, getTrustedProviders, resolveDynamicTrustedProxyHeaders, resolveRequestContext } from "../context/helpers.mjs";
|
|
4
3
|
import { getEndpoints, router } from "../api/index.mjs";
|
|
5
4
|
import { runWithAdapter } from "@better-auth/core/context";
|
|
6
5
|
import { BASE_ERROR_CODES, BetterAuthError } from "@better-auth/core/error";
|
|
@@ -13,26 +12,8 @@ const createBetterAuth = (options, initFn) => {
|
|
|
13
12
|
const ctx = await authContext;
|
|
14
13
|
const basePath = ctx.options.basePath || "/api/auth";
|
|
15
14
|
let handlerCtx;
|
|
16
|
-
if (isDynamicBaseURLConfig(options.baseURL))
|
|
17
|
-
|
|
18
|
-
const baseURL = resolveBaseURL(options.baseURL, basePath, request);
|
|
19
|
-
if (baseURL) {
|
|
20
|
-
handlerCtx.baseURL = baseURL;
|
|
21
|
-
handlerCtx.options = {
|
|
22
|
-
...ctx.options,
|
|
23
|
-
baseURL: getOrigin(baseURL) || void 0
|
|
24
|
-
};
|
|
25
|
-
} else throw new BetterAuthError("Could not resolve base URL from request. Check your allowedHosts config.");
|
|
26
|
-
const trustedOriginOptions = {
|
|
27
|
-
...handlerCtx.options,
|
|
28
|
-
baseURL: options.baseURL
|
|
29
|
-
};
|
|
30
|
-
handlerCtx.trustedOrigins = await getTrustedOrigins(trustedOriginOptions, request);
|
|
31
|
-
if (options.advanced?.crossSubDomainCookies?.enabled) {
|
|
32
|
-
handlerCtx.authCookies = getCookies(handlerCtx.options);
|
|
33
|
-
handlerCtx.createAuthCookie = createCookieGetter(handlerCtx.options);
|
|
34
|
-
}
|
|
35
|
-
} else {
|
|
15
|
+
if (isDynamicBaseURLConfig(options.baseURL)) handlerCtx = await resolveRequestContext(ctx, request, resolveDynamicTrustedProxyHeaders(ctx.options));
|
|
16
|
+
else {
|
|
36
17
|
handlerCtx = ctx;
|
|
37
18
|
if (!ctx.options.baseURL) {
|
|
38
19
|
const baseURL = getBaseURL(void 0, basePath, request, void 0, ctx.options.advanced?.trustedProxyHeaders);
|
|
@@ -42,8 +23,8 @@ const createBetterAuth = (options, initFn) => {
|
|
|
42
23
|
} else throw new BetterAuthError("Could not get base URL from request. Please provide a valid base URL.");
|
|
43
24
|
}
|
|
44
25
|
handlerCtx.trustedOrigins = await getTrustedOrigins(ctx.options, request);
|
|
26
|
+
handlerCtx.trustedProviders = await getTrustedProviders(ctx.options, request);
|
|
45
27
|
}
|
|
46
|
-
handlerCtx.trustedProviders = await getTrustedProviders(handlerCtx.options, request);
|
|
47
28
|
const { handler } = router(handlerCtx, options);
|
|
48
29
|
return runWithAdapter(handlerCtx.adapter, () => handler(request));
|
|
49
30
|
},
|
|
@@ -1,10 +1,41 @@
|
|
|
1
1
|
import { HasRequiredKeys, IsAny, Prettify as Prettify$1, UnionToIntersection } from "../types/helper.mjs";
|
|
2
2
|
import { InferAdditionalFromClient, InferSessionFromClient, InferUserFromClient } from "./types.mjs";
|
|
3
3
|
import { BetterAuthClientOptions, ClientFetchOption } from "@better-auth/core";
|
|
4
|
+
import { SocialProviderList } from "@better-auth/core/social-providers";
|
|
4
5
|
import { Endpoint, InputContext, StandardSchemaV1 } from "better-call";
|
|
5
6
|
import { BetterFetchResponse } from "@better-fetch/fetch";
|
|
6
7
|
|
|
7
8
|
//#region src/client/path-to-object.d.ts
|
|
9
|
+
/**
|
|
10
|
+
* Extract generic OAuth provider IDs from the client options.
|
|
11
|
+
* Supports both `$InferAuth` (server type bridge) and client plugins
|
|
12
|
+
* with `$InferServerPlugin`.
|
|
13
|
+
*/
|
|
14
|
+
type InferGenericOAuthProviderIds<O extends BetterAuthClientOptions> = (O extends {
|
|
15
|
+
$InferAuth: {
|
|
16
|
+
options: {
|
|
17
|
+
plugins: Array<infer P>;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
} ? P extends {
|
|
21
|
+
id: "generic-oauth";
|
|
22
|
+
options: {
|
|
23
|
+
config: Array<{
|
|
24
|
+
providerId: infer ID;
|
|
25
|
+
}>;
|
|
26
|
+
};
|
|
27
|
+
} ? ID & string : never : never) | (O extends {
|
|
28
|
+
plugins: Array<infer P>;
|
|
29
|
+
} ? P extends {
|
|
30
|
+
$InferServerPlugin: {
|
|
31
|
+
id: "generic-oauth";
|
|
32
|
+
options: {
|
|
33
|
+
config: Array<{
|
|
34
|
+
providerId: infer ID;
|
|
35
|
+
}>;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
} ? ID & string : never : never);
|
|
8
39
|
type KeepNullishFromOriginal<Original, Replaced> = Replaced | (undefined extends Original ? undefined : never) | (null extends Original ? null : never);
|
|
9
40
|
type ReplaceTopLevelField<Data, Field extends "user" | "session", Replaced> = Data extends object ? Field extends keyof Data ? Omit<Data, Field> & { [K in Field]: KeepNullishFromOriginal<Data[K], Replaced> } : Data : Data;
|
|
10
41
|
type ReplaceAuthUserAndSession<Data, ClientOpts extends BetterAuthClientOptions> = ReplaceTopLevelField<ReplaceTopLevelField<Data, "user", InferUserFromClient<ClientOpts>>, "session", InferSessionFromClient<ClientOpts>>;
|
|
@@ -51,7 +82,10 @@ type InferRoute<API, COpts extends BetterAuthClientOptions> = API extends Record
|
|
|
51
82
|
scope: "http";
|
|
52
83
|
} | {
|
|
53
84
|
scope: "server";
|
|
54
|
-
} ? {} : PathToObject<T["path"], T extends ((ctx: infer C) => infer R) ? C extends InputContext<any, any> ? <FetchOptions extends ClientFetchOption<Partial<C["body"]> & Record<string, any>, Partial<C["query"]> & Record<string, any>, C["params"]>>(...data: HasRequiredKeys<InferCtx<C, FetchOptions>> extends true ? [Prettify$1<T["path"] extends `/sign-up/email` ? InferSignUpEmailCtx<COpts, FetchOptions> :
|
|
85
|
+
} ? {} : PathToObject<T["path"], T extends ((ctx: infer C) => infer R) ? C extends InputContext<any, any> ? <FetchOptions extends ClientFetchOption<Partial<C["body"]> & Record<string, any>, Partial<C["query"]> & Record<string, any>, C["params"]>>(...data: HasRequiredKeys<InferCtx<C, FetchOptions>> extends true ? [Prettify$1<T["path"] extends `/sign-up/email` ? InferSignUpEmailCtx<COpts, FetchOptions> : T["path"] extends `/sign-in/social` ? Omit<InferCtx<C, FetchOptions>, "provider"> & {
|
|
86
|
+
provider: SocialProviderList[number] | InferGenericOAuthProviderIds<COpts> | (string & {});
|
|
87
|
+
fetchOptions?: FetchOptions | undefined;
|
|
88
|
+
} : InferCtx<C, FetchOptions>>, FetchOptions?] : [Prettify$1<T["path"] extends `/update-user` ? InferUserUpdateCtx<COpts, FetchOptions> : InferCtx<C, FetchOptions>>?, FetchOptions?]) => Promise<BetterFetchResponse<T["options"]["metadata"] extends {
|
|
55
89
|
CUSTOM_SESSION: boolean;
|
|
56
90
|
} ? MergeCustomSessionWithInferred<NonNullable<Awaited<R>>, COpts> : T["path"] extends "/get-session" ? {
|
|
57
91
|
user: InferUserFromClient<COpts>;
|
|
@@ -14,13 +14,13 @@ import { OktaOptions, okta } from "../../plugins/generic-oauth/providers/okta.mj
|
|
|
14
14
|
import { PatreonOptions, patreon } from "../../plugins/generic-oauth/providers/patreon.mjs";
|
|
15
15
|
import { SlackOptions, slack } from "../../plugins/generic-oauth/providers/slack.mjs";
|
|
16
16
|
import { BaseOAuthProviderOptions } from "../../plugins/generic-oauth/index.mjs";
|
|
17
|
-
import { JWKOptions, JWSAlgorithms, Jwk, JwtOptions } from "../../plugins/jwt/types.mjs";
|
|
17
|
+
import { JWKOptions, JWSAlgorithms, Jwk, JwtOptions, ResolvedSigningKey } from "../../plugins/jwt/types.mjs";
|
|
18
18
|
import { AuthorizationQuery, Client, CodeVerificationValue, OAuthAccessToken, OIDCMetadata, OIDCOptions, TokenBody } from "../../plugins/oidc-provider/types.mjs";
|
|
19
19
|
import { MULTI_SESSION_ERROR_CODES } from "../../plugins/multi-session/error-codes.mjs";
|
|
20
20
|
import { MultiSessionConfig } from "../../plugins/multi-session/index.mjs";
|
|
21
21
|
import { OneTimeTokenOptions } from "../../plugins/one-time-token/index.mjs";
|
|
22
22
|
import { PhoneNumberOptions, UserWithPhoneNumber } from "../../plugins/phone-number/types.mjs";
|
|
23
|
-
import { BackupCodeOptions, backupCode2fa, generateBackupCodes, getBackupCodes, verifyBackupCode } from "../../plugins/two-factor/backup-codes/index.mjs";
|
|
23
|
+
import { BackupCodeOptions, backupCode2fa, encodeBackupCodes, generateBackupCodes, getBackupCodes, verifyBackupCode } from "../../plugins/two-factor/backup-codes/index.mjs";
|
|
24
24
|
import { OTPOptions, otp2fa } from "../../plugins/two-factor/otp/index.mjs";
|
|
25
25
|
import { TOTPOptions, totp2fa } from "../../plugins/two-factor/totp/index.mjs";
|
|
26
26
|
import { TwoFactorOptions, TwoFactorProvider, TwoFactorTable, UserWithTwoFactor } from "../../plugins/two-factor/types.mjs";
|
|
@@ -37,6 +37,7 @@ import { customSessionClient } from "../../plugins/custom-session/client.mjs";
|
|
|
37
37
|
import { deviceAuthorizationClient } from "../../plugins/device-authorization/client.mjs";
|
|
38
38
|
import { EMAIL_OTP_ERROR_CODES } from "../../plugins/email-otp/error-codes.mjs";
|
|
39
39
|
import { emailOTPClient } from "../../plugins/email-otp/client.mjs";
|
|
40
|
+
import { OAUTH_CALLBACK_ERROR_CODES } from "../../oauth2/error-codes.mjs";
|
|
40
41
|
import { GENERIC_OAUTH_ERROR_CODES } from "../../plugins/generic-oauth/error-codes.mjs";
|
|
41
42
|
import { genericOAuthClient } from "../../plugins/generic-oauth/client.mjs";
|
|
42
43
|
import { jwtClient } from "../../plugins/jwt/client.mjs";
|
|
@@ -52,4 +53,4 @@ import { phoneNumberClient } from "../../plugins/phone-number/client.mjs";
|
|
|
52
53
|
import { siweClient } from "../../plugins/siwe/client.mjs";
|
|
53
54
|
import { usernameClient } from "../../plugins/username/client.mjs";
|
|
54
55
|
import { InferServerPlugin } from "./infer-plugin.mjs";
|
|
55
|
-
export { ADMIN_ERROR_CODES, ANONYMOUS_ERROR_CODES, AdminOptions, AnonymousOptions, AnonymousSession, Auth0Options, AuthorizationQuery, BackupCodeOptions, BaseOAuthProviderOptions, Client, CodeVerificationValue, EMAIL_OTP_ERROR_CODES, ExtractPluginField, GENERIC_OAUTH_ERROR_CODES, GenericOAuthConfig, GenericOAuthOptions, GoogleOneTapActionOptions, GoogleOneTapOptions, GsiButtonConfiguration, GumroadOptions, HasRequiredKeys, HubSpotOptions, InferAdminRolesFromOption, InferInvitation, InferMember, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPluginFieldFromTuple, InferServerPlugin, InferTeam, Invitation, InvitationInput, InvitationStatus, IsAny, JWKOptions, JWSAlgorithms, Jwk, JwtOptions, KeycloakOptions, LastLoginMethodClientConfig, LineOptions, MULTI_SESSION_ERROR_CODES, Member, MemberInput, MicrosoftEntraIdOptions, MultiSessionConfig, OAuthAccessToken, OIDCMetadata, OIDCOptions, ORGANIZATION_ERROR_CODES, OTPOptions, OidcClientPlugin, OktaOptions, OneTimeTokenOptions, Organization, OrganizationInput, OrganizationRole, OrganizationSchema, OverrideMerge, PHONE_NUMBER_ERROR_CODES, PatreonOptions, PhoneNumberOptions, Prettify, PrettifyDeep, RequiredKeysOf, SessionWithImpersonatedBy, SlackOptions, StripEmptyObjects, TOTPOptions, TWO_FACTOR_ERROR_CODES, Team, TeamInput, TeamMember, TeamMemberInput, TokenBody, TwoFactorOptions, TwoFactorProvider, TwoFactorTable, USERNAME_ERROR_CODES, UnionToIntersection, UserWithAnonymous, UserWithPhoneNumber, UserWithRole, UserWithTwoFactor, adminClient, anonymousClient, auth0, backupCode2fa, clientSideHasPermission, customSessionClient, defaultRolesSchema, deviceAuthorizationClient, emailOTPClient, generateBackupCodes, genericOAuthClient, getBackupCodes, gumroad, hubspot, inferAdditionalFields, inferOrgAdditionalFields, invitationSchema, invitationStatus, jwtClient, keycloak, lastLoginMethodClient, line, magicLinkClient, memberSchema, microsoftEntraId, multiSessionClient, oidcClient, okta, oneTapClient, oneTimeTokenClient, organizationClient, organizationRoleSchema, organizationSchema, otp2fa, patreon, phoneNumberClient, roleSchema, schema, siweClient, slack, teamMemberSchema, teamSchema, totp2fa, twoFactorClient, usernameClient, verifyBackupCode };
|
|
56
|
+
export { ADMIN_ERROR_CODES, ANONYMOUS_ERROR_CODES, AdminOptions, AnonymousOptions, AnonymousSession, Auth0Options, AuthorizationQuery, BackupCodeOptions, BaseOAuthProviderOptions, Client, CodeVerificationValue, EMAIL_OTP_ERROR_CODES, ExtractPluginField, GENERIC_OAUTH_ERROR_CODES, GenericOAuthConfig, GenericOAuthOptions, GoogleOneTapActionOptions, GoogleOneTapOptions, GsiButtonConfiguration, GumroadOptions, HasRequiredKeys, HubSpotOptions, InferAdminRolesFromOption, InferInvitation, InferMember, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPluginFieldFromTuple, InferServerPlugin, InferTeam, Invitation, InvitationInput, InvitationStatus, IsAny, JWKOptions, JWSAlgorithms, Jwk, JwtOptions, KeycloakOptions, LastLoginMethodClientConfig, LineOptions, MULTI_SESSION_ERROR_CODES, Member, MemberInput, MicrosoftEntraIdOptions, MultiSessionConfig, OAUTH_CALLBACK_ERROR_CODES, OAuthAccessToken, OIDCMetadata, OIDCOptions, ORGANIZATION_ERROR_CODES, OTPOptions, OidcClientPlugin, OktaOptions, OneTimeTokenOptions, Organization, OrganizationInput, OrganizationRole, OrganizationSchema, OverrideMerge, PHONE_NUMBER_ERROR_CODES, PatreonOptions, PhoneNumberOptions, Prettify, PrettifyDeep, RequiredKeysOf, ResolvedSigningKey, SessionWithImpersonatedBy, SlackOptions, StripEmptyObjects, TOTPOptions, TWO_FACTOR_ERROR_CODES, Team, TeamInput, TeamMember, TeamMemberInput, TokenBody, TwoFactorOptions, TwoFactorProvider, TwoFactorTable, USERNAME_ERROR_CODES, UnionToIntersection, UserWithAnonymous, UserWithPhoneNumber, UserWithRole, UserWithTwoFactor, adminClient, anonymousClient, auth0, backupCode2fa, clientSideHasPermission, customSessionClient, defaultRolesSchema, deviceAuthorizationClient, emailOTPClient, encodeBackupCodes, generateBackupCodes, genericOAuthClient, getBackupCodes, gumroad, hubspot, inferAdditionalFields, inferOrgAdditionalFields, invitationSchema, invitationStatus, jwtClient, keycloak, lastLoginMethodClient, line, magicLinkClient, memberSchema, microsoftEntraId, multiSessionClient, oidcClient, okta, oneTapClient, oneTimeTokenClient, organizationClient, organizationRoleSchema, organizationSchema, otp2fa, patreon, phoneNumberClient, roleSchema, schema, siweClient, slack, teamMemberSchema, teamSchema, totp2fa, twoFactorClient, usernameClient, verifyBackupCode };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { OAUTH_CALLBACK_ERROR_CODES } from "../../oauth2/error-codes.mjs";
|
|
1
2
|
import { inferAdditionalFields } from "../../plugins/additional-fields/client.mjs";
|
|
2
3
|
import { ADMIN_ERROR_CODES } from "../../plugins/admin/error-codes.mjs";
|
|
3
4
|
import { adminClient } from "../../plugins/admin/client.mjs";
|
|
@@ -27,4 +28,4 @@ import { twoFactorClient } from "../../plugins/two-factor/client.mjs";
|
|
|
27
28
|
import { USERNAME_ERROR_CODES } from "../../plugins/username/error-codes.mjs";
|
|
28
29
|
import { usernameClient } from "../../plugins/username/client.mjs";
|
|
29
30
|
import { InferServerPlugin } from "./infer-plugin.mjs";
|
|
30
|
-
export { ADMIN_ERROR_CODES, ANONYMOUS_ERROR_CODES, EMAIL_OTP_ERROR_CODES, GENERIC_OAUTH_ERROR_CODES, InferServerPlugin, MULTI_SESSION_ERROR_CODES, ORGANIZATION_ERROR_CODES, PHONE_NUMBER_ERROR_CODES, TWO_FACTOR_ERROR_CODES, USERNAME_ERROR_CODES, adminClient, anonymousClient, clientSideHasPermission, customSessionClient, deviceAuthorizationClient, emailOTPClient, genericOAuthClient, inferAdditionalFields, inferOrgAdditionalFields, jwtClient, lastLoginMethodClient, magicLinkClient, multiSessionClient, oidcClient, oneTapClient, oneTimeTokenClient, organizationClient, phoneNumberClient, siweClient, twoFactorClient, usernameClient };
|
|
31
|
+
export { ADMIN_ERROR_CODES, ANONYMOUS_ERROR_CODES, EMAIL_OTP_ERROR_CODES, GENERIC_OAUTH_ERROR_CODES, InferServerPlugin, MULTI_SESSION_ERROR_CODES, OAUTH_CALLBACK_ERROR_CODES, ORGANIZATION_ERROR_CODES, PHONE_NUMBER_ERROR_CODES, TWO_FACTOR_ERROR_CODES, USERNAME_ERROR_CODES, adminClient, anonymousClient, clientSideHasPermission, customSessionClient, deviceAuthorizationClient, emailOTPClient, genericOAuthClient, inferAdditionalFields, inferOrgAdditionalFields, jwtClient, lastLoginMethodClient, magicLinkClient, multiSessionClient, oidcClient, oneTapClient, oneTimeTokenClient, organizationClient, phoneNumberClient, siweClient, twoFactorClient, usernameClient };
|
package/dist/client/query.mjs
CHANGED
|
@@ -72,15 +72,15 @@ const useAuthQuery = (initializedAtom, path, $fetch, options) => {
|
|
|
72
72
|
});
|
|
73
73
|
};
|
|
74
74
|
initializedAtom = Array.isArray(initializedAtom) ? initializedAtom : [initializedAtom];
|
|
75
|
-
let
|
|
75
|
+
let isInitialized = false;
|
|
76
76
|
for (const initAtom of initializedAtom) initAtom.subscribe(async () => {
|
|
77
77
|
if (isServer()) return;
|
|
78
|
-
if (
|
|
78
|
+
if (isInitialized) await fn();
|
|
79
79
|
else onMount(value, () => {
|
|
80
80
|
const timeoutId = setTimeout(async () => {
|
|
81
|
-
if (!
|
|
81
|
+
if (!isInitialized) {
|
|
82
|
+
isInitialized = true;
|
|
82
83
|
await fn();
|
|
83
|
-
isMounted = true;
|
|
84
84
|
}
|
|
85
85
|
}, 0);
|
|
86
86
|
return () => {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { getBaseURL, isDynamicBaseURLConfig } from "../utils/url.mjs";
|
|
2
2
|
import { matchesOriginPattern } from "../auth/trusted-origins.mjs";
|
|
3
|
-
import { createInternalAdapter } from "../db/internal-adapter.mjs";
|
|
4
3
|
import { isPromise } from "../utils/is-promise.mjs";
|
|
5
|
-
import { getInternalPlugins, getTrustedOrigins, getTrustedProviders, runPluginInit } from "./helpers.mjs";
|
|
6
4
|
import { hashPassword, verifyPassword } from "../crypto/password.mjs";
|
|
7
5
|
import { createCookieGetter, getCookies } from "../cookies/index.mjs";
|
|
6
|
+
import { createInternalAdapter } from "../db/internal-adapter.mjs";
|
|
7
|
+
import { getInternalPlugins, getTrustedOrigins, getTrustedProviders, runPluginInit } from "./helpers.mjs";
|
|
8
8
|
import { checkPassword } from "../utils/password.mjs";
|
|
9
9
|
import { checkEndpointConflicts } from "../api/index.mjs";
|
|
10
10
|
import { DEFAULT_SECRET } from "../utils/constants.mjs";
|
package/dist/context/helpers.mjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { getBaseURL, isDynamicBaseURLConfig } from "../utils/url.mjs";
|
|
2
|
-
import { createInternalAdapter } from "../db/internal-adapter.mjs";
|
|
1
|
+
import { getBaseURL, getOrigin, isDynamicBaseURLConfig, isRequestLike, resolveBaseURL } from "../utils/url.mjs";
|
|
3
2
|
import { isPromise } from "../utils/is-promise.mjs";
|
|
3
|
+
import { createCookieGetter, getCookies } from "../cookies/index.mjs";
|
|
4
|
+
import { createInternalAdapter } from "../db/internal-adapter.mjs";
|
|
4
5
|
import { env } from "@better-auth/core/env";
|
|
6
|
+
import { BetterAuthError } from "@better-auth/core/error";
|
|
5
7
|
import { defu } from "defu";
|
|
6
8
|
//#region src/context/helpers.ts
|
|
7
9
|
async function runPluginInit(context) {
|
|
@@ -80,6 +82,62 @@ async function getTrustedOrigins(options, request) {
|
|
|
80
82
|
if (envTrustedOrigins) trustedOrigins.push(...envTrustedOrigins.split(","));
|
|
81
83
|
return trustedOrigins.filter((v) => Boolean(v));
|
|
82
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Picks a `Request`-like or `Headers` value from a direct `auth.api` call.
|
|
87
|
+
* Headers are only accepted when they carry a host: without one, host
|
|
88
|
+
* resolution would fall back to `null` and the caller should use `fallback`
|
|
89
|
+
* or pass a `Request` instead.
|
|
90
|
+
*/
|
|
91
|
+
function pickSource(input) {
|
|
92
|
+
if (isRequestLike(input?.request)) return input.request;
|
|
93
|
+
if (!input?.headers) return void 0;
|
|
94
|
+
const headers = input.headers instanceof Headers ? input.headers : new Headers(input.headers);
|
|
95
|
+
if (!headers.has("host") && !headers.has("x-forwarded-host")) return;
|
|
96
|
+
return headers;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Returns the effective `trustedProxyHeaders` value for dynamic `baseURL`
|
|
100
|
+
* resolution. When the user hasn't set `advanced.trustedProxyHeaders`,
|
|
101
|
+
* proxy headers (`x-forwarded-host` / `x-forwarded-proto`) are trusted by
|
|
102
|
+
* default so deployments behind a reverse proxy work without extra config.
|
|
103
|
+
*/
|
|
104
|
+
function resolveDynamicTrustedProxyHeaders(options) {
|
|
105
|
+
return options.advanced?.trustedProxyHeaders ?? true;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Per-request clone with `baseURL`, `trustedOrigins`, `trustedProviders`
|
|
109
|
+
* and cookies rehydrated for the resolved host. Throws `BetterAuthError`
|
|
110
|
+
* when the URL cannot be resolved; callers on the direct-API path convert
|
|
111
|
+
* this to `APIError`.
|
|
112
|
+
*/
|
|
113
|
+
async function resolveRequestContext(ctx, source, trustedProxyHeaders) {
|
|
114
|
+
const dynamicBaseURLConfig = ctx.options.baseURL;
|
|
115
|
+
const baseURL = resolveBaseURL(dynamicBaseURLConfig, ctx.options.basePath || "/api/auth", source, void 0, trustedProxyHeaders);
|
|
116
|
+
if (!baseURL) throw new BetterAuthError("Could not resolve base URL from request. Check your allowedHosts config.");
|
|
117
|
+
const resolved = Object.create(Object.getPrototypeOf(ctx), Object.getOwnPropertyDescriptors(ctx));
|
|
118
|
+
resolved.baseURL = baseURL;
|
|
119
|
+
resolved.options = {
|
|
120
|
+
...ctx.options,
|
|
121
|
+
baseURL: getOrigin(baseURL) || void 0
|
|
122
|
+
};
|
|
123
|
+
const trustedOriginOptions = {
|
|
124
|
+
...resolved.options,
|
|
125
|
+
baseURL: dynamicBaseURLConfig
|
|
126
|
+
};
|
|
127
|
+
const needsRequest = typeof ctx.options.trustedOrigins === "function" || typeof ctx.options.account?.accountLinking?.trustedProviders === "function";
|
|
128
|
+
let callbackRequest;
|
|
129
|
+
if (needsRequest) if (isRequestLike(source)) callbackRequest = source;
|
|
130
|
+
else if (source) callbackRequest = new Request(baseURL, { headers: source });
|
|
131
|
+
else callbackRequest = void 0;
|
|
132
|
+
else callbackRequest = void 0;
|
|
133
|
+
resolved.trustedOrigins = await getTrustedOrigins(trustedOriginOptions, callbackRequest);
|
|
134
|
+
resolved.trustedProviders = await getTrustedProviders(resolved.options, callbackRequest);
|
|
135
|
+
if (ctx.options.advanced?.crossSubDomainCookies?.enabled) {
|
|
136
|
+
resolved.authCookies = getCookies(resolved.options);
|
|
137
|
+
resolved.createAuthCookie = createCookieGetter(resolved.options);
|
|
138
|
+
}
|
|
139
|
+
return resolved;
|
|
140
|
+
}
|
|
83
141
|
async function getAwaitableValue(arr, item) {
|
|
84
142
|
if (!arr) return void 0;
|
|
85
143
|
for (const val of arr) {
|
|
@@ -94,4 +152,4 @@ async function getTrustedProviders(options, request) {
|
|
|
94
152
|
return (await trustedProviders(request) ?? []).filter((v) => Boolean(v));
|
|
95
153
|
}
|
|
96
154
|
//#endregion
|
|
97
|
-
export { getAwaitableValue, getInternalPlugins, getTrustedOrigins, getTrustedProviders, runPluginInit };
|
|
155
|
+
export { getAwaitableValue, getInternalPlugins, getTrustedOrigins, getTrustedProviders, pickSource, resolveDynamicTrustedProxyHeaders, resolveRequestContext, runPluginInit };
|
package/dist/cookies/index.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { isDynamicBaseURLConfig } from "../utils/url.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { signJWT, symmetricDecodeJWT, symmetricEncodeJWT, verifyJWT } from "../crypto/jwt.mjs";
|
|
3
3
|
import { parseUserOutput } from "../db/schema.mjs";
|
|
4
|
+
import { getDate } from "../utils/date.mjs";
|
|
4
5
|
import { isPromise } from "../utils/is-promise.mjs";
|
|
5
|
-
import { signJWT, symmetricDecodeJWT, symmetricEncodeJWT, verifyJWT } from "../crypto/jwt.mjs";
|
|
6
|
-
import { createAccountStore, createSessionStore, getAccountCookie, getChunkedCookie, setAccountCookie } from "./session-store.mjs";
|
|
7
6
|
import { sec } from "../utils/time.mjs";
|
|
8
7
|
import { HOST_COOKIE_PREFIX, SECURE_COOKIE_PREFIX, parseSetCookieHeader, setCookieToHeader, splitSetCookieHeader, stripSecureCookiePrefix } from "./cookie-utils.mjs";
|
|
8
|
+
import { createAccountStore, createSessionStore, getAccountCookie, getChunkedCookie, setAccountCookie } from "./session-store.mjs";
|
|
9
9
|
import { env, isProduction } from "@better-auth/core/env";
|
|
10
10
|
import { BetterAuthError } from "@better-auth/core/error";
|
|
11
11
|
import { safeJSONParse } from "@better-auth/core/utils/json";
|
package/dist/crypto/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { constantTimeEqual } from "./buffer.mjs";
|
|
2
1
|
import { signJWT, symmetricDecodeJWT, symmetricEncodeJWT, verifyJWT } from "./jwt.mjs";
|
|
2
|
+
import { constantTimeEqual } from "./buffer.mjs";
|
|
3
3
|
import { hashPassword, verifyPassword } from "./password.mjs";
|
|
4
4
|
import { generateRandomString } from "./random.mjs";
|
|
5
|
-
import { createHash } from "@better-auth/utils/hash";
|
|
6
5
|
import { getWebcryptoSubtle } from "@better-auth/utils";
|
|
6
|
+
import { createHash } from "@better-auth/utils/hash";
|
|
7
7
|
import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
|
|
8
8
|
import { bytesToHex, hexToBytes, managedNonce, utf8ToBytes } from "@noble/ciphers/utils.js";
|
|
9
9
|
//#region src/crypto/index.ts
|
package/dist/db/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __exportAll, __reExport } from "../_virtual/_rolldown/runtime.mjs";
|
|
2
2
|
import { getSchema } from "./get-schema.mjs";
|
|
3
|
-
import { convertFromDB, convertToDB } from "./field-converter.mjs";
|
|
4
3
|
import { getSessionDefaultFields, mergeSchema, parseAccountInput, parseAccountOutput, parseAdditionalUserInput, parseInputData, parseSessionInput, parseSessionOutput, parseUserInput, parseUserOutput } from "./schema.mjs";
|
|
4
|
+
import { convertFromDB, convertToDB } from "./field-converter.mjs";
|
|
5
5
|
import { getWithHooks } from "./with-hooks.mjs";
|
|
6
6
|
import { createInternalAdapter } from "./internal-adapter.mjs";
|
|
7
7
|
import { toZodSchema } from "./to-zod.mjs";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getIp } from "../utils/get-request-ip.mjs";
|
|
2
|
-
import { getDate } from "../utils/date.mjs";
|
|
3
2
|
import { getSessionDefaultFields, parseSessionOutput, parseUserOutput } from "./schema.mjs";
|
|
3
|
+
import { getDate } from "../utils/date.mjs";
|
|
4
4
|
import { getStorageOption, processIdentifier } from "./verification-token-storage.mjs";
|
|
5
5
|
import { getWithHooks } from "./with-hooks.mjs";
|
|
6
6
|
import { getCurrentAdapter, getCurrentAuthContext, runWithTransaction } from "@better-auth/core/context";
|
package/dist/index.d.mts
CHANGED
|
@@ -10,7 +10,7 @@ import { betterAuth } from "./auth/full.mjs";
|
|
|
10
10
|
import { generateState, parseState } from "./oauth2/state.mjs";
|
|
11
11
|
import { StateData, generateGenericState, parseGenericState } from "./state.mjs";
|
|
12
12
|
import { HIDE_METADATA } from "./utils/hide-metadata.mjs";
|
|
13
|
-
import { getBaseURL, getHost,
|
|
13
|
+
import { getBaseURL, getHost, getHostFromSource, getOrigin, getProtocol, getProtocolFromSource, isDynamicBaseURLConfig, isRequestLike, matchesHostPattern, resolveBaseURL, resolveDynamicBaseURL } from "./utils/url.mjs";
|
|
14
14
|
import { APIError } from "./api/index.mjs";
|
|
15
15
|
import { StandardSchemaV1 } from "@better-auth/core";
|
|
16
16
|
import { getCurrentAdapter } from "@better-auth/core/context";
|
|
@@ -27,4 +27,4 @@ export * from "@better-auth/core/utils/json";
|
|
|
27
27
|
export * from "@better-auth/core/social-providers";
|
|
28
28
|
export * from "better-call";
|
|
29
29
|
export * from "zod";
|
|
30
|
-
export { APIError, Account, AdditionalSessionFieldsInput, AdditionalUserFieldsInput, Auth, BetterAuthAdvancedOptions, BetterAuthClientOptions, BetterAuthClientPlugin, BetterAuthCookies, BetterAuthOptions, BetterAuthPlugin, BetterAuthRateLimitOptions, ClientAtomListener, ClientStore, DBAdapter, DBAdapterInstance, DBAdapterSchemaCreation, DBTransactionAdapter, ExtractPluginField, FilteredAPI, HIDE_METADATA, HasRequiredKeys, InferAPI, InferActions, InferAdditionalFromClient, InferClientAPI, InferErrorCodes, InferOptionSchema, InferPluginContext, InferPluginErrorCodes, InferPluginFieldFromTuple, InferPluginIDs, InferPluginTypes, InferSessionAPI, InferSessionFromClient, InferUserFromClient, IsAny, IsSignal, type JSONWebKeySet, type JWTPayload, JoinConfig, JoinOption, OverrideMerge, Prettify, PrettifyDeep, RateLimit, RequiredKeysOf, Session, SessionQueryParams, type StandardSchemaV1, StateData, StoreIdentifierOption, StripEmptyObjects, type TelemetryEvent, UnionToIntersection, User, Verification, Where, betterAuth, createTelemetry, generateGenericState, generateState, getBaseURL, getCurrentAdapter, getHost,
|
|
30
|
+
export { APIError, Account, AdditionalSessionFieldsInput, AdditionalUserFieldsInput, Auth, BetterAuthAdvancedOptions, BetterAuthClientOptions, BetterAuthClientPlugin, BetterAuthCookies, BetterAuthOptions, BetterAuthPlugin, BetterAuthRateLimitOptions, ClientAtomListener, ClientStore, DBAdapter, DBAdapterInstance, DBAdapterSchemaCreation, DBTransactionAdapter, ExtractPluginField, FilteredAPI, HIDE_METADATA, HasRequiredKeys, InferAPI, InferActions, InferAdditionalFromClient, InferClientAPI, InferErrorCodes, InferOptionSchema, InferPluginContext, InferPluginErrorCodes, InferPluginFieldFromTuple, InferPluginIDs, InferPluginTypes, InferSessionAPI, InferSessionFromClient, InferUserFromClient, IsAny, IsSignal, type JSONWebKeySet, type JWTPayload, JoinConfig, JoinOption, OverrideMerge, Prettify, PrettifyDeep, RateLimit, RequiredKeysOf, Session, SessionQueryParams, type StandardSchemaV1, StateData, StoreIdentifierOption, StripEmptyObjects, type TelemetryEvent, UnionToIntersection, User, Verification, Where, betterAuth, createTelemetry, generateGenericState, generateState, getBaseURL, getCurrentAdapter, getHost, getHostFromSource, getOrigin, getProtocol, getProtocolFromSource, getTelemetryAuthConfig, isDynamicBaseURLConfig, isRequestLike, matchesHostPattern, parseGenericState, parseState, resolveBaseURL, resolveDynamicBaseURL };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getBaseURL, getHost,
|
|
1
|
+
import { getBaseURL, getHost, getHostFromSource, getOrigin, getProtocol, getProtocolFromSource, isDynamicBaseURLConfig, isRequestLike, matchesHostPattern, resolveBaseURL, resolveDynamicBaseURL } from "./utils/url.mjs";
|
|
2
2
|
import { generateGenericState, parseGenericState } from "./state.mjs";
|
|
3
3
|
import { generateState, parseState } from "./oauth2/state.mjs";
|
|
4
4
|
import { HIDE_METADATA } from "./utils/hide-metadata.mjs";
|
|
@@ -14,4 +14,4 @@ export * from "@better-auth/core/oauth2";
|
|
|
14
14
|
export * from "@better-auth/core/utils/error-codes";
|
|
15
15
|
export * from "@better-auth/core/utils/id";
|
|
16
16
|
export * from "@better-auth/core/utils/json";
|
|
17
|
-
export { APIError, HIDE_METADATA, betterAuth, createTelemetry, generateGenericState, generateState, getBaseURL, getCurrentAdapter, getHost,
|
|
17
|
+
export { APIError, HIDE_METADATA, betterAuth, createTelemetry, generateGenericState, generateState, getBaseURL, getCurrentAdapter, getHost, getHostFromSource, getOrigin, getProtocol, getProtocolFromSource, getTelemetryAuthConfig, isDynamicBaseURLConfig, isRequestLike, matchesHostPattern, parseGenericState, parseState, resolveBaseURL, resolveDynamicBaseURL };
|