@better-auth/sso 1.7.0 → 1.7.2
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-Cj0SVRl5.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";
|
|
@@ -3796,33 +3797,31 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
|
|
|
3796
3797
|
const { code, error, error_description } = ctx.query;
|
|
3797
3798
|
if (!stateData) stateData = await parseState(ctx);
|
|
3798
3799
|
if (!stateData) {
|
|
3799
|
-
const
|
|
3800
|
-
throw ctx.redirect(
|
|
3800
|
+
const redirectURL = appendQueryParams(ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`, new URLSearchParams({ error: "invalid_state" }));
|
|
3801
|
+
throw ctx.redirect(redirectURL);
|
|
3801
3802
|
}
|
|
3802
3803
|
const providerReference = parsedProviderReference ?? parseSSOProviderReference(stateData.serverContext?.["ssoProviderReference"]);
|
|
3803
3804
|
const { callbackURL, errorURL, newUserURL, requestSignUp } = stateData;
|
|
3804
3805
|
const redirectOIDCError = (error, description) => {
|
|
3805
3806
|
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()}`);
|
|
3807
|
+
const params = new URLSearchParams({ error });
|
|
3808
|
+
if (description) params.set("error_description", description);
|
|
3809
|
+
const redirectURL = appendQueryParams(baseURL, params);
|
|
3810
|
+
throw ctx.redirect(redirectURL);
|
|
3812
3811
|
};
|
|
3813
|
-
if (!code || error) redirectOIDCError(error || "invalid_request", error_description || (error ? error : "authorization_code_not_found"));
|
|
3812
|
+
if (!code || error) return redirectOIDCError(error || "invalid_request", error_description || (error ? error : "authorization_code_not_found"));
|
|
3814
3813
|
const provider = await resolveOIDCProvider(ctx, options, providerId);
|
|
3815
|
-
if (!provider)
|
|
3814
|
+
if (!provider) return redirectOIDCError("invalid_provider", "provider not found");
|
|
3816
3815
|
const acceptedProviderReference = providerReference ?? redirectOIDCError("invalid_state", "missing_sso_provider_reference");
|
|
3817
|
-
if (!await isCurrentSSOProviderReference(provider, acceptedProviderReference)) redirectOIDCError("invalid_state", "sso_provider_changed_during_authentication");
|
|
3816
|
+
if (!await isCurrentSSOProviderReference(provider, acceptedProviderReference)) return redirectOIDCError("invalid_state", "sso_provider_changed_during_authentication");
|
|
3818
3817
|
if (options?.domainVerification?.enabled && !("domainVerified" in provider && provider.domainVerified)) throw new APIError("UNAUTHORIZED", { message: "Provider domain has not been verified" });
|
|
3819
3818
|
let config = provider.oidcConfig;
|
|
3820
|
-
if (!config)
|
|
3819
|
+
if (!config) return redirectOIDCError("invalid_provider", "provider not found");
|
|
3821
3820
|
try {
|
|
3822
3821
|
config = await ensureRuntimeDiscovery(config, provider.issuer, (url) => ctx.context.isTrustedOrigin(url));
|
|
3823
3822
|
} catch (error) {
|
|
3824
|
-
if (error instanceof DiscoveryError)
|
|
3825
|
-
|
|
3823
|
+
if (error instanceof DiscoveryError) return redirectOIDCError("discovery_failed", error.message);
|
|
3824
|
+
return redirectOIDCError("discovery_failed", "unexpected_discovery_error");
|
|
3826
3825
|
}
|
|
3827
3826
|
if (!config.scopes) config = {
|
|
3828
3827
|
...config,
|
|
@@ -3833,7 +3832,7 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
|
|
|
3833
3832
|
"offline_access"
|
|
3834
3833
|
]
|
|
3835
3834
|
};
|
|
3836
|
-
if (!config.tokenEndpoint)
|
|
3835
|
+
if (!config.tokenEndpoint) return redirectOIDCError("invalid_provider", "token_endpoint_not_found");
|
|
3837
3836
|
const tokenEndpoint = config.tokenEndpoint;
|
|
3838
3837
|
let tokenEndpointAuth = config.tokenEndpointAuthentication === "client_secret_post" ? { method: "client_secret_post" } : { method: "client_secret_basic" };
|
|
3839
3838
|
if (config.tokenEndpointAuthentication === "private_key_jwt") {
|
|
@@ -3845,7 +3844,7 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
|
|
|
3845
3844
|
keyId: config.privateKeyId,
|
|
3846
3845
|
issuer: config.issuer
|
|
3847
3846
|
});
|
|
3848
|
-
if (!resolved || !resolved.privateKeyJwk && !resolved.privateKeyPem)
|
|
3847
|
+
if (!resolved || !resolved.privateKeyJwk && !resolved.privateKeyPem) return redirectOIDCError("invalid_provider", "no_private_key_available");
|
|
3849
3848
|
const rawAlg = config.privateKeyAlgorithm ?? resolved.algorithm;
|
|
3850
3849
|
const algorithm = rawAlg && PRIVATE_KEY_JWT_SIGNING_ALGORITHMS.includes(rawAlg) ? rawAlg : void 0;
|
|
3851
3850
|
tokenEndpointAuth = {
|
|
@@ -3874,16 +3873,16 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
|
|
|
3874
3873
|
body,
|
|
3875
3874
|
headers
|
|
3876
3875
|
}, (url) => ctx.context.isTrustedOrigin(url));
|
|
3877
|
-
if (error) redirectOIDCError("invalid_provider", getOIDCErrorDescription(error, "token_response_error"));
|
|
3876
|
+
if (error) return redirectOIDCError("invalid_provider", getOIDCErrorDescription(error, "token_response_error"));
|
|
3878
3877
|
if (!data) throw new Error("Token endpoint returned an empty response");
|
|
3879
3878
|
return getOAuth2Tokens(data);
|
|
3880
3879
|
})().catch((e) => {
|
|
3881
3880
|
if (isAPIError(e)) throw e;
|
|
3882
3881
|
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"));
|
|
3882
|
+
if (e instanceof DiscoveryError) return redirectOIDCError("invalid_provider", e.message);
|
|
3883
|
+
return redirectOIDCError("invalid_provider", getOIDCErrorDescription(e, "token_response_error"));
|
|
3885
3884
|
});
|
|
3886
|
-
if (!tokenResponse)
|
|
3885
|
+
if (!tokenResponse) return redirectOIDCError("invalid_provider", "token_response_not_found");
|
|
3887
3886
|
let userInfo = null;
|
|
3888
3887
|
const mapping = config.mapping || {};
|
|
3889
3888
|
const readStringClaim = (claims, claim) => {
|
|
@@ -3894,28 +3893,28 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
|
|
|
3894
3893
|
let verifiedIdToken = null;
|
|
3895
3894
|
if (tokenResponse.idToken) {
|
|
3896
3895
|
const jwksEndpoint = config.jwksEndpoint;
|
|
3897
|
-
if (!jwksEndpoint) redirectOIDCError("invalid_provider", "jwks_endpoint_not_found");
|
|
3896
|
+
if (!jwksEndpoint) return redirectOIDCError("invalid_provider", "jwks_endpoint_not_found");
|
|
3898
3897
|
const verified = await validateOIDCIdToken(tokenResponse.idToken, jwksEndpoint, {
|
|
3899
3898
|
audience: config.clientId,
|
|
3900
3899
|
issuer: provider.issuer
|
|
3901
3900
|
}, (url) => ctx.context.isTrustedOrigin(url)).catch((error) => {
|
|
3902
|
-
if (error instanceof DiscoveryError) redirectOIDCError("invalid_provider", error.message);
|
|
3901
|
+
if (error instanceof DiscoveryError) return redirectOIDCError("invalid_provider", error.message);
|
|
3903
3902
|
ctx.context.logger.error(error);
|
|
3904
3903
|
return null;
|
|
3905
3904
|
});
|
|
3906
|
-
if (!verified) redirectOIDCError("invalid_provider", "token_not_verified");
|
|
3907
|
-
if (!readStringClaim(verified.payload, "sub")) redirectOIDCError("invalid_provider", "id_token_subject_missing");
|
|
3905
|
+
if (!verified) return redirectOIDCError("invalid_provider", "token_not_verified");
|
|
3906
|
+
if (!readStringClaim(verified.payload, "sub")) return redirectOIDCError("invalid_provider", "id_token_subject_missing");
|
|
3908
3907
|
verifiedIdToken = verified;
|
|
3909
3908
|
}
|
|
3910
|
-
if (options?.resolveUser && !verifiedIdToken) redirectOIDCError("invalid_provider", "id_token_required_for_user_resolution");
|
|
3909
|
+
if (options?.resolveUser && !verifiedIdToken) return redirectOIDCError("invalid_provider", "id_token_required_for_user_resolution");
|
|
3911
3910
|
if (config.userInfoEndpoint) {
|
|
3912
3911
|
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);
|
|
3912
|
+
if (e instanceof DiscoveryError) return redirectOIDCError("invalid_provider", e.message);
|
|
3914
3913
|
throw e;
|
|
3915
3914
|
});
|
|
3916
|
-
if (userInfoResponse.error) redirectOIDCError("invalid_provider", userInfoResponse.error.message || userInfoResponse.error.statusText || "userinfo_response_error");
|
|
3915
|
+
if (userInfoResponse.error) return redirectOIDCError("invalid_provider", userInfoResponse.error.message || userInfoResponse.error.statusText || "userinfo_response_error");
|
|
3917
3916
|
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");
|
|
3917
|
+
if (verifiedIdToken && rawUserInfo.sub !== verifiedIdToken.payload.sub) return redirectOIDCError("invalid_provider", "id_token_userinfo_subject_mismatch");
|
|
3919
3918
|
rawProfile = rawUserInfo;
|
|
3920
3919
|
userInfo = {
|
|
3921
3920
|
...Object.fromEntries(Object.entries(mapping.extraFields || {}).map(([key, value]) => [key, rawUserInfo[value]])),
|
|
@@ -3936,8 +3935,8 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
|
|
|
3936
3935
|
name: readStringClaim(idToken, mapping.name || "name"),
|
|
3937
3936
|
image: readStringClaim(idToken, mapping.image || "picture")
|
|
3938
3937
|
};
|
|
3939
|
-
} else
|
|
3940
|
-
if (!userInfo.email || !userInfo.id)
|
|
3938
|
+
} else return redirectOIDCError("invalid_provider", "user_info_endpoint_not_found");
|
|
3939
|
+
if (!userInfo.email || !userInfo.id) return redirectOIDCError("invalid_provider", "missing_user_info");
|
|
3941
3940
|
const userInfoEmail = userInfo.email;
|
|
3942
3941
|
const userInfoId = userInfo.id;
|
|
3943
3942
|
const providerUser = {
|
|
@@ -4025,20 +4024,10 @@ async function handleOIDCCallback(ctx, options, providerId, stateData, parsedPro
|
|
|
4025
4024
|
} catch (e) {
|
|
4026
4025
|
const failedAuthentication = getFailedSSOAuthenticationResult(e);
|
|
4027
4026
|
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()}`);
|
|
4027
|
+
else if (isAPIError(e) && e.body?.code) return redirectOIDCError(e.body.code, e.body.message);
|
|
4028
|
+
else throw e;
|
|
4041
4029
|
}
|
|
4030
|
+
if (linked.error) return redirectOIDCError(linked.error);
|
|
4042
4031
|
const { session, user } = linked.data;
|
|
4043
4032
|
if (options?.provisionUser && (linked.isRegister || options.provisionUserOnEveryLogin)) await options.provisionUser({
|
|
4044
4033
|
user,
|
|
@@ -4189,13 +4178,16 @@ const callbackSSOShared = (options) => {
|
|
|
4189
4178
|
}, async (ctx) => {
|
|
4190
4179
|
const stateData = await parseState(ctx);
|
|
4191
4180
|
if (!stateData) {
|
|
4192
|
-
const
|
|
4193
|
-
throw ctx.redirect(
|
|
4181
|
+
const redirectURL = appendQueryParams(ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`, new URLSearchParams({ error: "invalid_state" }));
|
|
4182
|
+
throw ctx.redirect(redirectURL);
|
|
4194
4183
|
}
|
|
4195
4184
|
const providerReference = parseSSOProviderReference(stateData.serverContext?.[SSO_PROVIDER_STATE_KEY]);
|
|
4196
4185
|
if (!providerReference) {
|
|
4197
|
-
const
|
|
4198
|
-
|
|
4186
|
+
const redirectURL = appendQueryParams(stateData.errorURL || stateData.callbackURL, new URLSearchParams({
|
|
4187
|
+
error: "invalid_state",
|
|
4188
|
+
error_description: "missing_sso_provider_reference"
|
|
4189
|
+
}));
|
|
4190
|
+
throw ctx.redirect(redirectURL);
|
|
4199
4191
|
}
|
|
4200
4192
|
return handleOIDCCallback(ctx, options, providerReference.providerId, stateData, providerReference);
|
|
4201
4193
|
});
|
|
@@ -4230,8 +4222,8 @@ const acsEndpoint = (options) => {
|
|
|
4230
4222
|
let resolvedErrorRedirectUrl;
|
|
4231
4223
|
if (ctx.method === "GET" && !ctx.body?.SAMLResponse) {
|
|
4232
4224
|
if (!(await getSessionFromCtx(ctx))?.session) {
|
|
4233
|
-
const
|
|
4234
|
-
throw ctx.redirect(
|
|
4225
|
+
const redirectURL = appendQueryParams(ctx.context.options.onAPIError?.errorURL || `${appOrigin}/error`, new URLSearchParams({ error: "invalid_request" }));
|
|
4226
|
+
throw ctx.redirect(redirectURL);
|
|
4235
4227
|
}
|
|
4236
4228
|
const relayState = ctx.query?.RelayState;
|
|
4237
4229
|
throw ctx.redirect(getSafeRedirectUrl([relayState], currentCallbackPath, appOrigin, (url, settings) => ctx.context.isTrustedOrigin(url, settings)));
|
|
@@ -4298,7 +4290,13 @@ const sloEndpoint = (options) => {
|
|
|
4298
4290
|
const relayState = ctx.body?.RelayState || ctx.query?.RelayState;
|
|
4299
4291
|
const appOrigin = new URL(ctx.context.baseURL).origin;
|
|
4300
4292
|
const safeErrorURL = getSafeRedirectUrl([relayState], `${appOrigin}/sso/saml2/sp/slo/${providerId}`, appOrigin, (url, settings) => ctx.context.isTrustedOrigin(url, settings));
|
|
4301
|
-
if (!samlRequest && !samlResponse)
|
|
4293
|
+
if (!samlRequest && !samlResponse) {
|
|
4294
|
+
const redirectURL = appendQueryParams(safeErrorURL, new URLSearchParams({
|
|
4295
|
+
error: "invalid_request",
|
|
4296
|
+
error_description: "missing_logout_data"
|
|
4297
|
+
}));
|
|
4298
|
+
throw ctx.redirect(redirectURL);
|
|
4299
|
+
}
|
|
4302
4300
|
const provider = await findSAMLProvider(providerId, options, ctx.context.adapter);
|
|
4303
4301
|
if (!provider?.samlConfig) throw APIError.from("NOT_FOUND", SAML_ERROR_CODES.SAML_PROVIDER_NOT_FOUND);
|
|
4304
4302
|
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.2",
|
|
4
4
|
"description": "SSO plugin for Better Auth",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -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.2",
|
|
76
|
+
"@better-auth/kysely-adapter": "1.7.2",
|
|
77
|
+
"better-auth": "1.7.2"
|
|
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
|
-
"
|
|
84
|
-
"better-auth": "^1.7.
|
|
83
|
+
"better-auth": "^1.7.2",
|
|
84
|
+
"@better-auth/core": "^1.7.2"
|
|
85
85
|
},
|
|
86
86
|
"scripts": {
|
|
87
87
|
"build": "tsdown",
|