@better-auth/sso 1.4.8-beta.7 → 1.4.8

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @better-auth/sso@1.4.8-beta.7 build /home/runner/work/better-auth/better-auth/packages/sso
2
+ > @better-auth/sso@1.4.8 build /home/runner/work/better-auth/better-auth/packages/sso
3
3
  > tsdown
4
4
 
5
5
  ℹ tsdown v0.17.2 powered by rolldown v1.0.0-beta.53
@@ -7,10 +7,10 @@
7
7
  ℹ entry: src/index.ts, src/client.ts
8
8
  ℹ tsconfig: tsconfig.json
9
9
  ℹ Build start
10
- ℹ dist/index.mjs 92.65 kB │ gzip: 18.13 kB
10
+ ℹ dist/index.mjs 92.73 kB │ gzip: 18.16 kB
11
11
  ℹ dist/client.mjs  0.15 kB │ gzip: 0.14 kB
12
12
  ℹ dist/index.d.mts  1.48 kB │ gzip: 0.51 kB
13
13
  ℹ dist/client.d.mts  0.49 kB │ gzip: 0.30 kB
14
- ℹ dist/index-DNWhGQW-.d.mts 42.86 kB │ gzip: 8.79 kB
15
- ℹ 5 files, total: 137.63 kB
16
- ✔ Build complete in 16370ms
14
+ ℹ dist/index-ZWFEs7WQ.d.mts 42.70 kB │ gzip: 8.67 kB
15
+ ℹ 5 files, total: 137.55 kB
16
+ ✔ Build complete in 15873ms
package/dist/client.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as SSOPlugin } from "./index-DNWhGQW-.mjs";
1
+ import { t as SSOPlugin } from "./index-ZWFEs7WQ.mjs";
2
2
 
3
3
  //#region src/client.d.ts
