@better-auth/sso 1.7.0-rc.4 → 1.7.0-rc.5
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/client.d.mts
CHANGED
package/dist/client.mjs
CHANGED
|
@@ -704,7 +704,7 @@ declare const requestDomainVerification: (options: SSOOptions) => import("better
|
|
|
704
704
|
};
|
|
705
705
|
};
|
|
706
706
|
};
|
|
707
|
-
use: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
707
|
+
use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
708
708
|
session: {
|
|
709
709
|
session: Record<string, any> & {
|
|
710
710
|
id: string;
|
|
@@ -726,7 +726,7 @@ declare const requestDomainVerification: (options: SSOOptions) => import("better
|
|
|
726
726
|
image?: string | null | undefined;
|
|
727
727
|
};
|
|
728
728
|
};
|
|
729
|
-
}
|
|
729
|
+
}>>[];
|
|
730
730
|
}, {
|
|
731
731
|
domainVerificationToken: string;
|
|
732
732
|
}>;
|
|
@@ -755,7 +755,7 @@ declare const verifyDomain: (options: SSOOptions) => import("better-call").Stric
|
|
|
755
755
|
};
|
|
756
756
|
};
|
|
757
757
|
};
|
|
758
|
-
use: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
758
|
+
use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
759
759
|
session: {
|
|
760
760
|
session: Record<string, any> & {
|
|
761
761
|
id: string;
|
|
@@ -777,7 +777,7 @@ declare const verifyDomain: (options: SSOOptions) => import("better-call").Stric
|
|
|
777
777
|
image?: string | null | undefined;
|
|
778
778
|
};
|
|
779
779
|
};
|
|
780
|
-
}
|
|
780
|
+
}>>[];
|
|
781
781
|
}, void>;
|
|
782
782
|
//#endregion
|
|
783
783
|
//#region src/utils.d.ts
|
|
@@ -795,7 +795,7 @@ type SanitizedCert = ParsedCert | {
|
|
|
795
795
|
};
|
|
796
796
|
declare const listSSOProviders: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sso/providers", {
|
|
797
797
|
method: "GET";
|
|
798
|
-
use: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
798
|
+
use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
799
799
|
session: {
|
|
800
800
|
session: Record<string, any> & {
|
|
801
801
|
id: string;
|
|
@@ -817,7 +817,7 @@ declare const listSSOProviders: (options?: SSOOptions) => import("better-call").
|
|
|
817
817
|
image?: string | null | undefined;
|
|
818
818
|
};
|
|
819
819
|
};
|
|
820
|
-
}
|
|
820
|
+
}>>[];
|
|
821
821
|
metadata: {
|
|
822
822
|
openapi: {
|
|
823
823
|
operationId: string;
|
|
@@ -866,7 +866,7 @@ declare const listSSOProviders: (options?: SSOOptions) => import("better-call").
|
|
|
866
866
|
}>;
|
|
867
867
|
declare const getSSOProvider: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sso/get-provider", {
|
|
868
868
|
method: "GET";
|
|
869
|
-
use: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
869
|
+
use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
870
870
|
session: {
|
|
871
871
|
session: Record<string, any> & {
|
|
872
872
|
id: string;
|
|
@@ -888,7 +888,7 @@ declare const getSSOProvider: (options?: SSOOptions) => import("better-call").St
|
|
|
888
888
|
image?: string | null | undefined;
|
|
889
889
|
};
|
|
890
890
|
};
|
|
891
|
-
}
|
|
891
|
+
}>>[];
|
|
892
892
|
query: z.ZodObject<{
|
|
893
893
|
providerId: z.ZodString;
|
|
894
894
|
}, z.core.$strip>;
|
|
@@ -944,7 +944,7 @@ declare const getSSOProvider: (options?: SSOOptions) => import("better-call").St
|
|
|
944
944
|
}>;
|
|
945
945
|
declare const updateSSOProvider: (options: SSOOptions) => import("better-call").StrictEndpoint<"/sso/update-provider", {
|
|
946
946
|
method: "POST";
|
|
947
|
-
use: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
947
|
+
use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
948
948
|
session: {
|
|
949
949
|
session: Record<string, any> & {
|
|
950
950
|
id: string;
|
|
@@ -966,7 +966,7 @@ declare const updateSSOProvider: (options: SSOOptions) => import("better-call").
|
|
|
966
966
|
image?: string | null | undefined;
|
|
967
967
|
};
|
|
968
968
|
};
|
|
969
|
-
}
|
|
969
|
+
}>>[];
|
|
970
970
|
body: z.ZodObject<{
|
|
971
971
|
issuer: z.ZodOptional<z.ZodString>;
|
|
972
972
|
domain: z.ZodOptional<z.ZodString>;
|
|
@@ -1100,7 +1100,7 @@ declare const updateSSOProvider: (options: SSOOptions) => import("better-call").
|
|
|
1100
1100
|
}>;
|
|
1101
1101
|
declare const deleteSSOProvider: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sso/delete-provider", {
|
|
1102
1102
|
method: "POST";
|
|
1103
|
-
use: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
1103
|
+
use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
1104
1104
|
session: {
|
|
1105
1105
|
session: Record<string, any> & {
|
|
1106
1106
|
id: string;
|
|
@@ -1122,7 +1122,7 @@ declare const deleteSSOProvider: (options?: SSOOptions) => import("better-call")
|
|
|
1122
1122
|
image?: string | null | undefined;
|
|
1123
1123
|
};
|
|
1124
1124
|
};
|
|
1125
|
-
}
|
|
1125
|
+
}>>[];
|
|
1126
1126
|
body: z.ZodObject<{
|
|
1127
1127
|
providerId: z.ZodString;
|
|
1128
1128
|
}, z.core.$strip>;
|
|
@@ -1172,7 +1172,7 @@ declare const registerSSOProvider: <O extends SSOOptions>(options: O) => import(
|
|
|
1172
1172
|
body: z.ZodObject<{
|
|
1173
1173
|
[x: string]: z.ZodOptional<z.ZodAny>;
|
|
1174
1174
|
}, z.core.$strip>;
|
|
1175
|
-
use: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
1175
|
+
use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
1176
1176
|
session: {
|
|
1177
1177
|
session: Record<string, any> & {
|
|
1178
1178
|
id: string;
|
|
@@ -1194,7 +1194,7 @@ declare const registerSSOProvider: <O extends SSOOptions>(options: O) => import(
|
|
|
1194
1194
|
image?: string | null | undefined;
|
|
1195
1195
|
};
|
|
1196
1196
|
};
|
|
1197
|
-
}
|
|
1197
|
+
}>>[];
|
|
1198
1198
|
metadata: {
|
|
1199
1199
|
$Infer: {
|
|
1200
1200
|
body: Record<string, any> & SSOProviderAdditionalFieldsInput<O>;
|
|
@@ -1598,7 +1598,7 @@ declare const initiateSLO: (options?: SSOOptions) => import("better-call").Stric
|
|
|
1598
1598
|
body: z.ZodObject<{
|
|
1599
1599
|
callbackURL: z.ZodOptional<z.ZodString>;
|
|
1600
1600
|
}, z.core.$strip>;
|
|
1601
|
-
use: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
1601
|
+
use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
1602
1602
|
session: {
|
|
1603
1603
|
session: Record<string, any> & {
|
|
1604
1604
|
id: string;
|
|
@@ -1620,7 +1620,7 @@ declare const initiateSLO: (options?: SSOOptions) => import("better-call").Stric
|
|
|
1620
1620
|
image?: string | null | undefined;
|
|
1621
1621
|
};
|
|
1622
1622
|
};
|
|
1623
|
-
}
|
|
1623
|
+
}>>[];
|
|
1624
1624
|
metadata: {
|
|
1625
1625
|
readonly scope: "server";
|
|
1626
1626
|
};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as SAMLIdentityProviderMetadata, B as SSOUserResolutionContext, C as deriveSAMLIdentityProviderEntityID, D as DEFAULT_MAX_SAML_RESPONSE_SIZE, E as DEFAULT_MAX_SAML_METADATA_SIZE, F as SSOProviderMutationGuardInput, G as DigestAlgorithm, H as AlgorithmValidationOptions, I as SSOProviderReference, K as KeyEncryptionAlgorithm, L as SSOProviderUserProfile, M as SSOOptions, N as SSOProvider, O as OIDCConfig, P as SSOProviderMutationGuardContext, R as SSOSAMLUserResolutionInput, S as SAMLServiceProviderPolicy, T as DEFAULT_CLOCK_SKEW_MS, U as DataEncryptionAlgorithm, V as SSOUserResolutionInput, W as DeprecatedAlgorithmBehavior, _ as REQUIRED_DISCOVERY_FIELDS, a as fetchDiscoveryDocument, b as TimestampValidationOptions, c as normalizeUrl, d as validateDiscoveryUrl, f as DiscoverOIDCConfigParams, g as OIDCDiscoveryDocument, h as HydratedOIDCConfig, i as discoverOIDCConfig, j as SSOOIDCUserResolutionInput, k as SAMLConfig, l as selectTokenEndpointAuthMethod, m as DiscoveryErrorCode, n as sso, o as needsRuntimeDiscovery, p as DiscoveryError, q as SignatureAlgorithm, r as computeDiscoveryUrl, s as normalizeDiscoveryUrls, t as SSOPlugin, u as validateDiscoveryDocument, v as RequiredDiscoveryField, w as deriveSAMLServiceProviderPolicy, x as validateSAMLTimestamp, y as SAMLConditions, z as SSOUserResolution } from "./index-
|
|
1
|
+
import { A as SAMLIdentityProviderMetadata, B as SSOUserResolutionContext, C as deriveSAMLIdentityProviderEntityID, D as DEFAULT_MAX_SAML_RESPONSE_SIZE, E as DEFAULT_MAX_SAML_METADATA_SIZE, F as SSOProviderMutationGuardInput, G as DigestAlgorithm, H as AlgorithmValidationOptions, I as SSOProviderReference, K as KeyEncryptionAlgorithm, L as SSOProviderUserProfile, M as SSOOptions, N as SSOProvider, O as OIDCConfig, P as SSOProviderMutationGuardContext, R as SSOSAMLUserResolutionInput, S as SAMLServiceProviderPolicy, T as DEFAULT_CLOCK_SKEW_MS, U as DataEncryptionAlgorithm, V as SSOUserResolutionInput, W as DeprecatedAlgorithmBehavior, _ as REQUIRED_DISCOVERY_FIELDS, a as fetchDiscoveryDocument, b as TimestampValidationOptions, c as normalizeUrl, d as validateDiscoveryUrl, f as DiscoverOIDCConfigParams, g as OIDCDiscoveryDocument, h as HydratedOIDCConfig, i as discoverOIDCConfig, j as SSOOIDCUserResolutionInput, k as SAMLConfig, l as selectTokenEndpointAuthMethod, m as DiscoveryErrorCode, n as sso, o as needsRuntimeDiscovery, p as DiscoveryError, q as SignatureAlgorithm, r as computeDiscoveryUrl, s as normalizeDiscoveryUrls, t as SSOPlugin, u as validateDiscoveryDocument, v as RequiredDiscoveryField, w as deriveSAMLServiceProviderPolicy, x as validateSAMLTimestamp, y as SAMLConditions, z as SSOUserResolution } from "./index-SHmV18t8.mjs";
|
|
2
2
|
export { type AlgorithmValidationOptions, DEFAULT_CLOCK_SKEW_MS, DEFAULT_MAX_SAML_METADATA_SIZE, DEFAULT_MAX_SAML_RESPONSE_SIZE, DataEncryptionAlgorithm, type DeprecatedAlgorithmBehavior, DigestAlgorithm, type DiscoverOIDCConfigParams, DiscoveryError, type DiscoveryErrorCode, type HydratedOIDCConfig, KeyEncryptionAlgorithm, type OIDCConfig, type OIDCDiscoveryDocument, REQUIRED_DISCOVERY_FIELDS, type RequiredDiscoveryField, type SAMLConditions, type SAMLConfig, type SAMLIdentityProviderMetadata, type SAMLServiceProviderPolicy, type SSOOIDCUserResolutionInput, type SSOOptions, SSOPlugin, type SSOProvider, type SSOProviderMutationGuardContext, type SSOProviderMutationGuardInput, type SSOProviderReference, type SSOProviderUserProfile, type SSOSAMLUserResolutionInput, type SSOUserResolution, type SSOUserResolutionContext, type SSOUserResolutionInput, SignatureAlgorithm, type TimestampValidationOptions, computeDiscoveryUrl, deriveSAMLIdentityProviderEntityID, deriveSAMLServiceProviderPolicy, discoverOIDCConfig, fetchDiscoveryDocument, needsRuntimeDiscovery, normalizeDiscoveryUrls, normalizeUrl, selectTokenEndpointAuthMethod, sso, validateDiscoveryDocument, validateDiscoveryUrl, validateSAMLTimestamp };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as PACKAGE_VERSION } from "./version-
|
|
1
|
+
import { t as PACKAGE_VERSION } from "./version-CwxXc1Y6.mjs";
|
|
2
2
|
import { APIError, addOAuthServerContext, createAuthEndpoint, createAuthMiddleware, getSessionFromCtx, sessionMiddleware } from "better-auth/api";
|
|
3
3
|
import { XMLParser, XMLValidator } from "fast-xml-parser";
|
|
4
4
|
import { X509Certificate } from "node:crypto";
|
|
@@ -151,98 +151,146 @@ function maskClientId(clientId) {
|
|
|
151
151
|
}
|
|
152
152
|
//#endregion
|
|
153
153
|
//#region src/linking/org-assignment.ts
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if (
|
|
162
|
-
|
|
154
|
+
const VERIFIED_PROVIDER_PAGE_SIZE = 100;
|
|
155
|
+
function getEmailDomain(email) {
|
|
156
|
+
const parts = email.trim().toLowerCase().split("@");
|
|
157
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) return null;
|
|
158
|
+
const domain = parts[1];
|
|
159
|
+
if (domain.includes("/") || domain.includes("\\") || domain.includes(":")) return null;
|
|
160
|
+
const normalizedDomains = parseProviderDomains(domain);
|
|
161
|
+
if (!normalizedDomains || normalizedDomains.length !== 1) return null;
|
|
162
|
+
return normalizedDomains[0] ?? null;
|
|
163
|
+
}
|
|
164
|
+
async function findVerifiedDomainProviders(ctx, domain) {
|
|
165
|
+
const matchingProviders = [];
|
|
166
|
+
let offset = 0;
|
|
167
|
+
while (true) {
|
|
168
|
+
const page = await ctx.context.adapter.findMany({
|
|
169
|
+
model: "ssoProvider",
|
|
170
|
+
where: [{
|
|
171
|
+
field: "domainVerified",
|
|
172
|
+
value: true
|
|
173
|
+
}],
|
|
174
|
+
limit: VERIFIED_PROVIDER_PAGE_SIZE,
|
|
175
|
+
offset,
|
|
176
|
+
sortBy: {
|
|
177
|
+
field: "providerId",
|
|
178
|
+
direction: "asc"
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
matchingProviders.push(...page.filter((provider) => domainMatches(domain, provider.domain)));
|
|
182
|
+
if (page.length < VERIFIED_PROVIDER_PAGE_SIZE) return matchingProviders;
|
|
183
|
+
offset += page.length;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async function assignOrganization(ctx, options) {
|
|
187
|
+
if (options.provisioningOptions?.disabled) return "provisioning-disabled";
|
|
188
|
+
if (!ctx.context.hasPlugin("organization")) return "ineligible-source";
|
|
189
|
+
let user;
|
|
190
|
+
let provider;
|
|
191
|
+
let organizationId;
|
|
192
|
+
let userInfo;
|
|
193
|
+
let token;
|
|
194
|
+
if (options.reason === "provider-bound") {
|
|
195
|
+
if (!options.provider.organizationId) return "no-target";
|
|
196
|
+
user = options.user;
|
|
197
|
+
provider = options.provider;
|
|
198
|
+
organizationId = options.provider.organizationId;
|
|
199
|
+
userInfo = options.profile.rawAttributes || {};
|
|
200
|
+
token = options.token;
|
|
201
|
+
} else {
|
|
202
|
+
if (!options.domainVerification?.enabled) return "provisioning-disabled";
|
|
203
|
+
const canonicalUser = await ctx.context.internalAdapter.findUserById(options.user.id);
|
|
204
|
+
if (!canonicalUser) {
|
|
205
|
+
ctx.context.logger.error("Unable to assign SSO organization membership because the canonical user was not found", { userId: options.user.id });
|
|
206
|
+
return "ineligible-source";
|
|
207
|
+
}
|
|
208
|
+
if (!canonicalUser.emailVerified) return "unverified-identity";
|
|
209
|
+
const domain = getEmailDomain(canonicalUser.email);
|
|
210
|
+
if (!domain) return "unverified-identity";
|
|
211
|
+
const matchingProviders = (await findVerifiedDomainProviders(ctx, domain)).filter((matchingProvider) => Boolean(matchingProvider.organizationId));
|
|
212
|
+
if (new Set(matchingProviders.map((matchingProvider) => matchingProvider.organizationId)).size > 1) {
|
|
213
|
+
ctx.context.logger.warn("Skipped SSO organization provisioning because a verified domain maps to multiple organizations", {
|
|
214
|
+
domain,
|
|
215
|
+
userId: canonicalUser.id
|
|
216
|
+
});
|
|
217
|
+
return "ambiguous-target";
|
|
218
|
+
}
|
|
219
|
+
if (matchingProviders.length === 0) return "no-target";
|
|
220
|
+
matchingProviders.sort((left, right) => left.providerId.localeCompare(right.providerId));
|
|
221
|
+
const selectedProvider = matchingProviders[0];
|
|
222
|
+
if (!selectedProvider) return "no-target";
|
|
223
|
+
user = canonicalUser;
|
|
224
|
+
provider = selectedProvider;
|
|
225
|
+
organizationId = selectedProvider.organizationId;
|
|
226
|
+
userInfo = {};
|
|
227
|
+
token = void 0;
|
|
228
|
+
}
|
|
163
229
|
if (await ctx.context.adapter.findOne({
|
|
164
230
|
model: "member",
|
|
165
231
|
where: [{
|
|
166
232
|
field: "organizationId",
|
|
167
|
-
value:
|
|
233
|
+
value: organizationId
|
|
168
234
|
}, {
|
|
169
235
|
field: "userId",
|
|
170
236
|
value: user.id
|
|
171
237
|
}]
|
|
172
|
-
})) return;
|
|
173
|
-
|
|
238
|
+
})) return "already-member";
|
|
239
|
+
if (await ctx.context.adapter.findOne({
|
|
240
|
+
model: "invitation",
|
|
241
|
+
where: [
|
|
242
|
+
{
|
|
243
|
+
field: "organizationId",
|
|
244
|
+
value: organizationId
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
field: "email",
|
|
248
|
+
value: user.email.toLowerCase()
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
field: "status",
|
|
252
|
+
value: "pending"
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
field: "expiresAt",
|
|
256
|
+
value: /* @__PURE__ */ new Date(),
|
|
257
|
+
operator: "gt"
|
|
258
|
+
}
|
|
259
|
+
]
|
|
260
|
+
})) return "invitation-pending";
|
|
261
|
+
const role = options.provisioningOptions?.getRole ? await options.provisioningOptions.getRole({
|
|
174
262
|
user,
|
|
175
|
-
userInfo
|
|
263
|
+
userInfo,
|
|
176
264
|
token,
|
|
177
265
|
provider
|
|
178
|
-
}) : provisioningOptions?.defaultRole || "member";
|
|
266
|
+
}) : options.provisioningOptions?.defaultRole || "member";
|
|
179
267
|
await ctx.context.adapter.create({
|
|
180
268
|
model: "member",
|
|
181
269
|
data: {
|
|
182
|
-
organizationId
|
|
270
|
+
organizationId,
|
|
183
271
|
userId: user.id,
|
|
184
272
|
role,
|
|
185
273
|
createdAt: /* @__PURE__ */ new Date()
|
|
186
274
|
}
|
|
187
275
|
});
|
|
276
|
+
return "assigned";
|
|
188
277
|
}
|
|
189
278
|
/**
|
|
190
|
-
* Assigns a user to
|
|
191
|
-
* Looks up SSO providers that match the user's email domain and assigns
|
|
192
|
-
* the user to the associated organization.
|
|
193
|
-
*
|
|
194
|
-
* This enables domain-based org assignment for non-SSO sign-in methods
|
|
195
|
-
* (e.g., Google OAuth with @acme.com email gets added to Acme's org).
|
|
279
|
+
* Assigns a user to the organization explicitly bound to an SSO provider.
|
|
196
280
|
*/
|
|
197
|
-
async function
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const domain = user.email.split("@")[1];
|
|
202
|
-
if (!domain) return;
|
|
203
|
-
const whereClause = [{
|
|
204
|
-
field: "domain",
|
|
205
|
-
value: domain
|
|
206
|
-
}];
|
|
207
|
-
if (domainVerification?.enabled) whereClause.push({
|
|
208
|
-
field: "domainVerified",
|
|
209
|
-
value: true
|
|
210
|
-
});
|
|
211
|
-
let ssoProvider = await ctx.context.adapter.findOne({
|
|
212
|
-
model: "ssoProvider",
|
|
213
|
-
where: whereClause
|
|
281
|
+
async function assignOrganizationFromProvider(ctx, options) {
|
|
282
|
+
await assignOrganization(ctx, {
|
|
283
|
+
reason: "provider-bound",
|
|
284
|
+
...options
|
|
214
285
|
});
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
if (await ctx.context.adapter.findOne({
|
|
224
|
-
model: "member",
|
|
225
|
-
where: [{
|
|
226
|
-
field: "organizationId",
|
|
227
|
-
value: ssoProvider.organizationId
|
|
228
|
-
}, {
|
|
229
|
-
field: "userId",
|
|
230
|
-
value: user.id
|
|
231
|
-
}]
|
|
232
|
-
})) return;
|
|
233
|
-
const role = provisioningOptions?.getRole ? await provisioningOptions.getRole({
|
|
234
|
-
user,
|
|
235
|
-
userInfo: {},
|
|
236
|
-
provider: ssoProvider
|
|
237
|
-
}) : provisioningOptions?.defaultRole || "member";
|
|
238
|
-
await ctx.context.adapter.create({
|
|
239
|
-
model: "member",
|
|
240
|
-
data: {
|
|
241
|
-
organizationId: ssoProvider.organizationId,
|
|
242
|
-
userId: user.id,
|
|
243
|
-
role,
|
|
244
|
-
createdAt: /* @__PURE__ */ new Date()
|
|
245
|
-
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Assigns a verified user to the organization for their verified email domain.
|
|
289
|
+
*/
|
|
290
|
+
async function assignOrganizationByDomain(ctx, options) {
|
|
291
|
+
await assignOrganization(ctx, {
|
|
292
|
+
reason: "verified-domain",
|
|
293
|
+
...options
|
|
246
294
|
});
|
|
247
295
|
}
|
|
248
296
|
//#endregion
|
|
@@ -2452,6 +2500,23 @@ const deleteSSOProvider = (options) => {
|
|
|
2452
2500
|
const DNS_LABEL_MAX_LENGTH = 63;
|
|
2453
2501
|
const DEFAULT_TOKEN_PREFIX = "better-auth-token";
|
|
2454
2502
|
const domainVerificationBodySchema = z.object({ providerId: z.string() });
|
|
2503
|
+
async function completeDomainVerification(adapter, provider) {
|
|
2504
|
+
if (!await adapter.incrementOne({
|
|
2505
|
+
model: "ssoProvider",
|
|
2506
|
+
where: [{
|
|
2507
|
+
field: "id",
|
|
2508
|
+
value: provider.id
|
|
2509
|
+
}, {
|
|
2510
|
+
field: "domain",
|
|
2511
|
+
value: provider.domain
|
|
2512
|
+
}],
|
|
2513
|
+
increment: {},
|
|
2514
|
+
set: { domainVerified: true }
|
|
2515
|
+
})) throw new APIError("CONFLICT", {
|
|
2516
|
+
code: "SSO_PROVIDER_CHANGED",
|
|
2517
|
+
message: "SSO provider changed while domain verification was in progress. Reload the provider and try again"
|
|
2518
|
+
});
|
|
2519
|
+
}
|
|
2455
2520
|
function getVerificationIdentifier(options, providerId) {
|
|
2456
2521
|
return `_${options.domainVerification?.tokenPrefix || DEFAULT_TOKEN_PREFIX}-${providerId}`;
|
|
2457
2522
|
}
|
|
@@ -2501,7 +2566,7 @@ const verifyDomain = (options) => {
|
|
|
2501
2566
|
description: "Verify the provider domain ownership via DNS records",
|
|
2502
2567
|
responses: {
|
|
2503
2568
|
"404": { description: "Provider not found" },
|
|
2504
|
-
"409": { description: "Domain has already been verified or
|
|
2569
|
+
"409": { description: "Domain has already been verified, or the provider changed while verification was in progress" },
|
|
2505
2570
|
"502": { description: "Unable to verify domain ownership due to upstream validator error" },
|
|
2506
2571
|
"204": { description: "Domain ownership was verified" }
|
|
2507
2572
|
}
|
|
@@ -2556,14 +2621,7 @@ const verifyDomain = (options) => {
|
|
|
2556
2621
|
code: "DOMAIN_VERIFICATION_FAILED"
|
|
2557
2622
|
});
|
|
2558
2623
|
}
|
|
2559
|
-
await ctx.context.adapter
|
|
2560
|
-
model: "ssoProvider",
|
|
2561
|
-
where: [{
|
|
2562
|
-
field: "providerId",
|
|
2563
|
-
value: provider.providerId
|
|
2564
|
-
}],
|
|
2565
|
-
update: { domainVerified: true }
|
|
2566
|
-
});
|
|
2624
|
+
await completeDomainVerification(ctx.context.adapter, provider);
|
|
2567
2625
|
ctx.setStatus(204);
|
|
2568
2626
|
});
|
|
2569
2627
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/sso",
|
|
3
|
-
"version": "1.7.0-rc.
|
|
3
|
+
"version": "1.7.0-rc.5",
|
|
4
4
|
"description": "SSO plugin for Better Auth",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -66,22 +66,22 @@
|
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@types/body-parser": "^1.19.6",
|
|
68
68
|
"@types/express": "^5.0.6",
|
|
69
|
-
"better-call": "1.
|
|
69
|
+
"better-call": "1.4.0",
|
|
70
70
|
"body-parser": "^2.3.0",
|
|
71
71
|
"express": "^5.2.1",
|
|
72
72
|
"kysely": "^0.28.17 || ^0.29.0",
|
|
73
73
|
"oauth2-mock-server": "^9.0.0",
|
|
74
74
|
"tsdown": "0.22.7",
|
|
75
|
-
"better-auth": "1.7.0-rc.
|
|
76
|
-
"@better-auth/
|
|
77
|
-
"
|
|
75
|
+
"@better-auth/core": "1.7.0-rc.5",
|
|
76
|
+
"@better-auth/kysely-adapter": "1.7.0-rc.5",
|
|
77
|
+
"better-auth": "1.7.0-rc.5"
|
|
78
78
|
},
|
|
79
79
|
"peerDependencies": {
|
|
80
80
|
"@better-auth/utils": "0.4.2",
|
|
81
81
|
"@better-fetch/fetch": "1.3.1",
|
|
82
|
-
"better-call": "1.
|
|
83
|
-
"@better-auth/core": "^1.7.0-rc.
|
|
84
|
-
"better-auth": "^1.7.0-rc.
|
|
82
|
+
"better-call": "1.4.0",
|
|
83
|
+
"@better-auth/core": "^1.7.0-rc.5",
|
|
84
|
+
"better-auth": "^1.7.0-rc.5"
|
|
85
85
|
},
|
|
86
86
|
"scripts": {
|
|
87
87
|
"build": "tsdown",
|