@better-auth/sso 1.7.1 → 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
@@ -1,4 +1,4 @@
1
- import { t as SSOPlugin } from "./index-CZytzKv6.mjs";
1
+ import { t as SSOPlugin } from "./index-sM6JWXeV.mjs";
2
2
  import { DBFieldAttribute } from "better-auth/db";
3
3
 
4
4
  //#region src/client.d.ts
package/dist/client.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as PACKAGE_VERSION } from "./version-BbG1DbY-.mjs";
1
+ import { t as PACKAGE_VERSION } from "./version-Cj0SVRl5.mjs";
2
2
  //#region src/client.ts
3
3
  const ssoClient = (options) => {
4
4
  return {
@@ -1511,7 +1511,7 @@ declare const callbackSSO: (options?: SSOOptions) => _$better_call0.StrictEndpoi
1511
1511
  };
1512
1512
  scope: "server";
1513
1513
  };
1514
- }, void>;
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
- }, void>;
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-CZytzKv6.mjs";
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-BbG1DbY-.mjs";
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 errorURL = ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`;
3800
- throw ctx.redirect(`${errorURL}?error=invalid_state`);
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
- error,
3808
- error_description: description
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) throw ctx.redirect(`${errorURL || callbackURL}?error=invalid_provider&error_description=provider not found`);
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) throw ctx.redirect(`${errorURL || callbackURL}?error=invalid_provider&error_description=provider not found`);
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) throw ctx.redirect(`${errorURL || callbackURL}?error=discovery_failed&error_description=${encodeURIComponent(error.message)}`);
3825
- throw ctx.redirect(`${errorURL || callbackURL}?error=discovery_failed&error_description=unexpected_discovery_error`);
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) throw ctx.redirect(`${errorURL || callbackURL}?error=invalid_provider&error_description=token_endpoint_not_found`);
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) throw ctx.redirect(`${errorURL || callbackURL}?error=invalid_provider&error_description=no_private_key_available`);
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) throw ctx.redirect(`${errorURL || callbackURL}?error=invalid_provider&error_description=token_response_not_found`);
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 throw ctx.redirect(`${errorURL || callbackURL}?error=invalid_provider&error_description=user_info_endpoint_not_found`);
3940
- if (!userInfo.email || !userInfo.id) throw ctx.redirect(`${errorURL || callbackURL}?error=invalid_provider&error_description=missing_user_info`);
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
- const baseURL = errorURL || callbackURL;
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 errorURL = ctx.context.options.onAPIError?.errorURL || `${ctx.context.baseURL}/error`;
4193
- throw ctx.redirect(`${errorURL}?error=invalid_state`);
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 errorURL = stateData.errorURL || stateData.callbackURL;
4198
- throw ctx.redirect(`${errorURL}?error=invalid_state&error_description=missing_sso_provider_reference`);
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 errorURL = ctx.context.options.onAPIError?.errorURL || `${appOrigin}/error`;
4234
- throw ctx.redirect(`${errorURL}?error=invalid_request`);
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) throw ctx.redirect(`${safeErrorURL}?error=invalid_request&error_description=missing_logout_data`);
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;
@@ -1,5 +1,5 @@
1
1
  //#endregion
2
2
  //#region src/version.ts
3
- const PACKAGE_VERSION = "1.7.1";
3
+ const PACKAGE_VERSION = "1.7.2";
4
4
  //#endregion
5
5
  export { PACKAGE_VERSION as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth/sso",
3
- "version": "1.7.1",
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.1",
76
- "@better-auth/kysely-adapter": "1.7.1",
77
- "better-auth": "1.7.1"
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
- "@better-auth/core": "^1.7.1",
84
- "better-auth": "^1.7.1"
83
+ "better-auth": "^1.7.2",
84
+ "@better-auth/core": "^1.7.2"
85
85
  },
86
86
  "scripts": {
87
87
  "build": "tsdown",