better-auth 1.6.17 → 1.6.19
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/routes/email-verification.mjs +19 -6
- package/dist/api/routes/session.mjs +3 -12
- package/dist/client/config.d.mts +86 -0
- package/dist/client/lynx/index.d.mts +20 -105
- package/dist/client/react/index.d.mts +20 -105
- package/dist/client/solid/index.d.mts +19 -99
- package/dist/client/svelte/index.d.mts +20 -105
- package/dist/client/types.d.mts +27 -16
- package/dist/client/vanilla.d.mts +19 -105
- package/dist/client/vue/index.d.mts +39 -135
- package/dist/cookies/index.mjs +2 -12
- package/dist/cookies/session-store.d.mts +0 -17
- package/dist/cookies/session-store.mjs +42 -51
- package/dist/package.mjs +1 -1
- package/dist/plugins/device-authorization/index.d.mts +1 -0
- package/dist/plugins/device-authorization/routes.mjs +5 -3
- package/dist/plugins/index.d.mts +2 -2
- package/dist/plugins/last-login-method/client.d.mts +10 -0
- package/dist/plugins/last-login-method/client.mjs +4 -1
- package/dist/plugins/oauth-popup/index.mjs +3 -2
- package/dist/plugins/open-api/generator.d.mts +67 -58
- package/dist/plugins/open-api/generator.mjs +234 -94
- package/dist/plugins/open-api/index.d.mts +2 -2
- package/dist/plugins/organization/adapter.mjs +3 -2
- package/dist/plugins/organization/routes/crud-access-control.mjs +1 -1
- package/dist/plugins/two-factor/backup-codes/index.mjs +4 -3
- package/dist/state.mjs +2 -1
- package/dist/test-utils/test-instance.d.mts +3 -12055
- package/package.json +10 -10
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
import { symmetricDecodeJWT, symmetricEncodeJWT } from "../crypto/jwt.mjs";
|
|
2
2
|
import { parseCookies } from "./cookie-utils.mjs";
|
|
3
3
|
import { safeJSONParse } from "@better-auth/core/utils/json";
|
|
4
|
+
import { serializeCookie } from "better-call";
|
|
4
5
|
import * as z from "zod";
|
|
5
6
|
//#region src/cookies/session-store.ts
|
|
6
|
-
const ALLOWED_COOKIE_SIZE = 4096;
|
|
7
|
-
const ESTIMATED_EMPTY_COOKIE_SIZE = 200;
|
|
8
|
-
const CHUNK_SIZE = ALLOWED_COOKIE_SIZE - ESTIMATED_EMPTY_COOKIE_SIZE;
|
|
9
7
|
/**
|
|
10
|
-
*
|
|
8
|
+
* Per-cookie byte ceiling.
|
|
9
|
+
* Safari's ~4093 floor is the lowest among browsers.
|
|
10
|
+
* Kept a little under it for attributes added after sizing.
|
|
11
|
+
*
|
|
12
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6265#section-6.1
|
|
13
|
+
* @see https://github.com/dotnet/aspnetcore/blob/aa5493528640932601bb82ef3295e4d8ca7e11c5/src/Shared/ChunkingCookieManager/ChunkingCookieManager.cs#L40
|
|
14
|
+
*/
|
|
15
|
+
const MAX_COOKIE_SIZE = 4050;
|
|
16
|
+
/**
|
|
17
|
+
* Max chunks per cookie.
|
|
18
|
+
* A larger value does not belong in a cookie.
|
|
11
19
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
const MAX_COOKIE_CHUNKS = 100;
|
|
21
|
+
/**
|
|
22
|
+
* Largest value that keeps the serialized cookie within {@link MAX_COOKIE_SIZE},
|
|
23
|
+
* measured with the real `serializeCookie` writer so it stays in sync with the
|
|
24
|
+
* wire. Non-positive when the name and attributes alone overflow.
|
|
25
|
+
*/
|
|
26
|
+
function getMaxCookieValueSize(name, options) {
|
|
27
|
+
return MAX_COOKIE_SIZE - serializeCookie(name, "", { ...options }).length;
|
|
17
28
|
}
|
|
18
29
|
/**
|
|
19
30
|
* Read all existing chunks from cookies
|
|
@@ -25,27 +36,24 @@ function readExistingChunks(cookieName, ctx) {
|
|
|
25
36
|
return chunks;
|
|
26
37
|
}
|
|
27
38
|
/**
|
|
28
|
-
* Get the full session data by joining all chunks
|
|
29
|
-
*/
|
|
30
|
-
function joinChunks(chunks) {
|
|
31
|
-
return Object.keys(chunks).sort((a, b) => {
|
|
32
|
-
return getChunkIndex(a) - getChunkIndex(b);
|
|
33
|
-
}).map((key) => chunks[key]).join("");
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
39
|
* Split a cookie value into chunks if needed
|
|
37
40
|
*/
|
|
38
41
|
function chunkCookie(storeName, cookie, chunks, logger) {
|
|
39
|
-
const
|
|
40
|
-
|
|
42
|
+
const chunkSize = getMaxCookieValueSize(`${cookie.name}.${MAX_COOKIE_CHUNKS - 1}`, cookie.attributes);
|
|
43
|
+
const chunkCount = chunkSize > 0 ? Math.ceil(cookie.value.length / chunkSize) : Infinity;
|
|
44
|
+
if (chunkCount <= 1) {
|
|
41
45
|
chunks[cookie.name] = cookie.value;
|
|
42
46
|
return [cookie];
|
|
43
47
|
}
|
|
48
|
+
if (chunkCount > MAX_COOKIE_CHUNKS) {
|
|
49
|
+
logger.warn(`${storeName} cookie is too large to store even after chunking, so the cache was skipped. Reduce the cached data or use a database session.`);
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
44
52
|
const cookies = [];
|
|
45
53
|
for (let i = 0; i < chunkCount; i++) {
|
|
46
54
|
const name = `${cookie.name}.${i}`;
|
|
47
|
-
const start = i *
|
|
48
|
-
const value = cookie.value.substring(start, start +
|
|
55
|
+
const start = i * chunkSize;
|
|
56
|
+
const value = cookie.value.substring(start, start + chunkSize);
|
|
49
57
|
cookies.push({
|
|
50
58
|
...cookie,
|
|
51
59
|
name,
|
|
@@ -54,11 +62,10 @@ function chunkCookie(storeName, cookie, chunks, logger) {
|
|
|
54
62
|
chunks[name] = value;
|
|
55
63
|
}
|
|
56
64
|
logger.debug(`CHUNKING_${storeName.toUpperCase()}_COOKIE`, {
|
|
57
|
-
message: `${storeName} cookie exceeds
|
|
58
|
-
emptyCookieSize: ESTIMATED_EMPTY_COOKIE_SIZE,
|
|
65
|
+
message: `${storeName} cookie exceeds the ${MAX_COOKIE_SIZE} byte limit and was split into ${chunkCount} chunks.`,
|
|
59
66
|
valueSize: cookie.value.length,
|
|
60
67
|
chunkCount,
|
|
61
|
-
|
|
68
|
+
chunkSizes: cookies.map((c) => c.value.length)
|
|
62
69
|
});
|
|
63
70
|
return cookies;
|
|
64
71
|
}
|
|
@@ -78,26 +85,22 @@ function getCleanCookies(chunks, cookieOptions) {
|
|
|
78
85
|
return cleanedChunks;
|
|
79
86
|
}
|
|
80
87
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
88
|
+
* Store that splits a cookie into numbered chunks when its serialized form
|
|
89
|
+
* would exceed the per-cookie byte limit, expiring stale chunks as needed.
|
|
83
90
|
*
|
|
84
|
-
* Based on next-auth's SessionStore implementation.
|
|
85
91
|
* @see https://github.com/nextauthjs/next-auth/blob/27b2519b84b8eb9cf053775dea29d577d2aa0098/packages/next-auth/src/core/lib/cookie.ts
|
|
86
92
|
*/
|
|
87
93
|
const storeFactory = (storeName) => (cookieName, cookieOptions, ctx) => {
|
|
88
94
|
const chunks = readExistingChunks(cookieName, ctx);
|
|
89
95
|
const logger = ctx.context.logger;
|
|
96
|
+
const expireExistingChunks = () => {
|
|
97
|
+
const expired = getCleanCookies(chunks, cookieOptions);
|
|
98
|
+
for (const name in chunks) delete chunks[name];
|
|
99
|
+
return expired;
|
|
100
|
+
};
|
|
90
101
|
return {
|
|
91
|
-
getValue() {
|
|
92
|
-
return joinChunks(chunks);
|
|
93
|
-
},
|
|
94
|
-
hasChunks() {
|
|
95
|
-
return Object.keys(chunks).length > 0;
|
|
96
|
-
},
|
|
97
102
|
chunk(value, options) {
|
|
98
|
-
const
|
|
99
|
-
for (const name in chunks) delete chunks[name];
|
|
100
|
-
const cookies = cleanedChunks;
|
|
103
|
+
const cookies = expireExistingChunks();
|
|
101
104
|
const chunked = chunkCookie(storeName, {
|
|
102
105
|
name: cookieName,
|
|
103
106
|
value,
|
|
@@ -110,9 +113,7 @@ const storeFactory = (storeName) => (cookieName, cookieOptions, ctx) => {
|
|
|
110
113
|
return Object.values(cookies);
|
|
111
114
|
},
|
|
112
115
|
clean() {
|
|
113
|
-
|
|
114
|
-
for (const name in chunks) delete chunks[name];
|
|
115
|
-
return Object.values(cleanedChunks);
|
|
116
|
+
return Object.values(expireExistingChunks());
|
|
116
117
|
},
|
|
117
118
|
setCookies(cookies) {
|
|
118
119
|
for (const cookie of cookies) ctx.setCookie(cookie.name, cookie.value, cookie.attributes);
|
|
@@ -148,18 +149,8 @@ async function setAccountCookie(c, accountData) {
|
|
|
148
149
|
...accountDataCookie.attributes
|
|
149
150
|
};
|
|
150
151
|
const data = await symmetricEncodeJWT(accountData, c.context.secretConfig, "better-auth-account", options.maxAge);
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const cookies = accountStore.chunk(data, options);
|
|
154
|
-
accountStore.setCookies(cookies);
|
|
155
|
-
} else {
|
|
156
|
-
const accountStore = createAccountStore(accountDataCookie.name, options, c);
|
|
157
|
-
if (accountStore.hasChunks()) {
|
|
158
|
-
const cleanCookies = accountStore.clean();
|
|
159
|
-
accountStore.setCookies(cleanCookies);
|
|
160
|
-
}
|
|
161
|
-
c.setCookie(accountDataCookie.name, data, options);
|
|
162
|
-
}
|
|
152
|
+
const accountStore = createAccountStore(accountDataCookie.name, options, c);
|
|
153
|
+
accountStore.setCookies(accountStore.chunk(data, options));
|
|
163
154
|
}
|
|
164
155
|
async function getAccountCookie(c) {
|
|
165
156
|
const accountCookie = getChunkedCookie(c, c.context.authCookies.accountData.name);
|
package/dist/package.mjs
CHANGED
|
@@ -104,6 +104,7 @@ declare const deviceAuthorization: (options?: Partial<DeviceAuthorizationOptions
|
|
|
104
104
|
method: "POST";
|
|
105
105
|
body: z.ZodObject<{
|
|
106
106
|
client_id: z.ZodString;
|
|
107
|
+
user_id: z.ZodOptional<z.ZodString>;
|
|
107
108
|
scope: z.ZodOptional<z.ZodString>;
|
|
108
109
|
}, z.core.$strip>;
|
|
109
110
|
error: z.ZodObject<{
|
|
@@ -9,6 +9,7 @@ import * as z from "zod";
|
|
|
9
9
|
const defaultCharset = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
10
10
|
const deviceCodeBodySchema = z.object({
|
|
11
11
|
client_id: z.string().meta({ description: "The client ID of the application" }),
|
|
12
|
+
user_id: z.string().meta({ description: "The user ID to which the device code should be pre-bound." }).optional(),
|
|
12
13
|
scope: z.string().meta({ description: "Space-separated list of scopes" }).optional()
|
|
13
14
|
});
|
|
14
15
|
const deviceCodeErrorSchema = z.object({
|
|
@@ -99,7 +100,7 @@ Follow [rfc8628#section-3.2](https://datatracker.ietf.org/doc/html/rfc8628#secti
|
|
|
99
100
|
data: {
|
|
100
101
|
deviceCode,
|
|
101
102
|
userCode,
|
|
102
|
-
userId: null,
|
|
103
|
+
userId: ctx.body.user_id || null,
|
|
103
104
|
expiresAt,
|
|
104
105
|
status: "pending",
|
|
105
106
|
pollingInterval: ms(opts.interval),
|
|
@@ -341,7 +342,7 @@ const deviceVerify = createAuthEndpoint("/device", {
|
|
|
341
342
|
});
|
|
342
343
|
const session = await getSessionFromCtx(ctx);
|
|
343
344
|
if (session?.user?.id && !deviceCodeRecord.userId && deviceCodeRecord.status === "pending") {
|
|
344
|
-
if (await ctx.context.adapter.
|
|
345
|
+
if (await ctx.context.adapter.incrementOne({
|
|
345
346
|
model: "deviceCode",
|
|
346
347
|
where: [
|
|
347
348
|
{
|
|
@@ -358,7 +359,8 @@ const deviceVerify = createAuthEndpoint("/device", {
|
|
|
358
359
|
value: null
|
|
359
360
|
}
|
|
360
361
|
],
|
|
361
|
-
|
|
362
|
+
increment: {},
|
|
363
|
+
set: { userId: session.user.id }
|
|
362
364
|
})) deviceCodeRecord.userId = session.user.id;
|
|
363
365
|
}
|
|
364
366
|
return ctx.json({
|
package/dist/plugins/index.d.mts
CHANGED
|
@@ -48,7 +48,7 @@ import { OAUTH_POPUP_COMPLETE_SCRIPT, OAUTH_POPUP_SCRIPT_CSP_HASH, oauthPopup }
|
|
|
48
48
|
import { OAuthProxyOptions, oAuthProxy } from "./oauth-proxy/index.mjs";
|
|
49
49
|
import { OneTapOptions, oneTap } from "./one-tap/index.mjs";
|
|
50
50
|
import { OneTimeTokenOptions, oneTimeToken } from "./one-time-token/index.mjs";
|
|
51
|
-
import { FieldSchema, OpenAPIModelSchema, Path, generator } from "./open-api/generator.mjs";
|
|
51
|
+
import { FieldSchema, OpenAPIModelSchema, OpenAPIParameter, OpenAPISchema, Path, generator } from "./open-api/generator.mjs";
|
|
52
52
|
import { OpenAPIOptions, openAPI } from "./open-api/index.mjs";
|
|
53
53
|
import { PhoneNumberOptions, UserWithPhoneNumber } from "./phone-number/types.mjs";
|
|
54
54
|
import { phoneNumber } from "./phone-number/index.mjs";
|
|
@@ -66,4 +66,4 @@ import { USERNAME_ERROR_CODES } from "./username/error-codes.mjs";
|
|
|
66
66
|
import { UsernameOptions, username } from "./username/index.mjs";
|
|
67
67
|
import { hasPermission } from "./organization/has-permission.mjs";
|
|
68
68
|
import { DefaultOrganizationPlugin, DynamicAccessControlEndpoints, OrganizationCreator, OrganizationEndpoints, OrganizationPlugin, TeamEndpoints, organization, parseRoles } from "./organization/organization.mjs";
|
|
69
|
-
export { AccessControl, AdminOptions, AnonymousOptions, AnonymousSession, ArrayElement, Auth0Options, AuthorizationQuery, AuthorizeResponse, BackupCodeOptions, BaseCaptchaOptions, BaseOAuthProviderOptions, BearerOptions, CaptchaFoxOptions, CaptchaOptions, Client, CloudflareTurnstileOptions, CodeVerificationValue, CustomSessionPluginOptions, DefaultOrganizationPlugin, DeviceAuthorizationOptions, DynamicAccessControlEndpoints, MULTI_SESSION_ERROR_CODES as ERROR_CODES, EmailOTPOptions, ExactRoleStatements, FieldSchema, GenericOAuthConfig, GenericOAuthOptions, GoogleRecaptchaOptions, GumroadOptions, HCaptchaOptions, HIDE_METADATA, HaveIBeenPwnedOptions, HubSpotOptions, InferAdminRolesFromOption, InferInvitation, InferMember, InferOptionSchema, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPluginContext, InferPluginErrorCodes, InferPluginIDs, InferTeam, Invitation, InvitationInput, InvitationStatus, JWKOptions, JWSAlgorithms, Jwk, JwtOptions, KeycloakOptions, LastLoginMethodOptions, LineOptions, LoginResult, MagicLinkOptions, Member, MemberInput, MicrosoftEntraIdOptions, MultiSessionConfig, OAUTH_POPUP_COMPLETE_SCRIPT, OAUTH_POPUP_DATA_ELEMENT_ID, OAUTH_POPUP_ERROR_CODES, OAUTH_POPUP_MESSAGE_TYPE, OAUTH_POPUP_SCRIPT_CSP_HASH, OAuthAccessToken, OAuthPopupData, OAuthPopupMessage, OAuthProxyOptions, OIDCMetadata, OIDCOptions, OTPOptions, OktaOptions, OneTapOptions, OneTimeTokenOptions, OpenAPIModelSchema, OpenAPIOptions, Organization, OrganizationCreator, OrganizationEndpoints, OrganizationInput, OrganizationOptions, OrganizationPlugin, OrganizationRole, OrganizationSchema, POPUP_MARKER_COOKIE, Path, PatreonOptions, PhoneNumberOptions, Provider, Role, RoleAuthorizeRequest, RoleInput, RoleStatements, SIWEPluginOptions, SessionWithImpersonatedBy, SlackOptions, Statements, SubArray, Subset, TOTPOptions, TWO_FACTOR_ERROR_CODES, Team, TeamEndpoints, TeamInput, TeamMember, TeamMemberInput, TestCookie, TestHelpers, TestUtilsOptions, TimeString, TokenBody, TwoFactorOptions, TwoFactorProvider, TwoFactorTable, USERNAME_ERROR_CODES, UserWithAnonymous, UserWithPhoneNumber, UserWithRole, UserWithTwoFactor, UsernameOptions, admin, anonymous, auth0, backupCode2fa, bearer, captcha, createAccessControl, createJwk, customSession, defaultRolesSchema, deviceAuthorization, deviceAuthorizationOptionsSchema, emailOTP, encodeBackupCodes, generateBackupCodes, generateExportedKeyPair, generator, genericOAuth, getBackupCodes, getClient, getJwtToken, getMCPProtectedResourceMetadata, getMCPProviderMetadata, getMetadata, getOrgAdapter, gumroad, hasPermission, haveIBeenPwned, hubspot, invitationSchema, invitationStatus, jwt, keycloak, lastLoginMethod, line, magicLink, mcp, memberSchema, microsoftEntraId, ms, multiSession, oAuthDiscoveryMetadata, oAuthProtectedResourceMetadata, oAuthProxy, oauthPopup, oidcProvider, okta, oneTap, oneTimeToken, openAPI, organization, organizationRoleSchema, organizationSchema, otp2fa, parseRoles, patreon, phoneNumber, role, roleSchema, sec, signJWT, siwe, slack, teamMemberSchema, teamSchema, testUtils, toExpJWT, totp2fa, twoFactor, twoFactorClient, username, verifyBackupCode, verifyJWT, withMcpAuth };
|
|
69
|
+
export { AccessControl, AdminOptions, AnonymousOptions, AnonymousSession, ArrayElement, Auth0Options, AuthorizationQuery, AuthorizeResponse, BackupCodeOptions, BaseCaptchaOptions, BaseOAuthProviderOptions, BearerOptions, CaptchaFoxOptions, CaptchaOptions, Client, CloudflareTurnstileOptions, CodeVerificationValue, CustomSessionPluginOptions, DefaultOrganizationPlugin, DeviceAuthorizationOptions, DynamicAccessControlEndpoints, MULTI_SESSION_ERROR_CODES as ERROR_CODES, EmailOTPOptions, ExactRoleStatements, FieldSchema, GenericOAuthConfig, GenericOAuthOptions, GoogleRecaptchaOptions, GumroadOptions, HCaptchaOptions, HIDE_METADATA, HaveIBeenPwnedOptions, HubSpotOptions, InferAdminRolesFromOption, InferInvitation, InferMember, InferOptionSchema, InferOrganization, InferOrganizationRolesFromOption, InferOrganizationZodRolesFromOption, InferPluginContext, InferPluginErrorCodes, InferPluginIDs, InferTeam, Invitation, InvitationInput, InvitationStatus, JWKOptions, JWSAlgorithms, Jwk, JwtOptions, KeycloakOptions, LastLoginMethodOptions, LineOptions, LoginResult, MagicLinkOptions, Member, MemberInput, MicrosoftEntraIdOptions, MultiSessionConfig, OAUTH_POPUP_COMPLETE_SCRIPT, OAUTH_POPUP_DATA_ELEMENT_ID, OAUTH_POPUP_ERROR_CODES, OAUTH_POPUP_MESSAGE_TYPE, OAUTH_POPUP_SCRIPT_CSP_HASH, OAuthAccessToken, OAuthPopupData, OAuthPopupMessage, OAuthProxyOptions, OIDCMetadata, OIDCOptions, OTPOptions, OktaOptions, OneTapOptions, OneTimeTokenOptions, OpenAPIModelSchema, OpenAPIOptions, OpenAPIParameter, OpenAPISchema, Organization, OrganizationCreator, OrganizationEndpoints, OrganizationInput, OrganizationOptions, OrganizationPlugin, OrganizationRole, OrganizationSchema, POPUP_MARKER_COOKIE, Path, PatreonOptions, PhoneNumberOptions, Provider, Role, RoleAuthorizeRequest, RoleInput, RoleStatements, SIWEPluginOptions, SessionWithImpersonatedBy, SlackOptions, Statements, SubArray, Subset, TOTPOptions, TWO_FACTOR_ERROR_CODES, Team, TeamEndpoints, TeamInput, TeamMember, TeamMemberInput, TestCookie, TestHelpers, TestUtilsOptions, TimeString, TokenBody, TwoFactorOptions, TwoFactorProvider, TwoFactorTable, USERNAME_ERROR_CODES, UserWithAnonymous, UserWithPhoneNumber, UserWithRole, UserWithTwoFactor, UsernameOptions, admin, anonymous, auth0, backupCode2fa, bearer, captcha, createAccessControl, createJwk, customSession, defaultRolesSchema, deviceAuthorization, deviceAuthorizationOptionsSchema, emailOTP, encodeBackupCodes, generateBackupCodes, generateExportedKeyPair, generator, genericOAuth, getBackupCodes, getClient, getJwtToken, getMCPProtectedResourceMetadata, getMCPProviderMetadata, getMetadata, getOrgAdapter, gumroad, hasPermission, haveIBeenPwned, hubspot, invitationSchema, invitationStatus, jwt, keycloak, lastLoginMethod, line, magicLink, mcp, memberSchema, microsoftEntraId, ms, multiSession, oAuthDiscoveryMetadata, oAuthProtectedResourceMetadata, oAuthProxy, oauthPopup, oidcProvider, okta, oneTap, oneTimeToken, openAPI, organization, organizationRoleSchema, organizationSchema, otp2fa, parseRoles, patreon, phoneNumber, role, roleSchema, sec, signJWT, siwe, slack, teamMemberSchema, teamSchema, testUtils, toExpJWT, totp2fa, twoFactor, twoFactorClient, username, verifyBackupCode, verifyJWT, withMcpAuth };
|
|
@@ -8,6 +8,16 @@ interface LastLoginMethodClientConfig {
|
|
|
8
8
|
* @default "better-auth.last_used_login_method"
|
|
9
9
|
*/
|
|
10
10
|
cookieName?: string | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Domain for the cookie. Required when using cross-subdomain cookies
|
|
13
|
+
* so the client can properly clear the cookie set by the server.
|
|
14
|
+
*
|
|
15
|
+
* Should match the `domain` value in your server's
|
|
16
|
+
* `crossSubDomainCookies` configuration.
|
|
17
|
+
*
|
|
18
|
+
* @example ".example.com"
|
|
19
|
+
*/
|
|
20
|
+
domain?: string | undefined;
|
|
11
21
|
}
|
|
12
22
|
/**
|
|
13
23
|
* Client-side plugin to retrieve the last used login method
|
|
@@ -19,7 +19,10 @@ const lastLoginMethodClient = (config = {}) => {
|
|
|
19
19
|
return getCookieValue(cookieName);
|
|
20
20
|
},
|
|
21
21
|
clearLastUsedLoginMethod: () => {
|
|
22
|
-
if (typeof document !== "undefined")
|
|
22
|
+
if (typeof document !== "undefined") {
|
|
23
|
+
const domainPart = config.domain ? ` domain=${config.domain};` : "";
|
|
24
|
+
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;${domainPart}`;
|
|
25
|
+
}
|
|
23
26
|
},
|
|
24
27
|
isLastUsedLoginMethod: (method) => {
|
|
25
28
|
return getCookieValue(cookieName) === method;
|
|
@@ -3,7 +3,7 @@ import { generateRandomString } from "../../crypto/random.mjs";
|
|
|
3
3
|
import { expireCookie } from "../../cookies/index.mjs";
|
|
4
4
|
import { getAwaitableValue } from "../../context/helpers.mjs";
|
|
5
5
|
import { setOAuthState } from "../../api/state/oauth.mjs";
|
|
6
|
-
import { generateGenericState } from "../../state.mjs";
|
|
6
|
+
import { INTERNAL_STATE_KEYS, generateGenericState } from "../../state.mjs";
|
|
7
7
|
import { HIDE_METADATA } from "../../utils/hide-metadata.mjs";
|
|
8
8
|
import { PACKAGE_VERSION } from "../../version.mjs";
|
|
9
9
|
import { OAUTH_POPUP_DATA_ELEMENT_ID, OAUTH_POPUP_MESSAGE_TYPE, POPUP_MARKER_COOKIE } from "./constants.mjs";
|
|
@@ -132,8 +132,9 @@ const oauthPopupStart = createAuthEndpoint("/oauth-popup/start", {
|
|
|
132
132
|
let url;
|
|
133
133
|
try {
|
|
134
134
|
const codeVerifier = generateRandomString(128);
|
|
135
|
+
const parsedAdditionalData = c.query.additionalData ? safeJSONParse(c.query.additionalData) ?? {} : {};
|
|
135
136
|
const stateData = {
|
|
136
|
-
...
|
|
137
|
+
...Object.fromEntries(Object.entries(parsedAdditionalData).filter(([key]) => !INTERNAL_STATE_KEYS.has(key))),
|
|
137
138
|
callbackURL,
|
|
138
139
|
codeVerifier,
|
|
139
140
|
errorURL: c.query.errorCallbackURL,
|
|
@@ -4,66 +4,75 @@ import { OpenAPIParameter, OpenAPISchemaType } from "better-call";
|
|
|
4
4
|
|
|
5
5
|
//#region src/plugins/open-api/generator.d.ts
|
|
6
6
|
interface Path {
|
|
7
|
-
get?:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
bearerAuth: string[];
|
|
13
|
-
}];
|
|
14
|
-
parameters?: OpenAPIParameter[];
|
|
15
|
-
responses?: { [key in string]: {
|
|
16
|
-
description?: string;
|
|
17
|
-
content: {
|
|
18
|
-
"application/json": {
|
|
19
|
-
schema: {
|
|
20
|
-
type?: OpenAPISchemaType;
|
|
21
|
-
properties?: Record<string, any>;
|
|
22
|
-
required?: string[];
|
|
23
|
-
$ref?: string;
|
|
24
|
-
};
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
} };
|
|
28
|
-
} | undefined;
|
|
29
|
-
post?: {
|
|
30
|
-
tags?: string[];
|
|
31
|
-
operationId?: string;
|
|
32
|
-
description?: string;
|
|
33
|
-
security?: [{
|
|
34
|
-
bearerAuth: string[];
|
|
35
|
-
}];
|
|
36
|
-
parameters?: OpenAPIParameter[];
|
|
37
|
-
requestBody?: {
|
|
38
|
-
content: {
|
|
39
|
-
"application/json": {
|
|
40
|
-
schema: {
|
|
41
|
-
type?: OpenAPISchemaType;
|
|
42
|
-
properties?: Record<string, any>;
|
|
43
|
-
required?: string[];
|
|
44
|
-
$ref?: string;
|
|
45
|
-
};
|
|
46
|
-
};
|
|
47
|
-
};
|
|
48
|
-
};
|
|
49
|
-
responses?: { [key in string]: {
|
|
50
|
-
description?: string;
|
|
51
|
-
content: {
|
|
52
|
-
"application/json": {
|
|
53
|
-
schema: {
|
|
54
|
-
type?: OpenAPISchemaType;
|
|
55
|
-
properties?: Record<string, any>;
|
|
56
|
-
required?: string[];
|
|
57
|
-
$ref?: string;
|
|
58
|
-
};
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
} };
|
|
62
|
-
} | undefined;
|
|
7
|
+
get?: OpenAPIOperation | undefined;
|
|
8
|
+
post?: OpenAPIOperation | undefined;
|
|
9
|
+
put?: OpenAPIOperation | undefined;
|
|
10
|
+
patch?: OpenAPIOperation | undefined;
|
|
11
|
+
delete?: OpenAPIOperation | undefined;
|
|
63
12
|
}
|
|
13
|
+
type OpenAPISchemaPrimitiveType = OpenAPISchemaType | "null";
|
|
14
|
+
type OpenAPISchema = {
|
|
15
|
+
type?: OpenAPISchemaPrimitiveType | OpenAPISchemaPrimitiveType[];
|
|
16
|
+
properties?: Record<string, OpenAPISchema>;
|
|
17
|
+
required?: string[];
|
|
18
|
+
$ref?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
default?: unknown;
|
|
21
|
+
readOnly?: boolean;
|
|
22
|
+
format?: string;
|
|
23
|
+
deprecated?: boolean;
|
|
24
|
+
enum?: unknown[];
|
|
25
|
+
items?: OpenAPISchema;
|
|
26
|
+
minLength?: number;
|
|
27
|
+
maxLength?: number;
|
|
28
|
+
minimum?: number;
|
|
29
|
+
maximum?: number;
|
|
30
|
+
additionalProperties?: boolean | OpenAPISchema;
|
|
31
|
+
propertyNames?: OpenAPISchema;
|
|
32
|
+
allOf?: OpenAPISchema[];
|
|
33
|
+
anyOf?: OpenAPISchema[];
|
|
34
|
+
oneOf?: OpenAPISchema[];
|
|
35
|
+
const?: unknown;
|
|
36
|
+
example?: unknown;
|
|
37
|
+
};
|
|
38
|
+
type OpenAPIParameter$1 = Omit<OpenAPIParameter, "schema"> & {
|
|
39
|
+
schema?: OpenAPISchema;
|
|
40
|
+
};
|
|
41
|
+
type OpenAPIMediaTypeObject = {
|
|
42
|
+
schema?: OpenAPISchema;
|
|
43
|
+
};
|
|
44
|
+
type OpenAPIResponseContent = {
|
|
45
|
+
"application/json"?: OpenAPIMediaTypeObject;
|
|
46
|
+
"text/plain"?: OpenAPIMediaTypeObject;
|
|
47
|
+
"text/html"?: OpenAPIMediaTypeObject;
|
|
48
|
+
[contentType: string]: OpenAPIMediaTypeObject | undefined;
|
|
49
|
+
};
|
|
50
|
+
type OpenAPIResponse = {
|
|
51
|
+
description?: string;
|
|
52
|
+
content?: OpenAPIResponseContent;
|
|
53
|
+
};
|
|
54
|
+
type OpenAPIRequestBody = {
|
|
55
|
+
required?: boolean;
|
|
56
|
+
content: {
|
|
57
|
+
"application/json": {
|
|
58
|
+
schema: OpenAPISchema;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
type OpenAPIOperation = {
|
|
63
|
+
tags?: string[];
|
|
64
|
+
operationId?: string;
|
|
65
|
+
description?: string;
|
|
66
|
+
security?: [{
|
|
67
|
+
bearerAuth: string[];
|
|
68
|
+
}];
|
|
69
|
+
parameters?: OpenAPIParameter$1[];
|
|
70
|
+
requestBody?: OpenAPIRequestBody;
|
|
71
|
+
responses?: Record<string, OpenAPIResponse>;
|
|
72
|
+
};
|
|
64
73
|
type FieldSchema = {
|
|
65
74
|
type: DBFieldType;
|
|
66
|
-
default?:
|
|
75
|
+
default?: DBFieldAttributeConfig["defaultValue"] | undefined;
|
|
67
76
|
readOnly?: boolean | undefined;
|
|
68
77
|
format?: string;
|
|
69
78
|
};
|
|
@@ -111,4 +120,4 @@ declare function generator(ctx: AuthContext, options: BetterAuthOptions): Promis
|
|
|
111
120
|
paths: Record<string, Path>;
|
|
112
121
|
}>;
|
|
113
122
|
//#endregion
|
|
114
|
-
export { FieldSchema, OpenAPIModelSchema, Path, generator };
|
|
123
|
+
export { FieldSchema, OpenAPIModelSchema, OpenAPIParameter$1 as OpenAPIParameter, OpenAPISchema, Path, generator };
|