@better-auth/sso 1.7.1 → 1.7.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
package/dist/client.mjs
CHANGED
|
@@ -1511,7 +1511,7 @@ declare const callbackSSO: (options?: SSOOptions) => _$better_call0.StrictEndpoi
|
|
|
1511
1511
|
};
|
|
1512
1512
|
scope: "server";
|
|
1513
1513
|
};
|
|
1514
|
-
},
|
|
1514
|
+
}, never>;
|
|
1515
1515
|
/**
|
|
1516
1516
|
* Shared OIDC callback endpoint (no `:providerId` in path).
|
|
1517
1517
|
* Used when `options.redirectURI` is set — the `providerId` is read from
|
|
@@ -1539,7 +1539,7 @@ declare const callbackSSOShared: (options?: SSOOptions) => _$better_call0.Strict
|
|
|
1539
1539
|
error_description: z.ZodOptional<z.ZodString>;
|
|
1540
1540
|
}, z.core.$strip>;
|
|
1541
1541
|
allowedMediaTypes: readonly ["application/x-www-form-urlencoded", "application/json"];
|
|
1542
|
-
},
|
|
1542
|
+
}, never>;
|
|
1543
1543
|
declare const acsEndpoint: (options?: SSOOptions) => _$better_call0.StrictEndpoint<"/sso/saml2/sp/acs/:providerId", {
|
|
1544
1544
|
method: ("GET" | "POST")[];
|
|
1545
1545
|
body: z.ZodOptional<z.ZodObject<{
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as SAMLIdentityProviderMetadata, B as SSOUserResolutionContext, C as deriveSAMLIdentityProviderEntityID, D as DEFAULT_MAX_SAML_RESPONSE_SIZE, E as DEFAULT_MAX_SAML_METADATA_SIZE, F as SSOProviderMutationGuardInput, G as DigestAlgorithm, H as AlgorithmValidationOptions, I as SSOProviderReference, K as KeyEncryptionAlgorithm, L as SSOProviderUserProfile, M as SSOOptions, N as SSOProvider, O as OIDCConfig, P as SSOProviderMutationGuardContext, R as SSOSAMLUserResolutionInput, S as SAMLServiceProviderPolicy, T as DEFAULT_CLOCK_SKEW_MS, U as DataEncryptionAlgorithm, V as SSOUserResolutionInput, W as DeprecatedAlgorithmBehavior, _ as REQUIRED_DISCOVERY_FIELDS, a as fetchDiscoveryDocument, b as TimestampValidationOptions, c as normalizeUrl, d as validateDiscoveryUrl, f as DiscoverOIDCConfigParams, g as OIDCDiscoveryDocument, h as HydratedOIDCConfig, i as discoverOIDCConfig, j as SSOOIDCUserResolutionInput, k as SAMLConfig, l as selectTokenEndpointAuthMethod, m as DiscoveryErrorCode, n as sso, o as needsRuntimeDiscovery, p as DiscoveryError, q as SignatureAlgorithm, r as computeDiscoveryUrl, s as normalizeDiscoveryUrls, t as SSOPlugin, u as validateDiscoveryDocument, v as RequiredDiscoveryField, w as deriveSAMLServiceProviderPolicy, x as validateSAMLTimestamp, y as SAMLConditions, z as SSOUserResolution } from "./index-
|
|
1
|
+
import { A as SAMLIdentityProviderMetadata, B as SSOUserResolutionContext, C as deriveSAMLIdentityProviderEntityID, D as DEFAULT_MAX_SAML_RESPONSE_SIZE, E as DEFAULT_MAX_SAML_METADATA_SIZE, F as SSOProviderMutationGuardInput, G as DigestAlgorithm, H as AlgorithmValidationOptions, I as SSOProviderReference, K as KeyEncryptionAlgorithm, L as SSOProviderUserProfile, M as SSOOptions, N as SSOProvider, O as OIDCConfig, P as SSOProviderMutationGuardContext, R as SSOSAMLUserResolutionInput, S as SAMLServiceProviderPolicy, T as DEFAULT_CLOCK_SKEW_MS, U as DataEncryptionAlgorithm, V as SSOUserResolutionInput, W as DeprecatedAlgorithmBehavior, _ as REQUIRED_DISCOVERY_FIELDS, a as fetchDiscoveryDocument, b as TimestampValidationOptions, c as normalizeUrl, d as validateDiscoveryUrl, f as DiscoverOIDCConfigParams, g as OIDCDiscoveryDocument, h as HydratedOIDCConfig, i as discoverOIDCConfig, j as SSOOIDCUserResolutionInput, k as SAMLConfig, l as selectTokenEndpointAuthMethod, m as DiscoveryErrorCode, n as sso, o as needsRuntimeDiscovery, p as DiscoveryError, q as SignatureAlgorithm, r as computeDiscoveryUrl, s as normalizeDiscoveryUrls, t as SSOPlugin, u as validateDiscoveryDocument, v as RequiredDiscoveryField, w as deriveSAMLServiceProviderPolicy, x as validateSAMLTimestamp, y as SAMLConditions, z as SSOUserResolution } from "./index-sM6JWXeV.mjs";
|
|
2
2
|
export { AlgorithmValidationOptions, DEFAULT_CLOCK_SKEW_MS, DEFAULT_MAX_SAML_METADATA_SIZE, DEFAULT_MAX_SAML_RESPONSE_SIZE, DataEncryptionAlgorithm, DeprecatedAlgorithmBehavior, DigestAlgorithm, DiscoverOIDCConfigParams, DiscoveryError, DiscoveryErrorCode, HydratedOIDCConfig, KeyEncryptionAlgorithm, OIDCConfig, OIDCDiscoveryDocument, REQUIRED_DISCOVERY_FIELDS, RequiredDiscoveryField, SAMLConditions, SAMLConfig, SAMLIdentityProviderMetadata, SAMLServiceProviderPolicy, SSOOIDCUserResolutionInput, SSOOptions, SSOPlugin, SSOProvider, SSOProviderMutationGuardContext, SSOProviderMutationGuardInput, SSOProviderReference, SSOProviderUserProfile, SSOSAMLUserResolutionInput, SSOUserResolution, SSOUserResolutionContext, SSOUserResolutionInput, SignatureAlgorithm, TimestampValidationOptions, computeDiscoveryUrl, deriveSAMLIdentityProviderEntityID, deriveSAMLServiceProviderPolicy, discoverOIDCConfig, fetchDiscoveryDocument, needsRuntimeDiscovery, normalizeDiscoveryUrls, normalizeUrl, selectTokenEndpointAuthMethod, sso, validateDiscoveryDocument, validateDiscoveryUrl, validateSAMLTimestamp };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as PACKAGE_VERSION } from "./version-
|
|
1
|
+
import { t as PACKAGE_VERSION } from "./version-BA_IW5w3.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";
|
|
@@ -18,6 +18,7 @@ import samlifyDefault from "samlify";
|
|
|
18
18
|
import { defineErrorCodes } from "@better-auth/core/utils/error-codes";
|
|
19
19
|
import { parseInputData, toZodSchema } from "better-auth/db";
|
|
20
20
|
import { isAPIError } from "@better-auth/core/utils/is-api-error";
|
|
21
|
+
import { appendQueryParams } from "@better-auth/core/utils/url";
|
|
21
22
|
import { HIDE_METADATA, PRIVATE_KEY_JWT_SIGNING_ALGORITHMS, authorizationCodeRequest, createAuthorizationURL, createPrivateKeyJwtClientAssertionGetter, generateGenericState, generateState, getOAuth2Tokens, parseGenericState, parseState } from "better-auth";
|
|
22
23
|
import { deleteSessionCookie, setAccountCookie, setSessionCookie } from "better-auth/cookies";
|
|
23
24
|
import { additionalAuthorizationParamsSchema, handleOAuthUserInfo } from "better-auth/oauth2";
|
|
@@ -3040,7 +3041,6 @@ async function processSAMLResponse(ctx, params, options) {
|
|
|
3040
3041
|
},
|
|
3041
3042
|
account: {
|
|
3042
3043
|
providerId,
|
|
3043
|
-
issuer: accountKey.issuer,
|
|
3044
3044
|
accountId: accountKey.accountId,
|
|
3045
3045
|
accessToken: "",
|
|
3046
3046
|
refreshToken: ""
|
|
@@ -3796,33 +3796,31 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
|
|
|
3796
3796
|
const { code, error, error_description } = ctx.query;
|
|
3797
3797
|
if (!stateData) stateData = await parseState(ctx);
|
|
3798
3798
|
if (!stateData) {
|
|
3799
|
-
const
|
|
3800
|
-
throw ctx.redirect(
|
|
3799
|
+
const redirectURL = appendQueryParams(ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`, new URLSearchParams({ error: "invalid_state" }));
|
|
3800
|
+
throw ctx.redirect(redirectURL);
|
|
3801
3801
|
}
|
|
3802
3802
|
const providerReference = parsedProviderReference ?? parseSSOProviderReference(stateData.serverContext?.["ssoProviderReference"]);
|
|
3803
3803
|
const { callbackURL, errorURL, newUserURL, requestSignUp } = stateData;
|
|
3804
3804
|
const redirectOIDCError = (error, description) => {
|
|
3805
3805
|
const baseURL = errorURL || callbackURL;
|
|
3806
|
-
const params = new URLSearchParams({
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
const separator = baseURL.includes("?") ? "&" : "?";
|
|
3811
|
-
throw ctx.redirect(`${baseURL}${separator}${params.toString()}`);
|
|
3806
|
+
const params = new URLSearchParams({ error });
|
|
3807
|
+
if (description) params.set("error_description", description);
|
|
3808
|
+
const redirectURL = appendQueryParams(baseURL, params);
|
|
3809
|
+
throw ctx.redirect(redirectURL);
|
|
3812
3810
|
};
|
|
3813
|
-
if (!code || error) redirectOIDCError(error || "invalid_request", error_description || (error ? error : "authorization_code_not_found"));
|
|
3811
|
+
if (!code || error) return redirectOIDCError(error || "invalid_request", error_description || (error ? error : "authorization_code_not_found"));
|
|
3814
3812
|
const provider = await resolveOIDCProvider(ctx, options, providerId);
|
|
3815
|
-
if (!provider)
|
|
3813
|
+
if (!provider) return redirectOIDCError("invalid_provider", "provider not found");
|
|
3816
3814
|
const acceptedProviderReference = providerReference ?? redirectOIDCError("invalid_state", "missing_sso_provider_reference");
|
|
3817
|
-
if (!await isCurrentSSOProviderReference(provider, acceptedProviderReference)) redirectOIDCError("invalid_state", "sso_provider_changed_during_authentication");
|
|
3815
|
+
if (!await isCurrentSSOProviderReference(provider, acceptedProviderReference)) return redirectOIDCError("invalid_state", "sso_provider_changed_during_authentication");
|
|
3818
3816
|
if (options?.domainVerification?.enabled && !("domainVerified" in provider && provider.domainVerified)) throw new APIError("UNAUTHORIZED", { message: "Provider domain has not been verified" });
|
|
3819
3817
|
let config = provider.oidcConfig;
|
|
3820
|
-
if (!config)
|
|
3818
|
+
if (!config) return redirectOIDCError("invalid_provider", "provider not found");
|
|
3821
3819
|
try {
|
|
3822
3820
|
config = await ensureRuntimeDiscovery(config, provider.issuer, (url) => ctx.context.isTrustedOrigin(url));
|
|
3823
3821
|
} catch (error) {
|
|
3824
|
-
if (error instanceof DiscoveryError)
|
|
3825
|
-
|
|
3822
|
+
if (error instanceof DiscoveryError) return redirectOIDCError("discovery_failed", error.message);
|
|
3823
|
+
return redirectOIDCError("discovery_failed", "unexpected_discovery_error");
|
|
3826
3824
|
}
|
|
3827
3825
|
if (!config.scopes) config = {
|
|
3828
3826
|
...config,
|
|
@@ -3833,7 +3831,7 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
|
|
|
3833
3831
|
"offline_access"
|
|
3834
3832
|
]
|
|
3835
3833
|
};
|
|
3836
|
-
if (!config.tokenEndpoint)
|
|
3834
|
+
if (!config.tokenEndpoint) return redirectOIDCError("invalid_provider", "token_endpoint_not_found");
|
|
3837
3835
|
const tokenEndpoint = config.tokenEndpoint;
|
|
3838
3836
|
let tokenEndpointAuth = config.tokenEndpointAuthentication === "client_secret_post" ? { method: "client_secret_post" } : { method: "client_secret_basic" };
|
|
3839
3837
|
if (config.tokenEndpointAuthentication === "private_key_jwt") {
|
|
@@ -3845,7 +3843,7 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
|
|
|
3845
3843
|
keyId: config.privateKeyId,
|
|
3846
3844
|
issuer: config.issuer
|
|
3847
3845
|
});
|
|
3848
|
-
if (!resolved || !resolved.privateKeyJwk && !resolved.privateKeyPem)
|
|
3846
|
+
if (!resolved || !resolved.privateKeyJwk && !resolved.privateKeyPem) return redirectOIDCError("invalid_provider", "no_private_key_available");
|
|
3849
3847
|
const rawAlg = config.privateKeyAlgorithm ?? resolved.algorithm;
|
|
3850
3848
|
const algorithm = rawAlg && PRIVATE_KEY_JWT_SIGNING_ALGORITHMS.includes(rawAlg) ? rawAlg : void 0;
|
|
3851
3849
|
tokenEndpointAuth = {
|
|
@@ -3874,16 +3872,16 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
|
|
|
3874
3872
|
body,
|
|
3875
3873
|
headers
|
|
3876
3874
|
}, (url) => ctx.context.isTrustedOrigin(url));
|
|
3877
|
-
if (error) redirectOIDCError("invalid_provider", getOIDCErrorDescription(error, "token_response_error"));
|
|
3875
|
+
if (error) return redirectOIDCError("invalid_provider", getOIDCErrorDescription(error, "token_response_error"));
|
|
3878
3876
|
if (!data) throw new Error("Token endpoint returned an empty response");
|
|
3879
3877
|
return getOAuth2Tokens(data);
|
|
3880
3878
|
})().catch((e) => {
|
|
3881
3879
|
if (isAPIError(e)) throw e;
|
|
3882
3880
|
ctx.context.logger.error("Error validating authorization code", e);
|
|
3883
|
-
if (e instanceof DiscoveryError) redirectOIDCError("invalid_provider", e.message);
|
|
3884
|
-
redirectOIDCError("invalid_provider", getOIDCErrorDescription(e, "token_response_error"));
|
|
3881
|
+
if (e instanceof DiscoveryError) return redirectOIDCError("invalid_provider", e.message);
|
|
3882
|
+
return redirectOIDCError("invalid_provider", getOIDCErrorDescription(e, "token_response_error"));
|
|
3885
3883
|
});
|
|
3886
|
-
if (!tokenResponse)
|
|
3884
|
+
if (!tokenResponse) return redirectOIDCError("invalid_provider", "token_response_not_found");
|
|
3887
3885
|
let userInfo = null;
|
|
3888
3886
|
const mapping = config.mapping || {};
|
|
3889
3887
|
const readStringClaim = (claims, claim) => {
|
|
@@ -3894,28 +3892,28 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
|
|
|
3894
3892
|
let verifiedIdToken = null;
|
|
3895
3893
|
if (tokenResponse.idToken) {
|
|
3896
3894
|
const jwksEndpoint = config.jwksEndpoint;
|
|
3897
|
-
if (!jwksEndpoint) redirectOIDCError("invalid_provider", "jwks_endpoint_not_found");
|
|
3895
|
+
if (!jwksEndpoint) return redirectOIDCError("invalid_provider", "jwks_endpoint_not_found");
|
|
3898
3896
|
const verified = await validateOIDCIdToken(tokenResponse.idToken, jwksEndpoint, {
|
|
3899
3897
|
audience: config.clientId,
|
|
3900
3898
|
issuer: provider.issuer
|
|
3901
3899
|
}, (url) => ctx.context.isTrustedOrigin(url)).catch((error) => {
|
|
3902
|
-
if (error instanceof DiscoveryError) redirectOIDCError("invalid_provider", error.message);
|
|
3900
|
+
if (error instanceof DiscoveryError) return redirectOIDCError("invalid_provider", error.message);
|
|
3903
3901
|
ctx.context.logger.error(error);
|
|
3904
3902
|
return null;
|
|
3905
3903
|
});
|
|
3906
|
-
if (!verified) redirectOIDCError("invalid_provider", "token_not_verified");
|
|
3907
|
-
if (!readStringClaim(verified.payload, "sub")) redirectOIDCError("invalid_provider", "id_token_subject_missing");
|
|
3904
|
+
if (!verified) return redirectOIDCError("invalid_provider", "token_not_verified");
|
|
3905
|
+
if (!readStringClaim(verified.payload, "sub")) return redirectOIDCError("invalid_provider", "id_token_subject_missing");
|
|
3908
3906
|
verifiedIdToken = verified;
|
|
3909
3907
|
}
|
|
3910
|
-
if (options?.resolveUser && !verifiedIdToken) redirectOIDCError("invalid_provider", "id_token_required_for_user_resolution");
|
|
3908
|
+
if (options?.resolveUser && !verifiedIdToken) return redirectOIDCError("invalid_provider", "id_token_required_for_user_resolution");
|
|
3911
3909
|
if (config.userInfoEndpoint) {
|
|
3912
3910
|
const userInfoResponse = await fetchOIDCEndpoint("userInfoEndpoint", config.userInfoEndpoint, { headers: { Authorization: `Bearer ${tokenResponse.accessToken}` } }, (url) => ctx.context.isTrustedOrigin(url)).catch((e) => {
|
|
3913
|
-
if (e instanceof DiscoveryError) redirectOIDCError("invalid_provider", e.message);
|
|
3911
|
+
if (e instanceof DiscoveryError) return redirectOIDCError("invalid_provider", e.message);
|
|
3914
3912
|
throw e;
|
|
3915
3913
|
});
|
|
3916
|
-
if (userInfoResponse.error) redirectOIDCError("invalid_provider", userInfoResponse.error.message || userInfoResponse.error.statusText || "userinfo_response_error");
|
|
3914
|
+
if (userInfoResponse.error) return redirectOIDCError("invalid_provider", userInfoResponse.error.message || userInfoResponse.error.statusText || "userinfo_response_error");
|
|
3917
3915
|
const rawUserInfo = userInfoResponse.data ?? redirectOIDCError("invalid_provider", "userinfo_response_not_found");
|
|
3918
|
-
if (verifiedIdToken && rawUserInfo.sub !== verifiedIdToken.payload.sub) redirectOIDCError("invalid_provider", "id_token_userinfo_subject_mismatch");
|
|
3916
|
+
if (verifiedIdToken && rawUserInfo.sub !== verifiedIdToken.payload.sub) return redirectOIDCError("invalid_provider", "id_token_userinfo_subject_mismatch");
|
|
3919
3917
|
rawProfile = rawUserInfo;
|
|
3920
3918
|
userInfo = {
|
|
3921
3919
|
...Object.fromEntries(Object.entries(mapping.extraFields || {}).map(([key, value]) => [key, rawUserInfo[value]])),
|
|
@@ -3936,8 +3934,8 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
|
|
|
3936
3934
|
name: readStringClaim(idToken, mapping.name || "name"),
|
|
3937
3935
|
image: readStringClaim(idToken, mapping.image || "picture")
|
|
3938
3936
|
};
|
|
3939
|
-
} else
|
|
3940
|
-
if (!userInfo.email || !userInfo.id)
|
|
3937
|
+
} else return redirectOIDCError("invalid_provider", "user_info_endpoint_not_found");
|
|
3938
|
+
if (!userInfo.email || !userInfo.id) return redirectOIDCError("invalid_provider", "missing_user_info");
|
|
3941
3939
|
const userInfoEmail = userInfo.email;
|
|
3942
3940
|
const userInfoId = userInfo.id;
|
|
3943
3941
|
const providerUser = {
|
|
@@ -3992,7 +3990,6 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
|
|
|
3992
3990
|
idToken: tokenResponse.idToken,
|
|
3993
3991
|
accessToken: tokenResponse.accessToken,
|
|
3994
3992
|
refreshToken: tokenResponse.refreshToken,
|
|
3995
|
-
issuer: accountKey.issuer,
|
|
3996
3993
|
accountId: userInfoId,
|
|
3997
3994
|
providerId: provider.providerId,
|
|
3998
3995
|
accessTokenExpiresAt: tokenResponse.accessTokenExpiresAt,
|
|
@@ -4025,20 +4022,10 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
|
|
|
4025
4022
|
} catch (e) {
|
|
4026
4023
|
const failedAuthentication = getFailedSSOAuthenticationResult(e);
|
|
4027
4024
|
if (failedAuthentication) linked = failedAuthentication;
|
|
4028
|
-
else if (isAPIError(e) && e.body?.code)
|
|
4029
|
-
|
|
4030
|
-
const params = new URLSearchParams({ error: e.body.code });
|
|
4031
|
-
if (e.body.message) params.set("error_description", e.body.message);
|
|
4032
|
-
const sep = baseURL.includes("?") ? "&" : "?";
|
|
4033
|
-
throw ctx.redirect(`${baseURL}${sep}${params.toString()}`);
|
|
4034
|
-
} else throw e;
|
|
4035
|
-
}
|
|
4036
|
-
if (linked.error) {
|
|
4037
|
-
const baseURL = errorURL || callbackURL;
|
|
4038
|
-
const params = new URLSearchParams({ error: linked.error });
|
|
4039
|
-
const sep = baseURL.includes("?") ? "&" : "?";
|
|
4040
|
-
throw ctx.redirect(`${baseURL}${sep}${params.toString()}`);
|
|
4025
|
+
else if (isAPIError(e) && e.body?.code) return redirectOIDCError(e.body.code, e.body.message);
|
|
4026
|
+
else throw e;
|
|
4041
4027
|
}
|
|
4028
|
+
if (linked.error) return redirectOIDCError(linked.error);
|
|
4042
4029
|
const { session, user } = linked.data;
|
|
4043
4030
|
if (options?.provisionUser && (linked.isRegister || options.provisionUserOnEveryLogin)) await options.provisionUser({
|
|
4044
4031
|
user,
|
|
@@ -4189,13 +4176,16 @@ const callbackSSOShared = (options) => {
|
|
|
4189
4176
|
}, async (ctx) => {
|
|
4190
4177
|
const stateData = await parseState(ctx);
|
|
4191
4178
|
if (!stateData) {
|
|
4192
|
-
const
|
|
4193
|
-
throw ctx.redirect(
|
|
4179
|
+
const redirectURL = appendQueryParams(ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`, new URLSearchParams({ error: "invalid_state" }));
|
|
4180
|
+
throw ctx.redirect(redirectURL);
|
|
4194
4181
|
}
|
|
4195
4182
|
const providerReference = parseSSOProviderReference(stateData.serverContext?.[SSO_PROVIDER_STATE_KEY]);
|
|
4196
4183
|
if (!providerReference) {
|
|
4197
|
-
const
|
|
4198
|
-
|
|
4184
|
+
const redirectURL = appendQueryParams(stateData.errorURL || stateData.callbackURL, new URLSearchParams({
|
|
4185
|
+
error: "invalid_state",
|
|
4186
|
+
error_description: "missing_sso_provider_reference"
|
|
4187
|
+
}));
|
|
4188
|
+
throw ctx.redirect(redirectURL);
|
|
4199
4189
|
}
|
|
4200
4190
|
return handleOIDCCallback(ctx, options, providerReference.providerId, stateData, providerReference);
|
|
4201
4191
|
});
|
|
@@ -4230,8 +4220,8 @@ const acsEndpoint = (options) => {
|
|
|
4230
4220
|
let resolvedErrorRedirectUrl;
|
|
4231
4221
|
if (ctx.method === "GET" && !ctx.body?.SAMLResponse) {
|
|
4232
4222
|
if (!(await getSessionFromCtx(ctx))?.session) {
|
|
4233
|
-
const
|
|
4234
|
-
throw ctx.redirect(
|
|
4223
|
+
const redirectURL = appendQueryParams(ctx.context.options.onAPIError?.errorURL || `${appOrigin}/error`, new URLSearchParams({ error: "invalid_request" }));
|
|
4224
|
+
throw ctx.redirect(redirectURL);
|
|
4235
4225
|
}
|
|
4236
4226
|
const relayState = ctx.query?.RelayState;
|
|
4237
4227
|
throw ctx.redirect(getSafeRedirectUrl([relayState], currentCallbackPath, appOrigin, (url, settings) => ctx.context.isTrustedOrigin(url, settings)));
|
|
@@ -4298,7 +4288,13 @@ const sloEndpoint = (options) => {
|
|
|
4298
4288
|
const relayState = ctx.body?.RelayState || ctx.query?.RelayState;
|
|
4299
4289
|
const appOrigin = new URL(ctx.context.baseURL).origin;
|
|
4300
4290
|
const safeErrorURL = getSafeRedirectUrl([relayState], `${appOrigin}/sso/saml2/sp/slo/${providerId}`, appOrigin, (url, settings) => ctx.context.isTrustedOrigin(url, settings));
|
|
4301
|
-
if (!samlRequest && !samlResponse)
|
|
4291
|
+
if (!samlRequest && !samlResponse) {
|
|
4292
|
+
const redirectURL = appendQueryParams(safeErrorURL, new URLSearchParams({
|
|
4293
|
+
error: "invalid_request",
|
|
4294
|
+
error_description: "missing_logout_data"
|
|
4295
|
+
}));
|
|
4296
|
+
throw ctx.redirect(redirectURL);
|
|
4297
|
+
}
|
|
4302
4298
|
const provider = await findSAMLProvider(providerId, options, ctx.context.adapter);
|
|
4303
4299
|
if (!provider?.samlConfig) throw APIError.from("NOT_FOUND", SAML_ERROR_CODES.SAML_PROVIDER_NOT_FOUND);
|
|
4304
4300
|
const config = provider.samlConfig;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/sso",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.3",
|
|
4
4
|
"description": "SSO plugin for Better Auth",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -56,12 +56,12 @@
|
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@xmldom/xmldom": "^0.9.
|
|
59
|
+
"@xmldom/xmldom": "^0.9.12",
|
|
60
60
|
"fast-xml-parser": "^5.8.0",
|
|
61
61
|
"jose": "^6.2.3",
|
|
62
62
|
"samlify": "^2.13.1",
|
|
63
63
|
"tldts": "^7.4.3",
|
|
64
|
-
"zod": "^4.
|
|
64
|
+
"zod": "^4.5.4"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@types/body-parser": "^1.19.6",
|
|
@@ -72,16 +72,16 @@
|
|
|
72
72
|
"kysely": "^0.28.17 || ^0.29.0",
|
|
73
73
|
"oauth2-mock-server": "^9.0.0",
|
|
74
74
|
"tsdown": "0.21.10",
|
|
75
|
-
"@better-auth/core": "1.7.
|
|
76
|
-
"@better-auth/kysely-adapter": "1.7.
|
|
77
|
-
"better-auth": "1.7.
|
|
75
|
+
"@better-auth/core": "1.7.3",
|
|
76
|
+
"@better-auth/kysely-adapter": "1.7.3",
|
|
77
|
+
"better-auth": "1.7.3"
|
|
78
78
|
},
|
|
79
79
|
"peerDependencies": {
|
|
80
80
|
"@better-auth/utils": "0.4.2",
|
|
81
81
|
"@better-fetch/fetch": "1.3.1",
|
|
82
82
|
"better-call": "1.4.0",
|
|
83
|
-
"@better-auth/core": "^1.7.
|
|
84
|
-
"better-auth": "^1.7.
|
|
83
|
+
"@better-auth/core": "^1.7.3",
|
|
84
|
+
"better-auth": "^1.7.3"
|
|
85
85
|
},
|
|
86
86
|
"scripts": {
|
|
87
87
|
"build": "tsdown",
|