@better-auth/sso 1.7.0-rc.4 → 1.7.0-rc.6
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
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { APIError } from "better-auth/api";
|
|
2
2
|
import * as z from "zod";
|
|
3
|
-
import "@better-fetch/fetch";
|
|
4
3
|
import samlifyDefault from "samlify";
|
|
5
4
|
import { DBFieldAttribute, FieldAttributeToObject, InferAdditionalFieldsFromPluginOptions, RemoveFieldsWithReturnedFalse } from "better-auth/db";
|
|
6
5
|
import { Awaitable, DBTransactionAdapter, OAuth2Tokens, User } from "better-auth";
|
|
7
|
-
import "
|
|
8
|
-
import "@better-auth/core";
|
|
6
|
+
import * as _$better_call0 from "better-call";
|
|
9
7
|
//#region src/saml/algorithms.d.ts
|
|
10
8
|
declare const SignatureAlgorithm: {
|
|
11
9
|
readonly RSA_SHA1: "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
|
|
@@ -478,7 +476,7 @@ interface SSOOptions {
|
|
|
478
476
|
domain?: string | undefined;
|
|
479
477
|
domainVerified?: string | undefined;
|
|
480
478
|
};
|
|
481
|
-
additionalFields?: { [key in string]: DBFieldAttribute
|
|
479
|
+
additionalFields?: { [key in string]: DBFieldAttribute };
|
|
482
480
|
};
|
|
483
481
|
} | undefined;
|
|
484
482
|
/**
|
|
@@ -682,7 +680,7 @@ interface SSOOptions {
|
|
|
682
680
|
}
|
|
683
681
|
//#endregion
|
|
684
682
|
//#region src/routes/domain-verification.d.ts
|
|
685
|
-
declare const requestDomainVerification: (options: SSOOptions) =>
|
|
683
|
+
declare const requestDomainVerification: (options: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/request-domain-verification", {
|
|
686
684
|
method: "POST";
|
|
687
685
|
body: z.ZodObject<{
|
|
688
686
|
providerId: z.ZodString;
|
|
@@ -704,7 +702,7 @@ declare const requestDomainVerification: (options: SSOOptions) => import("better
|
|
|
704
702
|
};
|
|
705
703
|
};
|
|
706
704
|
};
|
|
707
|
-
use: (
|
|
705
|
+
use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
|
|
708
706
|
session: {
|
|
709
707
|
session: Record<string, any> & {
|
|
710
708
|
id: string;
|
|
@@ -726,11 +724,11 @@ declare const requestDomainVerification: (options: SSOOptions) => import("better
|
|
|
726
724
|
image?: string | null | undefined;
|
|
727
725
|
};
|
|
728
726
|
};
|
|
729
|
-
}
|
|
727
|
+
}>>[];
|
|
730
728
|
}, {
|
|
731
729
|
domainVerificationToken: string;
|
|
732
730
|
}>;
|
|
733
|
-
declare const verifyDomain: (options: SSOOptions) =>
|
|
731
|
+
declare const verifyDomain: (options: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/verify-domain", {
|
|
734
732
|
method: "POST";
|
|
735
733
|
body: z.ZodObject<{
|
|
736
734
|
providerId: z.ZodString;
|
|
@@ -755,7 +753,7 @@ declare const verifyDomain: (options: SSOOptions) => import("better-call").Stric
|
|
|
755
753
|
};
|
|
756
754
|
};
|
|
757
755
|
};
|
|
758
|
-
use: (
|
|
756
|
+
use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
|
|
759
757
|
session: {
|
|
760
758
|
session: Record<string, any> & {
|
|
761
759
|
id: string;
|
|
@@ -777,7 +775,7 @@ declare const verifyDomain: (options: SSOOptions) => import("better-call").Stric
|
|
|
777
775
|
image?: string | null | undefined;
|
|
778
776
|
};
|
|
779
777
|
};
|
|
780
|
-
}
|
|
778
|
+
}>>[];
|
|
781
779
|
}, void>;
|
|
782
780
|
//#endregion
|
|
783
781
|
//#region src/utils.d.ts
|
|
@@ -793,9 +791,9 @@ type ParsedCert = ReturnType<typeof parseCertificate>;
|
|
|
793
791
|
type SanitizedCert = ParsedCert | {
|
|
794
792
|
error: string;
|
|
795
793
|
};
|
|
796
|
-
declare const listSSOProviders: (options?: SSOOptions) =>
|
|
794
|
+
declare const listSSOProviders: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/providers", {
|
|
797
795
|
method: "GET";
|
|
798
|
-
use: (
|
|
796
|
+
use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
|
|
799
797
|
session: {
|
|
800
798
|
session: Record<string, any> & {
|
|
801
799
|
id: string;
|
|
@@ -817,7 +815,7 @@ declare const listSSOProviders: (options?: SSOOptions) => import("better-call").
|
|
|
817
815
|
image?: string | null | undefined;
|
|
818
816
|
};
|
|
819
817
|
};
|
|
820
|
-
}
|
|
818
|
+
}>>[];
|
|
821
819
|
metadata: {
|
|
822
820
|
openapi: {
|
|
823
821
|
operationId: string;
|
|
@@ -864,9 +862,9 @@ declare const listSSOProviders: (options?: SSOOptions) => import("better-call").
|
|
|
864
862
|
spMetadataUrl: string;
|
|
865
863
|
}[];
|
|
866
864
|
}>;
|
|
867
|
-
declare const getSSOProvider: (options?: SSOOptions) =>
|
|
865
|
+
declare const getSSOProvider: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/get-provider", {
|
|
868
866
|
method: "GET";
|
|
869
|
-
use: (
|
|
867
|
+
use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
|
|
870
868
|
session: {
|
|
871
869
|
session: Record<string, any> & {
|
|
872
870
|
id: string;
|
|
@@ -888,7 +886,7 @@ declare const getSSOProvider: (options?: SSOOptions) => import("better-call").St
|
|
|
888
886
|
image?: string | null | undefined;
|
|
889
887
|
};
|
|
890
888
|
};
|
|
891
|
-
}
|
|
889
|
+
}>>[];
|
|
892
890
|
query: z.ZodObject<{
|
|
893
891
|
providerId: z.ZodString;
|
|
894
892
|
}, z.core.$strip>;
|
|
@@ -942,9 +940,9 @@ declare const getSSOProvider: (options?: SSOOptions) => import("better-call").St
|
|
|
942
940
|
} | undefined;
|
|
943
941
|
spMetadataUrl: string;
|
|
944
942
|
}>;
|
|
945
|
-
declare const updateSSOProvider: (options: SSOOptions) =>
|
|
943
|
+
declare const updateSSOProvider: (options: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/update-provider", {
|
|
946
944
|
method: "POST";
|
|
947
|
-
use: (
|
|
945
|
+
use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
|
|
948
946
|
session: {
|
|
949
947
|
session: Record<string, any> & {
|
|
950
948
|
id: string;
|
|
@@ -966,7 +964,7 @@ declare const updateSSOProvider: (options: SSOOptions) => import("better-call").
|
|
|
966
964
|
image?: string | null | undefined;
|
|
967
965
|
};
|
|
968
966
|
};
|
|
969
|
-
}
|
|
967
|
+
}>>[];
|
|
970
968
|
body: z.ZodObject<{
|
|
971
969
|
issuer: z.ZodOptional<z.ZodString>;
|
|
972
970
|
domain: z.ZodOptional<z.ZodString>;
|
|
@@ -1098,9 +1096,9 @@ declare const updateSSOProvider: (options: SSOOptions) => import("better-call").
|
|
|
1098
1096
|
} | undefined;
|
|
1099
1097
|
spMetadataUrl: string;
|
|
1100
1098
|
}>;
|
|
1101
|
-
declare const deleteSSOProvider: (options?: SSOOptions) =>
|
|
1099
|
+
declare const deleteSSOProvider: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/delete-provider", {
|
|
1102
1100
|
method: "POST";
|
|
1103
|
-
use: (
|
|
1101
|
+
use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
|
|
1104
1102
|
session: {
|
|
1105
1103
|
session: Record<string, any> & {
|
|
1106
1104
|
id: string;
|
|
@@ -1122,7 +1120,7 @@ declare const deleteSSOProvider: (options?: SSOOptions) => import("better-call")
|
|
|
1122
1120
|
image?: string | null | undefined;
|
|
1123
1121
|
};
|
|
1124
1122
|
};
|
|
1125
|
-
}
|
|
1123
|
+
}>>[];
|
|
1126
1124
|
body: z.ZodObject<{
|
|
1127
1125
|
providerId: z.ZodString;
|
|
1128
1126
|
}, z.core.$strip>;
|
|
@@ -1149,7 +1147,7 @@ declare const deleteSSOProvider: (options?: SSOOptions) => import("better-call")
|
|
|
1149
1147
|
}>;
|
|
1150
1148
|
//#endregion
|
|
1151
1149
|
//#region src/routes/sso.d.ts
|
|
1152
|
-
declare const spMetadata: (options?: SSOOptions) =>
|
|
1150
|
+
declare const spMetadata: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/saml2/sp/metadata", {
|
|
1153
1151
|
method: "GET";
|
|
1154
1152
|
query: z.ZodObject<{
|
|
1155
1153
|
providerId: z.ZodString;
|
|
@@ -1167,12 +1165,12 @@ declare const spMetadata: (options?: SSOOptions) => import("better-call").Strict
|
|
|
1167
1165
|
};
|
|
1168
1166
|
};
|
|
1169
1167
|
}, Response>;
|
|
1170
|
-
declare const registerSSOProvider: <O extends SSOOptions>(options: O) =>
|
|
1168
|
+
declare const registerSSOProvider: <O extends SSOOptions>(options: O) => _$better_call0.StrictEndpoint<"/sso/register", {
|
|
1171
1169
|
method: "POST";
|
|
1172
1170
|
body: z.ZodObject<{
|
|
1173
1171
|
[x: string]: z.ZodOptional<z.ZodAny>;
|
|
1174
1172
|
}, z.core.$strip>;
|
|
1175
|
-
use: (
|
|
1173
|
+
use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
|
|
1176
1174
|
session: {
|
|
1177
1175
|
session: Record<string, any> & {
|
|
1178
1176
|
id: string;
|
|
@@ -1194,7 +1192,7 @@ declare const registerSSOProvider: <O extends SSOOptions>(options: O) => import(
|
|
|
1194
1192
|
image?: string | null | undefined;
|
|
1195
1193
|
};
|
|
1196
1194
|
};
|
|
1197
|
-
}
|
|
1195
|
+
}>>[];
|
|
1198
1196
|
metadata: {
|
|
1199
1197
|
$Infer: {
|
|
1200
1198
|
body: Record<string, any> & SSOProviderAdditionalFieldsInput<O>;
|
|
@@ -1369,7 +1367,7 @@ declare const registerSSOProvider: <O extends SSOOptions>(options: O) => import(
|
|
|
1369
1367
|
oidcConfig: OIDCConfig | null;
|
|
1370
1368
|
samlConfig: SAMLConfig | null;
|
|
1371
1369
|
} & Omit<InferSSOProvider<O>, "samlConfig" | "oidcConfig">>;
|
|
1372
|
-
declare const signInSSO: (options?: SSOOptions) =>
|
|
1370
|
+
declare const signInSSO: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sign-in/sso", {
|
|
1373
1371
|
method: "POST";
|
|
1374
1372
|
body: z.ZodObject<{
|
|
1375
1373
|
email: z.ZodOptional<z.ZodString>;
|
|
@@ -1491,7 +1489,7 @@ declare const signInSSO: (options?: SSOOptions) => import("better-call").StrictE
|
|
|
1491
1489
|
url: string;
|
|
1492
1490
|
redirect: boolean;
|
|
1493
1491
|
}>;
|
|
1494
|
-
declare const callbackSSO: (options?: SSOOptions) =>
|
|
1492
|
+
declare const callbackSSO: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/callback/:providerId", {
|
|
1495
1493
|
method: "GET";
|
|
1496
1494
|
query: z.ZodObject<{
|
|
1497
1495
|
code: z.ZodOptional<z.ZodString>;
|
|
@@ -1519,7 +1517,7 @@ declare const callbackSSO: (options?: SSOOptions) => import("better-call").Stric
|
|
|
1519
1517
|
* Used when `options.redirectURI` is set — the `providerId` is read from
|
|
1520
1518
|
* the OAuth state instead of the URL path.
|
|
1521
1519
|
*/
|
|
1522
|
-
declare const callbackSSOShared: (options?: SSOOptions) =>
|
|
1520
|
+
declare const callbackSSOShared: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/callback", {
|
|
1523
1521
|
metadata: {
|
|
1524
1522
|
openapi: {
|
|
1525
1523
|
operationId: string;
|
|
@@ -1542,7 +1540,7 @@ declare const callbackSSOShared: (options?: SSOOptions) => import("better-call")
|
|
|
1542
1540
|
}, z.core.$strip>;
|
|
1543
1541
|
allowedMediaTypes: readonly ["application/x-www-form-urlencoded", "application/json"];
|
|
1544
1542
|
}, void>;
|
|
1545
|
-
declare const acsEndpoint: (options?: SSOOptions) =>
|
|
1543
|
+
declare const acsEndpoint: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/saml2/sp/acs/:providerId", {
|
|
1546
1544
|
method: ("GET" | "POST")[];
|
|
1547
1545
|
body: z.ZodOptional<z.ZodObject<{
|
|
1548
1546
|
SAMLResponse: z.ZodString;
|
|
@@ -1572,7 +1570,7 @@ declare const acsEndpoint: (options?: SSOOptions) => import("better-call").Stric
|
|
|
1572
1570
|
scope: "server";
|
|
1573
1571
|
};
|
|
1574
1572
|
}, never>;
|
|
1575
|
-
declare const sloEndpoint: (options?: SSOOptions) =>
|
|
1573
|
+
declare const sloEndpoint: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/saml2/sp/slo/:providerId", {
|
|
1576
1574
|
method: ("GET" | "POST")[];
|
|
1577
1575
|
body: z.ZodOptional<z.ZodObject<{
|
|
1578
1576
|
SAMLRequest: z.ZodOptional<z.ZodString>;
|
|
@@ -1593,12 +1591,12 @@ declare const sloEndpoint: (options?: SSOOptions) => import("better-call").Stric
|
|
|
1593
1591
|
scope: "server";
|
|
1594
1592
|
};
|
|
1595
1593
|
}, void | Response>;
|
|
1596
|
-
declare const initiateSLO: (options?: SSOOptions) =>
|
|
1594
|
+
declare const initiateSLO: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/saml2/logout/:providerId", {
|
|
1597
1595
|
method: "POST";
|
|
1598
1596
|
body: z.ZodObject<{
|
|
1599
1597
|
callbackURL: z.ZodOptional<z.ZodString>;
|
|
1600
1598
|
}, z.core.$strip>;
|
|
1601
|
-
use: (
|
|
1599
|
+
use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
|
|
1602
1600
|
session: {
|
|
1603
1601
|
session: Record<string, any> & {
|
|
1604
1602
|
id: string;
|
|
@@ -1620,7 +1618,7 @@ declare const initiateSLO: (options?: SSOOptions) => import("better-call").Stric
|
|
|
1620
1618
|
image?: string | null | undefined;
|
|
1621
1619
|
};
|
|
1622
1620
|
};
|
|
1623
|
-
}
|
|
1621
|
+
}>>[];
|
|
1624
1622
|
metadata: {
|
|
1625
1623
|
readonly scope: "server";
|
|
1626
1624
|
};
|
|
@@ -1762,29 +1760,7 @@ interface OIDCDiscoveryDocument {
|
|
|
1762
1760
|
/**
|
|
1763
1761
|
* Error codes for OIDC discovery operations.
|
|
1764
1762
|
*/
|
|
1765
|
-
type DiscoveryErrorCode =
|
|
1766
|
-
/** Request to discovery endpoint timed out */
|
|
1767
|
-
"discovery_timeout" |
|
|
1768
|
-
/** Discovery endpoint returned 404 or similar */
|
|
1769
|
-
"discovery_not_found" |
|
|
1770
|
-
/** Discovery endpoint returned invalid JSON */
|
|
1771
|
-
"discovery_invalid_json" |
|
|
1772
|
-
/** OIDC endpoint URL (discovery or per-endpoint: authorization, token, userinfo, jwks) is invalid, malformed, or uses a non-`http(s)` scheme */
|
|
1773
|
-
"discovery_invalid_url" |
|
|
1774
|
-
/** OIDC endpoint URL is not trusted by the trusted origins configuration */
|
|
1775
|
-
"discovery_untrusted_origin" |
|
|
1776
|
-
/** OIDC endpoint URL (discovery or per-endpoint) points to a host that is not publicly routable (loopback, RFC 1918, link-local, cloud metadata FQDN, etc.) */
|
|
1777
|
-
"discovery_private_host" |
|
|
1778
|
-
/** Server-side OIDC endpoint fetch received an HTTP redirect response */
|
|
1779
|
-
"oidc_endpoint_redirect" |
|
|
1780
|
-
/** Discovery document issuer doesn't match configured issuer */
|
|
1781
|
-
"issuer_mismatch" |
|
|
1782
|
-
/** Discovery document is missing required fields */
|
|
1783
|
-
"discovery_incomplete" |
|
|
1784
|
-
/** IdP only advertises token auth methods that Better Auth doesn't currently support */
|
|
1785
|
-
"unsupported_token_auth_method" |
|
|
1786
|
-
/** Catch-all for unexpected errors */
|
|
1787
|
-
"discovery_unexpected_error";
|
|
1763
|
+
type DiscoveryErrorCode = /** Request to discovery endpoint timed out */"discovery_timeout" /** Discovery endpoint returned 404 or similar */ | "discovery_not_found" /** Discovery endpoint returned invalid JSON */ | "discovery_invalid_json" /** OIDC endpoint URL (discovery or per-endpoint: authorization, token, userinfo, jwks) is invalid, malformed, or uses a non-`http(s)` scheme */ | "discovery_invalid_url" /** OIDC endpoint URL is not trusted by the trusted origins configuration */ | "discovery_untrusted_origin" /** OIDC endpoint URL (discovery or per-endpoint) points to a host that is not publicly routable (loopback, RFC 1918, link-local, cloud metadata FQDN, etc.) */ | "discovery_private_host" /** Server-side OIDC endpoint fetch received an HTTP redirect response */ | "oidc_endpoint_redirect" /** Discovery document issuer doesn't match configured issuer */ | "issuer_mismatch" /** Discovery document is missing required fields */ | "discovery_incomplete" /** IdP only advertises token auth methods that Better Auth doesn't currently support */ | "unsupported_token_auth_method" /** Catch-all for unexpected errors */ | "discovery_unexpected_error";
|
|
1788
1764
|
/**
|
|
1789
1765
|
* Custom error class for OIDC discovery failures.
|
|
1790
1766
|
* Can be caught and mapped to APIError at the edge.
|
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-
|
|
2
|
-
export {
|
|
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-CZytzKv6.mjs";
|
|
2
|
+
export { AlgorithmValidationOptions, DEFAULT_CLOCK_SKEW_MS, DEFAULT_MAX_SAML_METADATA_SIZE, DEFAULT_MAX_SAML_RESPONSE_SIZE, DataEncryptionAlgorithm, DeprecatedAlgorithmBehavior, DigestAlgorithm, DiscoverOIDCConfigParams, DiscoveryError, DiscoveryErrorCode, HydratedOIDCConfig, KeyEncryptionAlgorithm, OIDCConfig, OIDCDiscoveryDocument, REQUIRED_DISCOVERY_FIELDS, RequiredDiscoveryField, SAMLConditions, SAMLConfig, SAMLIdentityProviderMetadata, SAMLServiceProviderPolicy, SSOOIDCUserResolutionInput, SSOOptions, SSOPlugin, SSOProvider, SSOProviderMutationGuardContext, SSOProviderMutationGuardInput, SSOProviderReference, SSOProviderUserProfile, SSOSAMLUserResolutionInput, SSOUserResolution, SSOUserResolutionContext, SSOUserResolutionInput, SignatureAlgorithm, 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-CceXYJfW.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
|
};
|
|
@@ -3310,13 +3368,13 @@ const registerSSOProvider = (options) => {
|
|
|
3310
3368
|
if (!member) throw new APIError("BAD_REQUEST", { message: "You are not a member of the organization" });
|
|
3311
3369
|
if (ctx.context.hasPlugin("organization") && !hasOrgAdminRole(member)) throw new APIError("FORBIDDEN", { message: "You must be an organization owner or admin to register SSO providers" });
|
|
3312
3370
|
}
|
|
3313
|
-
if (
|
|
3371
|
+
if (new Set([
|
|
3314
3372
|
...BUILT_IN_ACCOUNT_PROVIDER_IDS,
|
|
3315
3373
|
...Object.keys(ctx.context.options.socialProviders ?? {}),
|
|
3316
3374
|
...ctx.context.socialProviders.map((p) => p.id),
|
|
3317
3375
|
...ctx.context.trustedProviders,
|
|
3318
3376
|
...options?.defaultSSO?.map((p) => p.providerId) ?? []
|
|
3319
|
-
])
|
|
3377
|
+
]).has(body.providerId)) {
|
|
3320
3378
|
ctx.context.logger.warn(`SSO provider registration rejected for reserved providerId: ${body.providerId}`);
|
|
3321
3379
|
throw new APIError("UNPROCESSABLE_ENTITY", { message: "This providerId is reserved and cannot be used for an SSO provider" });
|
|
3322
3380
|
}
|
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.6",
|
|
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
|
-
"tsdown": "0.
|
|
75
|
-
"better-auth": "1.7.0-rc.
|
|
76
|
-
"@better-auth/
|
|
77
|
-
"
|
|
74
|
+
"tsdown": "0.21.10",
|
|
75
|
+
"@better-auth/core": "1.7.0-rc.6",
|
|
76
|
+
"@better-auth/kysely-adapter": "1.7.0-rc.6",
|
|
77
|
+
"better-auth": "1.7.0-rc.6"
|
|
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.6",
|
|
84
|
+
"better-auth": "^1.7.0-rc.6"
|
|
85
85
|
},
|
|
86
86
|
"scripts": {
|
|
87
87
|
"build": "tsdown",
|