@better-auth/sso 1.7.12 → 1.7.14
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-
|
|
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 {
|
|
33
|
+
export {};
|
package/dist/client.mjs
CHANGED
|
@@ -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
|
|
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) =>
|
|
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:
|
|
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) =>
|
|
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:
|
|
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) =>
|
|
799
|
+
declare const listSSOProviders: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sso/providers", {
|
|
798
800
|
method: "GET";
|
|
799
|
-
use:
|
|
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) =>
|
|
870
|
+
declare const getSSOProvider: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sso/get-provider", {
|
|
869
871
|
method: "GET";
|
|
870
|
-
use:
|
|
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) =>
|
|
948
|
+
declare const updateSSOProvider: (options: SSOOptions) => import("better-call").StrictEndpoint<"/sso/update-provider", {
|
|
947
949
|
method: "POST";
|
|
948
|
-
use:
|
|
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) =>
|
|
1104
|
+
declare const deleteSSOProvider: (options?: SSOOptions) => import("better-call").StrictEndpoint<"/sso/delete-provider", {
|
|
1103
1105
|
method: "POST";
|
|
1104
|
-
use:
|
|
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) =>
|
|
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) =>
|
|
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:
|
|
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) =>
|
|
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) =>
|
|
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) =>
|
|
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) =>
|
|
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) =>
|
|
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) =>
|
|
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:
|
|
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 =
|
|
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-
|
|
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-
|
|
1
|
+
import { t as PACKAGE_VERSION } from "./version-5IaAS5uL.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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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)
|
|
2282
|
-
|
|
2283
|
-
|
|
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() +
|
|
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() +
|
|
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:
|
|
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() +
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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)
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
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);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/sso",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.14",
|
|
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.
|
|
75
|
-
"@better-auth/core": "1.7.
|
|
76
|
-
"@better-auth/kysely-adapter": "1.7.
|
|
77
|
-
"better-auth": "1.7.
|
|
74
|
+
"tsdown": "0.23.1",
|
|
75
|
+
"@better-auth/core": "1.7.14",
|
|
76
|
+
"@better-auth/kysely-adapter": "1.7.14",
|
|
77
|
+
"better-auth": "1.7.14"
|
|
78
78
|
},
|
|
79
79
|
"peerDependencies": {
|
|
80
80
|
"@better-auth/utils": "^0.4.2 || ^0.5.0",
|
|
81
|
-
"@better-fetch/fetch": "1.3.
|
|
81
|
+
"@better-fetch/fetch": "1.3.3",
|
|
82
82
|
"better-call": "1.4.4",
|
|
83
|
-
"better-auth": "^1.7.
|
|
84
|
-
"
|
|
83
|
+
"@better-auth/core": "^1.7.14",
|
|
84
|
+
"better-auth": "^1.7.14"
|
|
85
85
|
},
|
|
86
86
|
"scripts": {
|
|
87
87
|
"build": "tsdown",
|