@better-auth/sso 1.8.0-beta.2 → 1.8.0-beta.3

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,6 +1,5 @@
1
- import { t as SSOPlugin } from "./index-qb-OvHIE.mjs";
1
+ import { t as SSOPlugin } from "./index-BvKzNnKP.mjs";
2
2
  import { DBFieldAttribute } from "better-auth/db";
3
-
4
3
  //#region src/client.d.ts
5
4
  interface SSOClientOptions {
6
5
  domainVerification?: {
@@ -14,7 +13,7 @@ interface SSOClientOptions {
14
13
  };
15
14
  } | undefined;
16
15
  }
17
- declare const ssoClient: <CO extends SSOClientOptions>(options?: CO | undefined) => {
16
+ export declare const ssoClient: <CO extends SSOClientOptions>(options?: CO | undefined) => {
18
17
  id: "sso-client";
19
18
  version: string;
20
19
  $InferServerPlugin: SSOPlugin<{
@@ -31,4 +30,4 @@ declare const ssoClient: <CO extends SSOClientOptions>(options?: CO | undefined)
31
30
  };
32
31
  };
33
32
  //#endregion
34
- export { ssoClient };
33
+ export {};
package/dist/client.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as PACKAGE_VERSION } from "./version-Dv2lqEg3.mjs";
1
+ import { t as PACKAGE_VERSION } from "./version-HRaJjPrD.mjs";
2
2
  //#region src/client.ts