4
4
  interface SSOClientOptions {
@@ -257,13 +257,7 @@ interface SSOOptions {
257
257
  *
258
258
  * If you want to allow account linking for specific trusted providers, enable the `accountLinking` option in your auth config and specify those
259
259
  * providers in the `trustedProviders` list.
260
- *
261
260
  * @default false
262
- *
263
- * @deprecated This option is discouraged for new projects. Relying on provider-level `email_verified` is a weaker
264
- * trust signal compared to using `trustedProviders` in `accountLinking` or enabling `domainVerification` for SSO.
265
- * Existing configurations will continue to work, but new integrations should use explicit trust mechanisms.
266
- * This option may be removed in a future major version.
267
261
  */
268
262
  trustEmailVerified?: boolean | undefined;
269
263
  /**
@@ -776,9 +770,17 @@ declare const registerSSOProvider: <O extends SSOOptions>(options: O) => better_
776
770
  }, O["domainVerification"] extends {
777
771
  enabled: true;
778
772
  } ? {
773
+ redirectURI: string;
774
+ oidcConfig: OIDCConfig | null;
775
+ samlConfig: SAMLConfig | null;
776
+ } & Omit<SSOProvider<O>, "oidcConfig" | "samlConfig"> & {
779
777
  domainVerified: boolean;
780
778
  domainVerificationToken: string;
781
- } & SSOProvider<O> : SSOProvider<O>>;
779
+ } : {
780
+ redirectURI: string;
781
+ oidcConfig: OIDCConfig | null;
782
+ samlConfig: SAMLConfig | null;
783
+ } & Omit<SSOProvider<O>, "oidcConfig" | "samlConfig">>;
782
784
  declare const signInSSO: (options?: SSOOptions) => better_call0.StrictEndpoint<"/sign-in/sso", {
783
785
  method: "POST";
784
786
  body: z.ZodObject<{
package/dist/index.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { A as KeyEncryptionAlgorithm, C as SAMLConfig, D as DataEncryptionAlgorithm, E as AlgorithmValidationOptions, O as DeprecatedAlgorithmBehavior, S as OIDCConfig, T as SSOProvider, _ 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 SignatureAlgorithm, k as DigestAlgorithm, l as selectTokenEndpointAuthMethod, m as DiscoveryErrorCode, n as sso, o as needsRuntimeDiscovery, p as DiscoveryError, r as computeDiscoveryUrl, s as normalizeDiscoveryUrls, t as SSOPlugin, u as validateDiscoveryDocument, v as RequiredDiscoveryField, w as SSOOptions, x as validateSAMLTimestamp, y as SAMLConditions } from "./index-DNWhGQW-.mjs";
1
+ import { A as KeyEncryptionAlgorithm, C as SAMLConfig, D as DataEncryptionAlgorithm, E as AlgorithmValidationOptions, O as DeprecatedAlgorithmBehavior, S as OIDCConfig, T as SSOProvider, _ 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 SignatureAlgorithm, k as DigestAlgorithm, l as selectTokenEndpointAuthMethod, m as DiscoveryErrorCode, n as sso, o as needsRuntimeDiscovery, p as DiscoveryError, r as computeDiscoveryUrl, s as normalizeDiscoveryUrls, t as SSOPlugin, u as validateDiscoveryDocument, v as RequiredDiscoveryField, w as SSOOptions, x as validateSAMLTimestamp, y as SAMLConditions } from "./index-ZWFEs7WQ.mjs";
2
2
  export { AlgorithmValidationOptions, DataEncryptionAlgorithm, DeprecatedAlgorithmBehavior, DigestAlgorithm, DiscoverOIDCConfigParams, DiscoveryError, DiscoveryErrorCode, HydratedOIDCConfig, KeyEncryptionAlgorithm, OIDCConfig, OIDCDiscoveryDocument, REQUIRED_DISCOVERY_FIELDS, RequiredDiscoveryField, SAMLConditions, SAMLConfig, SSOOptions, SSOPlugin, SSOProvider, SignatureAlgorithm, TimestampValidationOptions, computeDiscoveryUrl, discoverOIDCConfig, fetchDiscoveryDocument, needsRuntimeDiscovery, normalizeDiscoveryUrls, normalizeUrl, selectTokenEndpointAuthMethod, sso, validateDiscoveryDocument, validateDiscoveryUrl, validateSAMLTimestamp };
package/dist/index.mjs CHANGED
@@ -4,6 +4,7 @@ import * as saml from "samlify";
4
4
  import { generateRandomString } from "better-auth/crypto";
5
5
  import * as z$1 from "zod/v4";
6
6
  import z from "zod/v4";
7
+ import { base64 } from "@better-auth/utils/base64";
7
8
  import { BetterFetchError, betterFetch } from "@better-fetch/fetch";
8
9
  import { HIDE_METADATA, createAuthorizationURL, generateState, parseState, validateAuthorizationCode, validateToken } from "better-auth";
9
10
  import { setSessionCookie } from "better-auth/cookies";
@@ -1297,14 +1298,15 @@ const registerSSOProvider = (options) => {
1297
1298
  }
1298
1299
  });
1299
1300
  }
1300
- return ctx.json({
1301
+ const result = {
1301
1302
  ...provider,
1302
1303
  oidcConfig: safeJsonParse(provider.oidcConfig),
1303
1304
  samlConfig: safeJsonParse(provider.samlConfig),
1304
1305
  redirectURI: `${ctx.context.baseURL}/sso/callback/${provider.providerId}`,
1305
1306
  ...options?.domainVerification?.enabled ? { domainVerified } : {},
1306
1307
  ...options?.domainVerification?.enabled ? { domainVerificationToken } : {}
1307
- });
1308
+ };
1309
+ return ctx.json(result);
1308
1310
  });
1309
1311
  };
1310
1312
  const signInSSOBodySchema = z.object({
@@ -1782,7 +1784,7 @@ const callbackSSOSAML = (options) => {
1782
1784
  } catch (error) {
1783
1785
  ctx.context.logger.error("SAML response validation failed", {
1784
1786
  error,
1785
- decodedResponse: Buffer.from(SAMLResponse, "base64").toString("utf-8")
1787
+ decodedResponse: new TextDecoder().decode(base64.decode(SAMLResponse))
1786
1788
  });
1787
1789
  throw new APIError("BAD_REQUEST", {
1788
1790
  message: "Invalid SAML response",
@@ -2016,7 +2018,7 @@ const acsEndpoint = (options) => {
2016
2018
  } catch (error) {
2017
2019
  ctx.context.logger.error("SAML response validation failed", {
2018
2020
  error,
2019
- decodedResponse: Buffer.from(SAMLResponse, "base64").toString("utf-8")
2021
+ decodedResponse: new TextDecoder().decode(base64.decode(SAMLResponse))
2020
2022
  });
2021
2023
  throw new APIError("BAD_REQUEST", {
2022
2024
  message: "Invalid SAML response",
@@ -2067,7 +2069,7 @@ const acsEndpoint = (options) => {
2067
2069
  throw ctx.redirect(`${redirectUrl}?error=unsolicited_response&error_description=IdP-initiated+SSO+not+allowed`);
2068
2070
  }
2069
2071
  }
2070
- const assertionIdAcs = extractAssertionId(Buffer.from(SAMLResponse, "base64").toString("utf-8"));
2072
+ const assertionIdAcs = extractAssertionId(new TextDecoder().decode(base64.decode(SAMLResponse)));
2071
2073
  if (assertionIdAcs) {
2072
2074
  const issuer = idp.entityMeta.getEntityID();
2073
2075
  const conditions = extract.conditions;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@better-auth/sso",
3
3
  "author": "Bereket Engida",
4
- "version": "1.4.8-beta.7",
4
+ "version": "1.4.8",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
7
7
  "types": "dist/index.d.mts",
@@ -52,6 +52,7 @@
52
52
  }
53
53
  },
54
54
  "dependencies": {
55
+ "@better-auth/utils": "0.3.0",
55
56
  "@better-fetch/fetch": "1.1.21",
56
57
  "fast-xml-parser": "^5.2.5",
57
58
  "jose": "^6.1.0",
@@ -66,10 +67,10 @@
66
67
  "express": "^5.1.0",
67
68
  "oauth2-mock-server": "^8.2.0",
68
69
  "tsdown": "^0.17.2",
69
- "better-auth": "1.4.8-beta.7"
70
+ "better-auth": "1.4.8"
70
71
  },
71
72
  "peerDependencies": {
72
- "better-auth": "1.4.8-beta.7"
73
+ "better-auth": "1.4.8"
73
74
  },
74
75
  "scripts": {
75
76
  "test": "vitest",
package/src/index.ts CHANGED
@@ -153,7 +153,7 @@ export function sso<O extends SSOOptions>(options?: O | undefined): any {
153
153
  return;
154
154
  }
155
155
 
156
- await assignOrganizationByDomain(ctx, {
156
+ await assignOrganizationByDomain(ctx as any, {
157
157
  user: newSession.user,
158
158
  provisioningOptions: options?.organizationProvisioning,
159
159
  domainVerification: options?.domainVerification,
@@ -1,7 +1,25 @@
1
- import type { GenericEndpointContext, OAuth2Tokens, User } from "better-auth";
1
+ import type { OAuth2Tokens, User } from "better-auth";
2
2
  import type { SSOOptions, SSOProvider } from "../types";
3
3
  import type { NormalizedSSOProfile } from "./types";
4
4
 
5
+ interface EndpointContext {
6
+ context: {
7
+ options: {
8
+ plugins?: Array<{ id: string }>;
9
+ };
10
+ adapter: {
11
+ findOne: <T>(options: {
12
+ model: string;
13
+ where: Array<{ field: string; value: unknown }>;
14
+ }) => Promise<T | null>;
15
+ create: (options: {
16
+ model: string;
17
+ data: Record<string, unknown>;
18
+ }) => Promise<unknown>;
19
+ };
20
+ };
21
+ }
22
+
5
23
  export interface OrganizationProvisioningOptions {
6
24
  disabled?: boolean;
7
25
  defaultRole?: "member" | "admin";
@@ -26,7 +44,7 @@ export interface AssignOrganizationFromProviderOptions {
26
44
  * Used in SSO flows (OIDC, SAML) where the provider is already linked to an org.
27
45
  */
28
46
  export async function assignOrganizationFromProvider(
29
- ctx: GenericEndpointContext,
47
+ ctx: EndpointContext,
30
48
  options: AssignOrganizationFromProviderOptions,
31
49
  ): Promise<void> {
32
50
  const { user, profile, provider, token, provisioningOptions } = options;
@@ -96,7 +114,7 @@ export interface AssignOrganizationByDomainOptions {
96
114
  * (e.g., Google OAuth with @acme.com email gets added to Acme's org).
97
115
  */
98
116
  export async function assignOrganizationByDomain(
99
- ctx: GenericEndpointContext,
117
+ ctx: EndpointContext,
100
118
  options: AssignOrganizationByDomainOptions,
101
119
  ): Promise<void> {
102
120
  const { user, provisioningOptions, domainVerification } = options;
package/src/routes/sso.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { base64 } from "@better-auth/utils/base64";
1
2
  import { BetterFetchError, betterFetch } from "@better-fetch/fetch";
2
3
  import type { User, Verification } from "better-auth";
3
4
  import {
@@ -836,14 +837,20 @@ export const registerSSOProvider = <O extends SSOOptions>(options: O) => {
836
837
  });
837
838
  }
838
839
 
840
+ type SSOProviderResponse = {
841
+ redirectURI: string;
842
+ oidcConfig: OIDCConfig | null;
843
+ samlConfig: SAMLConfig | null;
844
+ } & Omit<SSOProvider<O>, "oidcConfig" | "samlConfig">;
845
+
839
846
  type SSOProviderReturn = O["domainVerification"] extends { enabled: true }
840
- ? {
847
+ ? SSOProviderResponse & {
841
848
  domainVerified: boolean;
842
849
  domainVerificationToken: string;
843
- } & SSOProvider<O>
844
- : SSOProvider<O>;
850
+ }
851
+ : SSOProviderResponse;
845
852
 
846
- return ctx.json({
853
+ const result = {
847
854
  ...provider,
848
855
  oidcConfig: safeJsonParse<OIDCConfig>(
849
856
  provider.oidcConfig as unknown as string,
@@ -856,7 +863,9 @@ export const registerSSOProvider = <O extends SSOOptions>(options: O) => {
856
863
  ...(options?.domainVerification?.enabled
857
864
  ? { domainVerificationToken }
858
865
  : {}),
859
- } as unknown as SSOProviderReturn);
866
+ };
867
+
868
+ return ctx.json(result as SSOProviderReturn);
860
869
  },
861
870
  );
862
871
  };
@@ -1807,8 +1816,8 @@ export const callbackSSOSAML = (options?: SSOOptions) => {
1807
1816
  } catch (error) {
1808
1817
  ctx.context.logger.error("SAML response validation failed", {
1809
1818
  error,
1810
- decodedResponse: Buffer.from(SAMLResponse, "base64").toString(
1811
- "utf-8",
1819
+ decodedResponse: new TextDecoder().decode(
1820
+ base64.decode(SAMLResponse),
1812
1821
  ),
1813
1822
  });
1814
1823
  throw new APIError("BAD_REQUEST", {
@@ -2237,8 +2246,8 @@ export const acsEndpoint = (options?: SSOOptions) => {
2237
2246
  } catch (error) {
2238
2247
  ctx.context.logger.error("SAML response validation failed", {
2239
2248
  error,
2240
- decodedResponse: Buffer.from(SAMLResponse, "base64").toString(
2241
- "utf-8",
2249
+ decodedResponse: new TextDecoder().decode(
2250
+ base64.decode(SAMLResponse),
2242
2251
  ),
2243
2252
  });
2244
2253
  throw new APIError("BAD_REQUEST", {
@@ -2334,8 +2343,8 @@ export const acsEndpoint = (options?: SSOOptions) => {
2334
2343
  }
2335
2344
 
2336
2345
  // Assertion Replay Protection
2337
- const samlContentAcs = Buffer.from(SAMLResponse, "base64").toString(
2338
- "utf-8",
2346
+ const samlContentAcs = new TextDecoder().decode(
2347
+ base64.decode(SAMLResponse),
2339
2348
  );
2340
2349
  const assertionIdAcs = extractAssertionId(samlContentAcs);
2341
2350
 
package/src/types.ts CHANGED
@@ -231,13 +231,7 @@ export interface SSOOptions {
231
231
  *
232
232
  * If you want to allow account linking for specific trusted providers, enable the `accountLinking` option in your auth config and specify those
233
233
  * providers in the `trustedProviders` list.
234
- *
235
234
  * @default false
236
- *
237
- * @deprecated This option is discouraged for new projects. Relying on provider-level `email_verified` is a weaker
238
- * trust signal compared to using `trustedProviders` in `accountLinking` or enabling `domainVerification` for SSO.
239
- * Existing configurations will continue to work, but new integrations should use explicit trust mechanisms.
240
- * This option may be removed in a future major version.
241
235
  */
242
236
  trustEmailVerified?: boolean | undefined;
243
237
  /**