@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
@@ -1,5 +1,6 @@
1
- import { t as SSOPlugin } from "./index-nfENSAuB.mjs";
1
+ import { t as SSOPlugin } from "./index-CZytzKv6.mjs";
2
2
  import { DBFieldAttribute } from "better-auth/db";
3
+
3
4
  //#region src/client.d.ts
4
5
  interface SSOClientOptions {
5
6
  domainVerification?: {
package/dist/client.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as PACKAGE_VERSION } from "./version-Do0kTnv7.mjs";
1
+ import { t as PACKAGE_VERSION } from "./version-CceXYJfW.mjs";
2
2
  //#region src/client.ts
3
3
  const ssoClient = (options) => {
4
4
  return {
@@ -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 "@better-auth/core/db/adapter";
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) => import("better-call").StrictEndpoint<"/sso/request-domain-verification", {
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: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
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) => import("better-call").StrictEndpoint<"/sso/verify-domain", {
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: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
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) => import("better-call").StrictEndpoint<"/sso/providers", {
794
+ declare const listSSOProviders: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/providers", {
797
795
  method: "GET";
798
- use: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
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) => import("better-call").StrictEndpoint<"/sso/get-provider", {
865
+ declare const getSSOProvider: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/get-provider", {
868
866
  method: "GET";
869
- use: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
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) => import("better-call").StrictEndpoint<"/sso/update-provider", {
943
+ declare const updateSSOProvider: (options: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/update-provider", {
946
944
  method: "POST";
947
- use: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
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) => import("better-call").StrictEndpoint<"/sso/delete-provider", {
1099
+ declare const deleteSSOProvider: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/delete-provider", {
1102
1100
  method: "POST";
1103
- use: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
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) => import("better-call").StrictEndpoint<"/sso/saml2/sp/metadata", {
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) => import("better-call").StrictEndpoint<"/sso/register", {
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: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
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) => import("better-call").StrictEndpoint<"/sign-in/sso", {
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) => import("better-call").StrictEndpoint<"/sso/callback/:providerId", {
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) => import("better-call").StrictEndpoint<"/sso/callback", {
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) => import("better-call").StrictEndpoint<"/sso/saml2/sp/acs/:providerId", {
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) => import("better-call").StrictEndpoint<"/sso/saml2/sp/slo/:providerId", {
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) => import("better-call").StrictEndpoint<"/sso/saml2/logout/:providerId", {
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: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
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-nfENSAuB.mjs";
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 };
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-Do0kTnv7.mjs";
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
- * Assigns a user to an organization based on the SSO provider's organizationId.
156
- * Used in SSO flows (OIDC, SAML) where the provider is already linked to an org.
157
- */
158
- async function assignOrganizationFromProvider(ctx, options) {
159
- const { user, profile, provider, token, provisioningOptions } = options;
160
- if (!provider.organizationId) return;
161
- if (provisioningOptions?.disabled) return;
162
- if (!ctx.context.hasPlugin("organization")) return;
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: provider.organizationId
233
+ value: organizationId
168
234
  }, {
169
235
  field: "userId",
170
236
  value: user.id
171
237
  }]
172
- })) return;
173
- const role = provisioningOptions?.getRole ? await provisioningOptions.getRole({
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: profile.rawAttributes || {},
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: provider.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 an organization based on their email domain.
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 assignOrganizationByDomain(ctx, options) {
198
- const { user, provisioningOptions, domainVerification } = options;
199
- if (provisioningOptions?.disabled) return;
200
- if (!ctx.context.hasPlugin("organization")) return;
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
- if (!ssoProvider) ssoProvider = (await ctx.context.adapter.findMany({
216
- model: "ssoProvider",
217
- where: domainVerification?.enabled ? [{
218
- field: "domainVerified",
219
- value: true
220
- }] : []
221
- })).find((p) => domainMatches(domain, p.domain)) ?? null;
222
- if (!ssoProvider || !ssoProvider.organizationId) return;
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 no pending verification exists" },
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.update({
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 ((/* @__PURE__ */ new Set([
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
- ])).has(body.providerId)) {
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
  }
@@ -1,5 +1,5 @@
1
1
  //#endregion
2
2
  //#region src/version.ts
3
- const PACKAGE_VERSION = "1.7.0-rc.4";
3
+ const PACKAGE_VERSION = "1.7.0-rc.6";
4
4
  //#endregion
5
5
  export { PACKAGE_VERSION as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth/sso",
3
- "version": "1.7.0-rc.4",
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.3.7",
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.22.7",
75
- "better-auth": "1.7.0-rc.4",
76
- "@better-auth/core": "1.7.0-rc.4",
77
- "@better-auth/kysely-adapter": "1.7.0-rc.4"
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.3.7",
83
- "@better-auth/core": "^1.7.0-rc.4",
84
- "better-auth": "^1.7.0-rc.4"
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",