3
3
  const ssoClient = (options) => {
4
4
  return {
@@ -1,9 +1,11 @@
1
1
  import { APIError } from "better-auth/api";
2
2
  import * as z from "zod";
3
+ import "@better-fetch/fetch";
3
4
  import samlifyDefault from "samlify";
4
5
  import { DBFieldAttribute, FieldAttributeToObject, InferAdditionalFieldsFromPluginOptions, RemoveFieldsWithReturnedFalse } from "better-auth/db";
5
6
  import { Awaitable, DBTransactionAdapter, OAuth2Tokens, User } from "better-auth";
6
- import * as _$better_call0 from "better-call";
7
+ import "@better-auth/core/db/adapter";
8
+ import "@better-auth/core";
7
9
  //#region src/saml/algorithms.d.ts
8
10
  declare const SignatureAlgorithm: {
9
11
  readonly RSA_SHA1: "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
@@ -479,7 +481,7 @@ interface SSOOptions {
479
481
  domain?: string | undefined;
480
482
  domainVerified?: string | undefined;
481
483
  };
482
- additionalFields?: { [key in string]: DBFieldAttribute };
484
+ additionalFields?: { [key in string]: DBFieldAttribute; };
483
485
  };
484
486
  } | undefined;
485
487
  /**
@@ -683,7 +685,7 @@ interface SSOOptions {
683
685
  }
684
686
  //#endregion
685
687
  //#region src/routes/domain-verification.d.ts
686
- declare const requestDomainVerification: (options: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/request-domain-verification", {
688
+ declare const requestDomainVerification: (options: SSOOptions) => import("better-call").StrictEndpoint<"/sso/request-domain-verification", {
687
689
  method: "POST";
688
690
  body: z.ZodObject<{
689
691
  providerId: z.ZodString;
@@ -705,7 +707,7 @@ declare const requestDomainVerification: (options: SSOOptions) => _$better_call0
705
707
  };
706
708
  };
707
709
  };
708
- use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
710
+ use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
709
711
  session: {
710
712
  session: Record<string, any> & {
711
713
  id: string;
@@ -731,7 +733,7 @@ declare const requestDomainVerification: (options: SSOOptions) => _$better_call0
731
733
  }, {
732
734
  domainVerificationToken: string;
733
735
  }>;
734
- declare const verifyDomain: (options: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/verify-domain", {
736
+ declare const verifyDomain: (options: SSOOptions) => import("better-call").StrictEndpoint<"/sso/verify-domain", {
735
737
  method: "POST";
736
738
  body: z.ZodObject<{
737
739
  providerId: z.ZodString;
@@ -756,7 +758,7 @@ declare const verifyDomain: (options: SSOOptions) => _$better_call0.StrictEndpoi
756
758
  };
757
759
  };
758
760
  };
759
- use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
761
+ use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
760
762
  session: {
761
763
  session: Record<string, any> & {
762
764
  id: string;
@@ -794,9 +796,9 @@ type ParsedCert = ReturnType<typeof parseCertificate>;
794
796
  type SanitizedCert = ParsedCert | {
795
797
  error: string;
796
798
  };
797
- declare const listSSOProviders: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/providers", {
799
+ declare const listSSOProviders: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sso/providers", {
798
800
  method: "GET";
799
- use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
801
+ use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
800
802
  session: {
801
803
  session: Record<string, any> & {
802
804
  id: string;
@@ -865,9 +867,9 @@ declare const listSSOProviders: (options?: SSOOptions) => _$better_call0.StrictE
865
867
  spMetadataUrl: string;
866
868
  }[];
867
869
  }>;
868
- declare const getSSOProvider: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/get-provider", {
870
+ declare const getSSOProvider: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sso/get-provider", {
869
871
  method: "GET";
870
- use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
872
+ use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
871
873
  session: {
872
874
  session: Record<string, any> & {
873
875
  id: string;
@@ -943,9 +945,9 @@ declare const getSSOProvider: (options?: SSOOptions) => _$better_call0.StrictEnd
943
945
  } | undefined;
944
946
  spMetadataUrl: string;
945
947
  }>;
946
- declare const updateSSOProvider: (options: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/update-provider", {
948
+ declare const updateSSOProvider: (options: SSOOptions) => import("better-call").StrictEndpoint<"/sso/update-provider", {
947
949
  method: "POST";
948
- use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
950
+ use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
949
951
  session: {
950
952
  session: Record<string, any> & {
951
953
  id: string;
@@ -1099,9 +1101,9 @@ declare const updateSSOProvider: (options: SSOOptions) => _$better_call0.StrictE
1099
1101
  } | undefined;
1100
1102
  spMetadataUrl: string;
1101
1103
  }>;
1102
- declare const deleteSSOProvider: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/delete-provider", {
1104
+ declare const deleteSSOProvider: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sso/delete-provider", {
1103
1105
  method: "POST";
1104
- use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
1106
+ use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
1105
1107
  session: {
1106
1108
  session: Record<string, any> & {
1107
1109
  id: string;
@@ -1150,7 +1152,7 @@ declare const deleteSSOProvider: (options?: SSOOptions) => _$better_call0.Strict
1150
1152
  }>;
1151
1153
  //#endregion
1152
1154
  //#region src/routes/sso.d.ts
1153
- declare const spMetadata: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/saml2/sp/metadata", {
1155
+ declare const spMetadata: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sso/saml2/sp/metadata", {
1154
1156
  method: "GET";
1155
1157
  query: z.ZodObject<{
1156
1158
  providerId: z.ZodString;
@@ -1168,12 +1170,12 @@ declare const spMetadata: (options?: SSOOptions) => _$better_call0.StrictEndpoin
1168
1170
  };
1169
1171
  };
1170
1172
  }, Response>;
1171
- declare const registerSSOProvider: <O extends SSOOptions>(options: O) => _$better_call0.StrictEndpoint<"/sso/register", {
1173
+ declare const registerSSOProvider: <O extends SSOOptions>(options: O) => import("better-call").StrictEndpoint<"/sso/register", {
1172
1174
  method: "POST";
1173
1175
  body: z.ZodObject<{
1174
1176
  [x: string]: z.ZodOptional<z.ZodAny>;
1175
1177
  }, z.core.$strip>;
1176
- use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
1178
+ use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
1177
1179
  session: {
1178
1180
  session: Record<string, any> & {
1179
1181
  id: string;
@@ -1369,7 +1371,7 @@ declare const registerSSOProvider: <O extends SSOOptions>(options: O) => _$bette
1369
1371
  oidcConfig: OIDCConfig | null;
1370
1372
  samlConfig: SAMLConfig | null;
1371
1373
  } & Omit<InferSSOProvider<O>, "samlConfig" | "oidcConfig">>;
1372
- declare const signInSSO: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sign-in/sso", {
1374
+ declare const signInSSO: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sign-in/sso", {
1373
1375
  method: "POST";
1374
1376
  body: z.ZodObject<{
1375
1377
  email: z.ZodOptional<z.ZodString>;
@@ -1491,7 +1493,7 @@ declare const signInSSO: (options?: SSOOptions) => _$better_call0.StrictEndpoint
1491
1493
  url: string;
1492
1494
  redirect: boolean;
1493
1495
  }>;
1494
- declare const callbackSSO: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/callback/:providerId", {
1496
+ declare const callbackSSO: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sso/callback/:providerId", {
1495
1497
  method: "GET";
1496
1498
  query: z.ZodObject<{
1497
1499
  code: z.ZodOptional<z.ZodString>;
@@ -1519,7 +1521,7 @@ declare const callbackSSO: (options?: SSOOptions) => _$better_call0.StrictEndpoi
1519
1521
  * Used when `options.redirectURI` is set — the `providerId` is read from
1520
1522
  * the OAuth state instead of the URL path.
1521
1523
  */
1522
- declare const callbackSSOShared: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/callback", {
1524
+ declare const callbackSSOShared: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sso/callback", {
1523
1525
  metadata: {
1524
1526
  openapi: {
1525
1527
  operationId: string;
@@ -1542,7 +1544,7 @@ declare const callbackSSOShared: (options?: SSOOptions) => _$better_call0.Strict
1542
1544
  }, z.core.$strip>;
1543
1545
  allowedMediaTypes: readonly ["application/x-www-form-urlencoded", "application/json"];
1544
1546
  }, never>;
1545
- declare const acsEndpoint: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/saml2/sp/acs/:providerId", {
1547
+ declare const acsEndpoint: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sso/saml2/sp/acs/:providerId", {
1546
1548
  method: ("GET" | "POST")[];
1547
1549
  body: z.ZodOptional<z.ZodObject<{
1548
1550
  SAMLResponse: z.ZodString;
@@ -1572,7 +1574,7 @@ declare const acsEndpoint: (options?: SSOOptions) => _$better_call0.StrictEndpoi
1572
1574
  scope: "server";
1573
1575
  };
1574
1576
  }, never>;
1575
- declare const sloEndpoint: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/saml2/sp/slo/:providerId", {
1577
+ declare const sloEndpoint: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sso/saml2/sp/slo/:providerId", {
1576
1578
  method: ("GET" | "POST")[];
1577
1579
  body: z.ZodOptional<z.ZodObject<{
1578
1580
  SAMLRequest: z.ZodOptional<z.ZodString>;
@@ -1593,12 +1595,12 @@ declare const sloEndpoint: (options?: SSOOptions) => _$better_call0.StrictEndpoi
1593
1595
  scope: "server";
1594
1596
  };
1595
1597
  }, void | Response>;
1596
- declare const initiateSLO: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/saml2/logout/:providerId", {
1598
+ declare const initiateSLO: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sso/saml2/logout/:providerId", {
1597
1599
  method: "POST";
1598
1600
  body: z.ZodObject<{
1599
1601
  callbackURL: z.ZodOptional<z.ZodString>;
1600
1602
  }, z.core.$strip>;
1601
- use: _$better_call0.Middleware<_$better_call0.MiddlewareOptions, (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
1603
+ use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
1602
1604
  session: {
1603
1605
  session: Record<string, any> & {
1604
1606
  id: string;
@@ -1762,7 +1764,29 @@ interface OIDCDiscoveryDocument {
1762
1764
  /**
1763
1765
  * Error codes for OIDC discovery operations.
1764
1766
  */
1765
- 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";
1767
+ type DiscoveryErrorCode =
1768
+ /** Request to discovery endpoint timed out */
1769
+ "discovery_timeout" |
1770
+ /** Discovery endpoint returned 404 or similar */
1771
+ "discovery_not_found" |
1772
+ /** Discovery endpoint returned invalid JSON */
1773
+ "discovery_invalid_json" |
1774
+ /** OIDC endpoint URL (discovery or per-endpoint: authorization, token, userinfo, jwks) is invalid, malformed, or uses a non-`http(s)` scheme */
1775
+ "discovery_invalid_url" |
1776
+ /** OIDC endpoint URL is not trusted by the trusted origins configuration */
1777
+ "discovery_untrusted_origin" |
1778
+ /** 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.) */
1779
+ "discovery_private_host" |
1780
+ /** Server-side OIDC endpoint fetch received an HTTP redirect response */
1781
+ "oidc_endpoint_redirect" |
1782
+ /** Discovery document issuer doesn't match configured issuer */
1783
+ "issuer_mismatch" |
1784
+ /** Discovery document is missing required fields */
1785
+ "discovery_incomplete" |
1786
+ /** IdP only advertises token auth methods that Better Auth doesn't currently support */
1787
+ "unsupported_token_auth_method" |
1788
+ /** Catch-all for unexpected errors */
1789
+ "discovery_unexpected_error";
1766
1790
  /**
1767
1791
  * Custom error class for OIDC discovery failures.
1768
1792
  * 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-qb-OvHIE.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 };
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-BvKzNnKP.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 };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as PACKAGE_VERSION } from "./version-Dv2lqEg3.mjs";
1
+ import { t as PACKAGE_VERSION } from "./version-HRaJjPrD.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";
@@ -14,8 +14,7 @@ import { createRemoteJWKSet, customFetch } from "jose";
14
14
  import { base64, base64Url } from "@better-auth/utils/base64";
15
15
  import { createHash } from "@better-auth/utils/hash";
16
16
  import { DOMParser } from "@xmldom/xmldom";
17
- import * as samlifyNamespace from "samlify";
18
- import samlifyDefault from "samlify";
17
+ import samlifyDefault, * as samlifyNamespace from "samlify";
19
18
  import { defineErrorCodes } from "@better-auth/core/utils/error-codes";
20
19
  import { parseInputData, toZodSchema } from "better-auth/db";
21
20
  import { isAPIError } from "@better-auth/core/utils/is-api-error";
@@ -41,7 +40,7 @@ const LOGOUT_REQUEST_KEY_PREFIX = "saml-logout-request:";
41
40
  * Default TTL for used assertion records (15 minutes).
42
41
  * This should match the maximum expected NotOnOrAfter window plus clock skew.
43
42
  */
44
- const DEFAULT_ASSERTION_TTL_MS = 900 * 1e3;
43
+ const DEFAULT_ASSERTION_TTL_MS = 9e5;
45
44
  /**
46
45
  * Default clock skew tolerance (5 minutes).
47
46
  * Allows for minor time differences between IdP and SP servers.
@@ -51,17 +50,17 @@ const DEFAULT_ASSERTION_TTL_MS = 900 * 1e3;
51
50
  * - Clock synchronization differences (NTP drift)
52
51
  * - Distributed systems across timezones
53
52
  */
54
- const DEFAULT_CLOCK_SKEW_MS = 300 * 1e3;
53
+ const DEFAULT_CLOCK_SKEW_MS = 3e5;
55
54
  /**
56
55
  * Default maximum size for SAML responses (256 KB).
57
56
  * Protects against memory exhaustion from oversized SAML payloads.
58
57
  */
59
- const DEFAULT_MAX_SAML_RESPONSE_SIZE = 256 * 1024;
58
+ const DEFAULT_MAX_SAML_RESPONSE_SIZE = 262144;
60
59
  /**
61
60
  * Default maximum size for IdP metadata (100 KB).
62
61
  * Protects against oversized metadata documents.
63
62
  */
64
- const DEFAULT_MAX_SAML_METADATA_SIZE = 100 * 1024;
63
+ const DEFAULT_MAX_SAML_METADATA_SIZE = 102400;
65
64
  //#endregion
66
65
  //#region src/utils.ts
67
66
  const unsafeSAMLRedirectPathPrefix = /^\/(?:\/|\\|%2f|%5c)/i;
@@ -114,7 +113,8 @@ const validateEmailDomain = (email, domain) => {
114
113
  return domainMatches(emailDomain, domain);
115
114
  };
116
115
  function parseCertificate(certPem) {
117
- const cert = new X509Certificate(certPem.includes("-----BEGIN") ? certPem : `-----BEGIN CERTIFICATE-----\n${certPem}\n-----END CERTIFICATE-----`);
116
+ const normalized = certPem.includes("-----BEGIN") ? certPem : `-----BEGIN CERTIFICATE-----\n${certPem}\n-----END CERTIFICATE-----`;
117
+ const cert = new X509Certificate(normalized);
118
118
  return {
119
119
  fingerprintSha256: cert.fingerprint256,
120
120
  notBefore: cert.validFrom,
@@ -578,8 +578,9 @@ function assertOIDCAuthorizedParty(payload, clientId) {
578
578
  * the SSO OIDC flow.
579
579
  */
580
580
  async function validateOIDCIdToken(token, jwksEndpoint, options, isTrustedOrigin) {
581
+ const jwks = createRemoteJWKSet(new URL(jwksEndpoint), { [customFetch]: (url, init) => fetchOIDCEndpointResponse("jwksEndpoint", url, init, isTrustedOrigin) });
581
582
  const verified = await verifyIdToken(token, {
582
- jwks: createRemoteJWKSet(new URL(jwksEndpoint), { [customFetch]: (url, init) => fetchOIDCEndpointResponse("jwksEndpoint", url, init, isTrustedOrigin) }),
583
+ jwks,
583
584
  audience: options.audience,
584
585
  issuer: options.issuer
585
586
  });
@@ -1100,10 +1101,7 @@ function handleDeprecatedAlgorithm(message, behavior, errorCode) {
1100
1101
  message,
1101
1102
  code: errorCode
1102
1103
  });
1103
- case "warn":
1104
- console.warn(`[SAML Security Warning] ${message}`);
1105
- break;
1106
- case "allow": break;
1104
+ case "warn": console.warn(`[SAML Security Warning] ${message}`);
1107
1105
  }
1108
1106
  }
1109
1107
  function validateSignatureAlgorithm(algorithm, options = {}) {
@@ -2278,9 +2276,10 @@ async function checkProviderAccess(ctx, providerId) {
2278
2276
  });
2279
2277
  if (!provider) throw new APIError("NOT_FOUND", { message: "Provider not found" });
2280
2278
  let hasAccess = false;
2281
- if (provider.organizationId) if (ctx.context.hasPlugin("organization")) hasAccess = await isOrgAdmin(ctx, userId, provider.organizationId);
2282
- else hasAccess = provider.userId === userId;
2283
- else hasAccess = provider.userId === userId;
2279
+ if (provider.organizationId) {
2280
+ if (ctx.context.hasPlugin("organization")) hasAccess = await isOrgAdmin(ctx, userId, provider.organizationId);
2281
+ else hasAccess = provider.userId === userId;
2282
+ } else hasAccess = provider.userId === userId;
2284
2283
  if (!hasAccess) throw new APIError("FORBIDDEN", { message: "You don't have access to this provider" });
2285
2284
  return provider;
2286
2285
  }
@@ -2575,7 +2574,7 @@ const requestDomainVerification = (options) => {
2575
2574
  await ctx.context.internalAdapter.createVerificationValue({
2576
2575
  identifier,
2577
2576
  value: domainVerificationToken,
2578
- expiresAt: new Date(Date.now() + 3600 * 24 * 7 * 1e3)
2577
+ expiresAt: new Date(Date.now() + 6048e5)
2579
2578
  });
2580
2579
  ctx.setStatus(201);
2581
2580
  return ctx.json({ domainVerificationToken });
@@ -2663,7 +2662,7 @@ async function generateRelayState(c, link, providerReference) {
2663
2662
  /**
2664
2663
  * This is the actual expiry time of the state
2665
2664
  */
2666
- expiresAt: Date.now() + 600 * 1e3,
2665
+ expiresAt: Date.now() + 6e5,
2667
2666
  requestSignUp: c.body.requestSignUp,
2668
2667
  serverContext: providerReference ? { [SSO_PROVIDER_STATE_KEY]: providerReference } : void 0
2669
2668
  };
@@ -3193,9 +3192,10 @@ const spMetadata = (options) => {
3193
3192
  });
3194
3193
  };
3195
3194
  const registerSSOProvider = (options) => {
3195
+ const registerBodySchema = getRegisterSSOProviderBodySchema(options);
3196
3196
  return createAuthEndpoint("/sso/register", {
3197
3197
  method: "POST",
3198
- body: getRegisterSSOProviderBodySchema(options),
3198
+ body: registerBodySchema,
3199
3199
  use: [sessionMiddleware],
3200
3200
  metadata: {
3201
3201
  $Infer: { body: {} },
@@ -3390,13 +3390,13 @@ const registerSSOProvider = (options) => {
3390
3390
  if (!member) throw new APIError("BAD_REQUEST", { message: "You are not a member of the organization" });
3391
3391
  if (ctx.context.hasPlugin("organization") && !hasOrgAdminRole(member)) throw new APIError("FORBIDDEN", { message: "You must be an organization owner or admin to register SSO providers" });
3392
3392
  }
3393
- if (new Set([
3393
+ if ((/* @__PURE__ */ new Set([
3394
3394
  ...BUILT_IN_ACCOUNT_PROVIDER_IDS,
3395
3395
  ...Object.keys(ctx.context.options.socialProviders ?? {}),
3396
3396
  ...ctx.context.socialProviders.map((p) => p.id),
3397
3397
  ...ctx.context.trustedProviders,
3398
3398
  ...options?.defaultSSO?.map((p) => p.providerId) ?? []
3399
- ]).has(body.providerId)) {
3399
+ ])).has(body.providerId)) {
3400
3400
  ctx.context.logger.warn(`SSO provider registration rejected for reserved providerId: ${body.providerId}`);
3401
3401
  throw new APIError("UNPROCESSABLE_ENTITY", { message: "This providerId is reserved and cannot be used for an SSO provider" });
3402
3402
  }
@@ -3538,7 +3538,7 @@ const registerSSOProvider = (options) => {
3538
3538
  await ctx.context.internalAdapter.createVerificationValue({
3539
3539
  identifier: getVerificationIdentifier(options, provider.providerId),
3540
3540
  value: domainVerificationToken,
3541
- expiresAt: new Date(Date.now() + 3600 * 24 * 7 * 1e3)
3541
+ expiresAt: new Date(Date.now() + 6048e5)
3542
3542
  });
3543
3543
  }
3544
3544
  const result = {
@@ -3818,7 +3818,9 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
3818
3818
  const { code, error, error_description } = ctx.query;
3819
3819
  if (!stateData) stateData = await parseState(ctx);
3820
3820
  if (!stateData) {
3821
- const redirectURL = appendQueryParams(ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`, new URLSearchParams({ error: "invalid_state" }));
3821
+ const errorURL = ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`;
3822
+ const params = new URLSearchParams({ error: "invalid_state" });
3823
+ const redirectURL = appendQueryParams(errorURL, params);
3822
3824
  throw ctx.redirect(redirectURL);
3823
3825
  }
3824
3826
  const providerReference = parsedProviderReference ?? parseSSOProviderReference(stateData.serverContext?.["ssoProviderReference"]);
@@ -4199,15 +4201,19 @@ const callbackSSOShared = (options) => {
4199
4201
  }, async (ctx) => {
4200
4202
  const stateData = await parseState(ctx);
4201
4203
  if (!stateData) {
4202
- const redirectURL = appendQueryParams(ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`, new URLSearchParams({ error: "invalid_state" }));
4204
+ const errorURL = ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`;
4205
+ const params = new URLSearchParams({ error: "invalid_state" });
4206
+ const redirectURL = appendQueryParams(errorURL, params);
4203
4207
  throw ctx.redirect(redirectURL);
4204
4208
  }
4205
4209
  const providerReference = parseSSOProviderReference(stateData.serverContext?.[SSO_PROVIDER_STATE_KEY]);
4206
4210
  if (!providerReference) {
4207
- const redirectURL = appendQueryParams(stateData.errorURL || stateData.callbackURL, new URLSearchParams({
4211
+ const errorURL = stateData.errorURL || stateData.callbackURL;
4212
+ const params = new URLSearchParams({
4208
4213
  error: "invalid_state",
4209
4214
  error_description: "missing_sso_provider_reference"
4210
- }));
4215
+ });
4216
+ const redirectURL = appendQueryParams(errorURL, params);
4211
4217
  throw ctx.redirect(redirectURL);
4212
4218
  }
4213
4219
  return handleOIDCCallback(ctx, options, providerReference.providerId, stateData, providerReference);
@@ -4243,7 +4249,9 @@ const acsEndpoint = (options) => {
4243
4249
  let resolvedErrorRedirectUrl;
4244
4250
  if (ctx.method === "GET" && !ctx.body?.SAMLResponse) {
4245
4251
  if (!(await getSessionFromCtx(ctx))?.session) {
4246
- const redirectURL = appendQueryParams(ctx.context.options.onAPIError?.errorURL || `${appOrigin}/error`, new URLSearchParams({ error: "invalid_request" }));
4252
+ const errorURL = ctx.context.options.onAPIError?.errorURL || `${appOrigin}/error`;
4253
+ const params = new URLSearchParams({ error: "invalid_request" });
4254
+ const redirectURL = appendQueryParams(errorURL, params);
4247
4255
  throw ctx.redirect(redirectURL);
4248
4256
  }
4249
4257
  const relayState = ctx.query?.RelayState;
@@ -4312,10 +4320,11 @@ const sloEndpoint = (options) => {
4312
4320
  const appOrigin = new URL(ctx.context.baseURL).origin;
4313
4321
  const safeErrorURL = getSafeRedirectUrl([relayState], `${appOrigin}/sso/saml2/sp/slo/${providerId}`, appOrigin, (url, settings) => ctx.context.isTrustedOrigin(url, settings));
4314
4322
  if (!samlRequest && !samlResponse) {
4315
- const redirectURL = appendQueryParams(safeErrorURL, new URLSearchParams({
4323
+ const params = new URLSearchParams({
4316
4324
  error: "invalid_request",
4317
4325
  error_description: "missing_logout_data"
4318
- }));
4326
+ });
4327
+ const redirectURL = appendQueryParams(safeErrorURL, params);
4319
4328
  throw ctx.redirect(redirectURL);
4320
4329
  }
4321
4330
  const provider = await findSAMLProvider(providerId, options, ctx.context.adapter);
@@ -4378,14 +4387,16 @@ async function handleLogoutRequest(ctx, sp, idp, relayState, providerId) {
4378
4387
  const stored = await ctx.context.internalAdapter.findVerificationValue(key);
4379
4388
  if (stored) {
4380
4389
  const data = safeJsonParse(stored.value);
4381
- if (data) if (!sessionIndex || !data.sessionIndex || sessionIndex === data.sessionIndex) {
4382
- await ctx.context.internalAdapter.deleteSession(data.sessionToken).catch((e) => ctx.context.logger.warn("Failed to delete session during SLO", { error: e }));
4383
- await ctx.context.internalAdapter.deleteVerificationByIdentifier(`${SAML_SESSION_BY_ID_PREFIX}${data.sessionId}`).catch((e) => ctx.context.logger.warn("Failed to delete SAML session lookup during SLO", e));
4384
- } else ctx.context.logger.warn("SessionIndex mismatch in LogoutRequest - skipping session deletion", {
4385
- providerId,
4386
- requestedSessionIndex: sessionIndex,
4387
- storedSessionIndex: data.sessionIndex
4388
- });
4390
+ if (data) {
4391
+ if (!sessionIndex || !data.sessionIndex || sessionIndex === data.sessionIndex) {
4392
+ await ctx.context.internalAdapter.deleteSession(data.sessionToken).catch((e) => ctx.context.logger.warn("Failed to delete session during SLO", { error: e }));
4393
+ await ctx.context.internalAdapter.deleteVerificationByIdentifier(`${SAML_SESSION_BY_ID_PREFIX}${data.sessionId}`).catch((e) => ctx.context.logger.warn("Failed to delete SAML session lookup during SLO", e));
4394
+ } else ctx.context.logger.warn("SessionIndex mismatch in LogoutRequest - skipping session deletion", {
4395
+ providerId,
4396
+ requestedSessionIndex: sessionIndex,
4397
+ storedSessionIndex: data.sessionIndex
4398
+ });
4399
+ }
4389
4400
  await ctx.context.internalAdapter.deleteVerificationByIdentifier(key).catch((e) => ctx.context.logger.warn("Failed to delete SAML session key during SLO", e));
4390
4401
  }
4391
4402
  const currentSession = await getSessionFromCtx(ctx);
@@ -1,5 +1,5 @@
1
1
  //#endregion
2
2
  //#region src/version.ts
3
- const PACKAGE_VERSION = "1.8.0-beta.2";
3
+ const PACKAGE_VERSION = "1.8.0-beta.3";
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.8.0-beta.2",
3
+ "version": "1.8.0-beta.3",
4
4
  "description": "SSO plugin for Better Auth",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -71,17 +71,17 @@
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.21.10",
75
- "@better-auth/core": "1.8.0-beta.2",
76
- "@better-auth/kysely-adapter": "1.8.0-beta.2",
77
- "better-auth": "1.8.0-beta.2"
74
+ "tsdown": "0.23.1",
75
+ "@better-auth/core": "1.8.0-beta.3",
76
+ "@better-auth/kysely-adapter": "1.8.0-beta.3",
77
+ "better-auth": "1.8.0-beta.3"
78
78
  },
79
79
  "peerDependencies": {
80
80
  "@better-auth/utils": "^0.4.2 || ^0.5.0",
81
- "@better-fetch/fetch": "1.3.2",
81
+ "@better-fetch/fetch": "1.3.3",
82
82
  "better-call": "1.4.4",
83
- "@better-auth/core": "^1.8.0-beta.2",
84
- "better-auth": "^1.8.0-beta.2"
83
+ "@better-auth/core": "^1.8.0-beta.3",
84
+ "better-auth": "^1.8.0-beta.3"
85
85
  },
86
86
  "scripts": {
87
87
  "build": "tsdown",