@better-auth/sso 1.5.0-beta.13 → 1.5.0-beta.15

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.
@@ -459,11 +459,11 @@ describe("SSO provider read endpoints", () => {
459
459
  });
460
460
  });
461
461
 
462
- describe("GET /sso/providers/:providerId", () => {
462
+ describe("GET /sso/get-provider", () => {
463
463
  it("should return 401 when not authenticated", async () => {
464
464
  const { auth } = createTestAuth();
465
465
  const response = await auth.api.getSSOProvider({
466
- params: { providerId: "test" },
466
+ query: { providerId: "test" },
467
467
  asResponse: true,
468
468
  });
469
469
  expect(response.status).toBe(401);
@@ -478,7 +478,7 @@ describe("SSO provider read endpoints", () => {
478
478
  });
479
479
 
480
480
  const response = await auth.api.getSSOProvider({
481
- params: { providerId: "nonexistent" },
481
+ query: { providerId: "nonexistent" },
482
482
  headers,
483
483
  asResponse: true,
484
484
  });
@@ -504,7 +504,7 @@ describe("SSO provider read endpoints", () => {
504
504
  });
505
505
 
506
506
  const response = await auth.api.getSSOProvider({
507
- params: { providerId: "other-provider" },
507
+ query: { providerId: "other-provider" },
508
508
  headers: otherHeaders,
509
509
  asResponse: true,
510
510
  });
@@ -524,7 +524,7 @@ describe("SSO provider read endpoints", () => {
524
524
  await registerSAMLProvider(headers, "my-saml-provider");
525
525
 
526
526
  const response = await auth.api.getSSOProvider({
527
- params: { providerId: "my-saml-provider" },
527
+ query: { providerId: "my-saml-provider" },
528
528
  headers,
529
529
  });
530
530
 
@@ -559,7 +559,7 @@ describe("SSO provider read endpoints", () => {
559
559
  );
560
560
 
561
561
  const response = await auth.api.getSSOProvider({
562
- params: { providerId: "my-oidc-provider" },
562
+ query: { providerId: "my-oidc-provider" },
563
563
  headers,
564
564
  });
565
565
 
@@ -589,7 +589,7 @@ describe("SSO provider read endpoints", () => {
589
589
  createOIDCProviderData(user!.id, "my-oidc-provider", "client123");
590
590
 
591
591
  const response = await auth.api.getSSOProvider({
592
- params: { providerId: "my-oidc-provider" },
592
+ query: { providerId: "my-oidc-provider" },
593
593
  headers,
594
594
  });
595
595
 
@@ -629,7 +629,7 @@ describe("SSO provider read endpoints", () => {
629
629
  });
630
630
 
631
631
  const response = await auth.api.getSSOProvider({
632
- params: { providerId: "my-provider" },
632
+ query: { providerId: "my-provider" },
633
633
  headers,
634
634
  });
635
635
 
@@ -671,7 +671,7 @@ describe("SSO provider read endpoints", () => {
671
671
 
672
672
  // Owner should be able to access it since they created the org (are admin)
673
673
  const ownerResponse = await auth.api.getSSOProvider({
674
- params: { providerId: "user-owned-org-provider" },
674
+ query: { providerId: "user-owned-org-provider" },
675
675
  headers: ownerHeaders,
676
676
  });
677
677
 
@@ -685,7 +685,7 @@ describe("SSO provider read endpoints", () => {
685
685
  });
686
686
 
687
687
  const nonAdminResponse = await auth.api.getSSOProvider({
688
- params: { providerId: "user-owned-org-provider" },
688
+ query: { providerId: "user-owned-org-provider" },
689
689
  headers: nonAdminHeaders,
690
690
  asResponse: true,
691
691
  });
@@ -709,7 +709,7 @@ describe("SSO provider read endpoints", () => {
709
709
  await registerSAMLProvider(headers, "my-saml-provider");
710
710
 
711
711
  const response = await auth.api.getSSOProvider({
712
- params: { providerId: "my-saml-provider" },
712
+ query: { providerId: "my-saml-provider" },
713
713
  headers,
714
714
  });
715
715
 
@@ -745,7 +745,7 @@ describe("SSO provider read endpoints", () => {
745
745
  });
746
746
 
747
747
  const response = await auth.api.getSSOProvider({
748
- params: { providerId: "my-saml-provider" },
748
+ query: { providerId: "my-saml-provider" },
749
749
  headers,
750
750
  });
751
751
 
@@ -771,7 +771,7 @@ describe("SSO provider read endpoints", () => {
771
771
  createOIDCProviderData(user!.id, "my-oidc-provider", "abc");
772
772
 
773
773
  const response = await auth.api.getSSOProvider({
774
- params: { providerId: "my-oidc-provider" },
774
+ query: { providerId: "my-oidc-provider" },
775
775
  headers,
776
776
  });
777
777
 
@@ -779,12 +779,11 @@ describe("SSO provider read endpoints", () => {
779
779
  });
780
780
  });
781
781
 
782
- describe("PATCH /sso/providers/:providerId", () => {
782
+ describe("POST /sso/update-provider", () => {
783
783
  it("should return 401 when not authenticated", async () => {
784
784
  const { auth } = createTestAuth();
785
785
  const response = await auth.api.updateSSOProvider({
786
- params: { providerId: "test" },
787
- body: { domain: "new-domain.com" },
786
+ body: { providerId: "test", domain: "new-domain.com" },
788
787
  asResponse: true,
789
788
  });
790
789
  expect(response.status).toBe(401);
@@ -799,8 +798,7 @@ describe("SSO provider read endpoints", () => {
799
798
  });
800
799
 
801
800
  const response = await auth.api.updateSSOProvider({
802
- params: { providerId: "nonexistent" },
803
- body: { domain: "new-domain.com" },
801
+ body: { providerId: "nonexistent", domain: "new-domain.com" },
804
802
  headers,
805
803
  asResponse: true,
806
804
  });
@@ -826,8 +824,7 @@ describe("SSO provider read endpoints", () => {
826
824
  });
827
825
 
828
826
  const response = await auth.api.updateSSOProvider({
829
- params: { providerId: "other-provider" },
830
- body: { domain: "new-domain.com" },
827
+ body: { providerId: "other-provider", domain: "new-domain.com" },
831
828
  headers: otherHeaders,
832
829
  asResponse: true,
833
830
  });
@@ -849,8 +846,7 @@ describe("SSO provider read endpoints", () => {
849
846
  await registerSAMLProvider(headers, "my-saml-provider");
850
847
 
851
848
  const updated = await auth.api.updateSSOProvider({
852
- params: { providerId: "my-saml-provider" },
853
- body: { domain: "new-domain.com" },
849
+ body: { providerId: "my-saml-provider", domain: "new-domain.com" },
854
850
  headers,
855
851
  });
856
852
 
@@ -871,8 +867,8 @@ describe("SSO provider read endpoints", () => {
871
867
  await registerSAMLProvider(headers, "my-saml-provider");
872
868
 
873
869
  const updated = await auth.api.updateSSOProvider({
874
- params: { providerId: "my-saml-provider" },
875
870
  body: {
871
+ providerId: "my-saml-provider",
876
872
  samlConfig: {
877
873
  audience: "new-audience",
878
874
  wantAssertionsSigned: false,
@@ -904,8 +900,8 @@ describe("SSO provider read endpoints", () => {
904
900
  createOIDCProviderData(user!.id, "my-oidc-provider", "client123");
905
901
 
906
902
  const updated = await auth.api.updateSSOProvider({
907
- params: { providerId: "my-oidc-provider" },
908
903
  body: {
904
+ providerId: "my-oidc-provider",
909
905
  oidcConfig: {
910
906
  scopes: ["openid", "email", "profile", "custom"],
911
907
  pkce: false,
@@ -936,8 +932,10 @@ describe("SSO provider read endpoints", () => {
936
932
  await registerSAMLProvider(headers, "my-saml-provider");
937
933
 
938
934
  const updated = await auth.api.updateSSOProvider({
939
- params: { providerId: "my-saml-provider" },
940
- body: { issuer: "https://new-issuer.example.com" },
935
+ body: {
936
+ providerId: "my-saml-provider",
937
+ issuer: "https://new-issuer.example.com",
938
+ },
941
939
  headers,
942
940
  });
943
941
 
@@ -957,8 +955,7 @@ describe("SSO provider read endpoints", () => {
957
955
  await registerSAMLProvider(headers, "my-saml-provider");
958
956
 
959
957
  const response = await auth.api.updateSSOProvider({
960
- params: { providerId: "my-saml-provider" },
961
- body: { issuer: "invalid-url" },
958
+ body: { providerId: "my-saml-provider", issuer: "invalid-url" },
962
959
  headers,
963
960
  asResponse: true,
964
961
  });
@@ -979,8 +976,7 @@ describe("SSO provider read endpoints", () => {
979
976
  await registerSAMLProvider(headers, "my-saml-provider");
980
977
 
981
978
  const response = await auth.api.updateSSOProvider({
982
- params: { providerId: "my-saml-provider" },
983
- body: {},
979
+ body: { providerId: "my-saml-provider" },
984
980
  headers,
985
981
  asResponse: true,
986
982
  });
@@ -1020,8 +1016,7 @@ describe("SSO provider read endpoints", () => {
1020
1016
  await addMember(adminUser!.id, org!.id, "admin", ownerHeaders);
1021
1017
 
1022
1018
  const updated = await auth.api.updateSSOProvider({
1023
- params: { providerId: "org-provider" },
1024
- body: { domain: "new-domain.com" },
1019
+ body: { providerId: "org-provider", domain: "new-domain.com" },
1025
1020
  headers: adminHeaders,
1026
1021
  });
1027
1022
 
@@ -1060,8 +1055,7 @@ describe("SSO provider read endpoints", () => {
1060
1055
  await addMember(memberUser!.id, org!.id, "member", ownerHeaders);
1061
1056
 
1062
1057
  const response = await auth.api.updateSSOProvider({
1063
- params: { providerId: "org-provider" },
1064
- body: { domain: "new-domain.com" },
1058
+ body: { providerId: "org-provider", domain: "new-domain.com" },
1065
1059
  headers: memberHeaders,
1066
1060
  asResponse: true,
1067
1061
  });
@@ -1085,8 +1079,8 @@ describe("SSO provider read endpoints", () => {
1085
1079
  createOIDCProviderData(user!.id, "my-oidc-provider", "client123");
1086
1080
 
1087
1081
  const response = await auth.api.updateSSOProvider({
1088
- params: { providerId: "my-oidc-provider" },
1089
1082
  body: {
1083
+ providerId: "my-oidc-provider",
1090
1084
  samlConfig: {
1091
1085
  entryPoint: "https://idp.example.com/sso",
1092
1086
  cert: TEST_CERT,
@@ -1114,8 +1108,8 @@ describe("SSO provider read endpoints", () => {
1114
1108
  await registerSAMLProvider(headers, "my-saml-provider");
1115
1109
 
1116
1110
  const response = await auth.api.updateSSOProvider({
1117
- params: { providerId: "my-saml-provider" },
1118
1111
  body: {
1112
+ providerId: "my-saml-provider",
1119
1113
  oidcConfig: {
1120
1114
  clientId: "new-client-id",
1121
1115
  clientSecret: "new-secret",
@@ -1129,11 +1123,11 @@ describe("SSO provider read endpoints", () => {
1129
1123
  });
1130
1124
  });
1131
1125
 
1132
- describe("DELETE /sso/providers/:providerId", () => {
1126
+ describe("POST /sso/delete-provider", () => {
1133
1127
  it("should return 401 when not authenticated", async () => {
1134
1128
  const { auth } = createTestAuth();
1135
1129
  const response = await auth.api.deleteSSOProvider({
1136
- params: { providerId: "test" },
1130
+ body: { providerId: "test" },
1137
1131
  asResponse: true,
1138
1132
  });
1139
1133
  expect(response.status).toBe(401);
@@ -1148,7 +1142,7 @@ describe("SSO provider read endpoints", () => {
1148
1142
  });
1149
1143
 
1150
1144
  const response = await auth.api.deleteSSOProvider({
1151
- params: { providerId: "nonexistent" },
1145
+ body: { providerId: "nonexistent" },
1152
1146
  headers,
1153
1147
  asResponse: true,
1154
1148
  });
@@ -1174,7 +1168,7 @@ describe("SSO provider read endpoints", () => {
1174
1168
  });
1175
1169
 
1176
1170
  const response = await auth.api.deleteSSOProvider({
1177
- params: { providerId: "other-provider" },
1171
+ body: { providerId: "other-provider" },
1178
1172
  headers: otherHeaders,
1179
1173
  asResponse: true,
1180
1174
  });
@@ -1194,14 +1188,14 @@ describe("SSO provider read endpoints", () => {
1194
1188
  await registerSAMLProvider(headers, "my-saml-provider");
1195
1189
 
1196
1190
  const deleteResponse = await auth.api.deleteSSOProvider({
1197
- params: { providerId: "my-saml-provider" },
1191
+ body: { providerId: "my-saml-provider" },
1198
1192
  headers,
1199
1193
  });
1200
1194
 
1201
1195
  expect(deleteResponse.success).toBe(true);
1202
1196
 
1203
1197
  const getResponse = await auth.api.getSSOProvider({
1204
- params: { providerId: "my-saml-provider" },
1198
+ query: { providerId: "my-saml-provider" },
1205
1199
  headers,
1206
1200
  asResponse: true,
1207
1201
  });
@@ -1241,7 +1235,7 @@ describe("SSO provider read endpoints", () => {
1241
1235
  await addMember(adminUser!.id, org!.id, "admin", ownerHeaders);
1242
1236
 
1243
1237
  const deleteResponse = await auth.api.deleteSSOProvider({
1244
- params: { providerId: "org-provider" },
1238
+ body: { providerId: "org-provider" },
1245
1239
  headers: adminHeaders,
1246
1240
  });
1247
1241
 
@@ -1280,7 +1274,7 @@ describe("SSO provider read endpoints", () => {
1280
1274
  await addMember(memberUser!.id, org!.id, "member", ownerHeaders);
1281
1275
 
1282
1276
  const response = await auth.api.deleteSSOProvider({
1283
- params: { providerId: "org-provider" },
1277
+ body: { providerId: "org-provider" },
1284
1278
  headers: memberHeaders,
1285
1279
  asResponse: true,
1286
1280
  });
@@ -1316,7 +1310,7 @@ describe("SSO provider read endpoints", () => {
1316
1310
  const accountCountBefore = data.account.length;
1317
1311
 
1318
1312
  await auth.api.deleteSSOProvider({
1319
- params: { providerId: "my-saml-provider" },
1313
+ body: { providerId: "my-saml-provider" },
1320
1314
  headers,
1321
1315
  });
1322
1316
 
@@ -8,10 +8,22 @@ import { generateRandomString } from "better-auth/crypto";
8
8
  import * as z from "zod/v4";
9
9
  import type { SSOOptions, SSOProvider } from "../types";
10
10
 
11
+ const DNS_LABEL_MAX_LENGTH = 63;
12
+ const DEFAULT_TOKEN_PREFIX = "better-auth-token";
13
+
11
14
  const domainVerificationBodySchema = z.object({
12
15
  providerId: z.string(),
13
16
  });
14
17
 
18
+ export function getVerificationIdentifier(
19
+ options: SSOOptions,
20
+ providerId: string,
21
+ ): string {
22
+ const tokenPrefix =
23
+ options.domainVerification?.tokenPrefix || DEFAULT_TOKEN_PREFIX;
24
+ return `_${tokenPrefix}-${providerId}`;
25
+ }
26
+
15
27
  export const requestDomainVerification = (options: SSOOptions) => {
16
28
  return createAuthEndpoint(
17
29
  "/sso/request-domain-verification",
@@ -83,15 +95,18 @@ export const requestDomainVerification = (options: SSOOptions) => {
83
95
  });
84
96
  }
85
97
 
98
+ const identifier = getVerificationIdentifier(
99
+ options,
100
+ provider.providerId,
101
+ );
102
+
86
103
  const activeVerification =
87
104
  await ctx.context.adapter.findOne<Verification>({
88
105
  model: "verification",
89
106
  where: [
90
107
  {
91
108
  field: "identifier",
92
- value: options.domainVerification?.tokenPrefix
93
- ? `${options.domainVerification?.tokenPrefix}-${provider.providerId}`
94
- : `better-auth-token-${provider.providerId}`,
109
+ value: identifier,
95
110
  },
96
111
  { field: "expiresAt", value: new Date(), operator: "gt" },
97
112
  ],
@@ -106,9 +121,7 @@ export const requestDomainVerification = (options: SSOOptions) => {
106
121
  await ctx.context.adapter.create<Verification>({
107
122
  model: "verification",
108
123
  data: {
109
- identifier: options.domainVerification?.tokenPrefix
110
- ? `${options.domainVerification?.tokenPrefix}-${provider.providerId}`
111
- : `better-auth-token-${provider.providerId}`,
124
+ identifier,
112
125
  createdAt: new Date(),
113
126
  updatedAt: new Date(),
114
127
  value: domainVerificationToken,
@@ -199,15 +212,25 @@ export const verifyDomain = (options: SSOOptions) => {
199
212
  });
200
213
  }
201
214
 
215
+ const identifier = getVerificationIdentifier(
216
+ options,
217
+ provider.providerId,
218
+ );
219
+
220
+ if (identifier.length > DNS_LABEL_MAX_LENGTH) {
221
+ throw new APIError("BAD_REQUEST", {
222
+ message: `Verification identifier exceeds the DNS label limit of ${DNS_LABEL_MAX_LENGTH} characters`,
223
+ code: "IDENTIFIER_TOO_LONG",
224
+ });
225
+ }
226
+
202
227
  const activeVerification =
203
228
  await ctx.context.adapter.findOne<Verification>({
204
229
  model: "verification",
205
230
  where: [
206
231
  {
207
232
  field: "identifier",
208
- value: options.domainVerification?.tokenPrefix
209
- ? `${options.domainVerification?.tokenPrefix}-${provider.providerId}`
210
- : `better-auth-token-${provider.providerId}`,
233
+ value: identifier,
211
234
  },
212
235
  { field: "expiresAt", value: new Date(), operator: "gt" },
213
236
  ],
@@ -237,9 +260,8 @@ export const verifyDomain = (options: SSOOptions) => {
237
260
  }
238
261
 
239
262
  try {
240
- const dnsRecords = await dns.resolveTxt(
241
- new URL(provider.domain).hostname,
242
- );
263
+ const hostname = new URL(provider.domain).hostname;
264
+ const dnsRecords = await dns.resolveTxt(`${identifier}.${hostname}`);
243
265
  records = dnsRecords.flat();
244
266
  } catch (error) {
245
267
  ctx.context.logger.warn(
@@ -0,0 +1,126 @@
1
+ import type { DBAdapter } from "@better-auth/core/db/adapter";
2
+ import * as saml from "samlify";
3
+ import type { SAMLConfig, SSOOptions, SSOProvider } from "../types";
4
+ import { safeJsonParse } from "../utils";
5
+
6
+ export async function findSAMLProvider(
7
+ providerId: string,
8
+ options: SSOOptions | undefined,
9
+ adapter: DBAdapter,
10
+ ): Promise<SSOProvider<SSOOptions> | null> {
11
+ if (options?.defaultSSO?.length) {
12
+ const match = options.defaultSSO.find((p) => p.providerId === providerId);
13
+ if (match) {
14
+ return {
15
+ ...match,
16
+ userId: "default",
17
+ issuer: match.samlConfig?.issuer || "",
18
+ ...(options.domainVerification?.enabled
19
+ ? { domainVerified: true }
20
+ : {}),
21
+ } as SSOProvider<SSOOptions>;
22
+ }
23
+ }
24
+
25
+ const res = await adapter.findOne<SSOProvider<SSOOptions>>({
26
+ model: "ssoProvider",
27
+ where: [{ field: "providerId", value: providerId }],
28
+ });
29
+
30
+ if (!res) return null;
31
+
32
+ return {
33
+ ...res,
34
+ samlConfig: res.samlConfig
35
+ ? safeJsonParse<SAMLConfig>(res.samlConfig as unknown as string) ||
36
+ undefined
37
+ : undefined,
38
+ };
39
+ }
40
+
41
+ export function createSP(
42
+ config: SAMLConfig,
43
+ baseURL: string,
44
+ providerId: string,
45
+ sloOptions?: {
46
+ wantLogoutRequestSigned?: boolean;
47
+ wantLogoutResponseSigned?: boolean;
48
+ },
49
+ ) {
50
+ const sloLocation = `${baseURL}/sso/saml2/sp/slo/${providerId}`;
51
+ return saml.ServiceProvider({
52
+ entityID: config.spMetadata?.entityID || config.issuer,
53
+ assertionConsumerService: [
54
+ {
55
+ Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
56
+ Location:
57
+ config.callbackUrl || `${baseURL}/sso/saml2/sp/acs/${providerId}`,
58
+ },
59
+ ],
60
+ singleLogoutService: [
61
+ {
62
+ Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
63
+ Location: sloLocation,
64
+ },
65
+ {
66
+ Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
67
+ Location: sloLocation,
68
+ },
69
+ ],
70
+ wantMessageSigned: config.wantAssertionsSigned || false,
71
+ wantLogoutRequestSigned: sloOptions?.wantLogoutRequestSigned ?? false,
72
+ wantLogoutResponseSigned: sloOptions?.wantLogoutResponseSigned ?? false,
73
+ metadata: config.spMetadata?.metadata,
74
+ privateKey: config.spMetadata?.privateKey || config.privateKey,
75
+ privateKeyPass: config.spMetadata?.privateKeyPass,
76
+ });
77
+ }
78
+
79
+ export function createIdP(config: SAMLConfig) {
80
+ const idpData = config.idpMetadata;
81
+ if (idpData?.metadata) {
82
+ return saml.IdentityProvider({
83
+ metadata: idpData.metadata,
84
+ privateKey: idpData.privateKey,
85
+ privateKeyPass: idpData.privateKeyPass,
86
+ encPrivateKey: idpData.encPrivateKey,
87
+ encPrivateKeyPass: idpData.encPrivateKeyPass,
88
+ });
89
+ }
90
+ return saml.IdentityProvider({
91
+ entityID: idpData?.entityID || config.issuer,
92
+ singleSignOnService: idpData?.singleSignOnService || [
93
+ {
94
+ Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
95
+ Location: config.entryPoint,
96
+ },
97
+ ],
98
+ singleLogoutService: idpData?.singleLogoutService,
99
+ signingCert: idpData?.cert || config.cert,
100
+ });
101
+ }
102
+
103
+ function escapeHtml(str: string | undefined | null): string {
104
+ if (!str) return "";
105
+ return String(str)
106
+ .replace(/&/g, "&amp;")
107
+ .replace(/</g, "&lt;")
108
+ .replace(/>/g, "&gt;")
109
+ .replace(/"/g, "&quot;")
110
+ .replace(/'/g, "&#39;");
111
+ }
112
+
113
+ export function createSAMLPostForm(
114
+ action: string,
115
+ samlParam: string,
116
+ samlValue: string,
117
+ relayState?: string,
118
+ ): Response {
119
+ const safeAction = escapeHtml(action);
120
+ const safeSamlParam = escapeHtml(samlParam);
121
+ const safeSamlValue = escapeHtml(samlValue);
122
+ const safeRelayState = relayState ? escapeHtml(relayState) : undefined;
123
+
124
+ const html = `<!DOCTYPE html><html><body onload="document.forms[0].submit();"><form method="POST" action="${safeAction}"><input type="hidden" name="${safeSamlParam}" value="${safeSamlValue}" />${safeRelayState ? `<input type="hidden" name="RelayState" value="${safeRelayState}" />` : ""}<noscript><input type="submit" value="Continue" /></noscript></form></body></html>`;
125
+ return new Response(html, { headers: { "Content-Type": "text/html" } });
126
+ }
@@ -233,7 +233,7 @@ export const listSSOProviders = () => {
233
233
  );
234
234
  };
235
235
 
236
- const getSSOProviderParamsSchema = z.object({
236
+ const getSSOProviderQuerySchema = z.object({
237
237
  providerId: z.string(),
238
238
  });
239
239
 
@@ -280,11 +280,11 @@ async function checkProviderAccess(
280
280
 
281
281
  export const getSSOProvider = () => {
282
282
  return createAuthEndpoint(
283
- "/sso/providers/:providerId",
283
+ "/sso/get-provider",
284
284
  {
285
285
  method: "GET",
286
286
  use: [sessionMiddleware],
287
- params: getSSOProviderParamsSchema,
287
+ query: getSSOProviderQuerySchema,
288
288
  metadata: {
289
289
  openapi: {
290
290
  operationId: "getSSOProvider",
@@ -305,7 +305,7 @@ export const getSSOProvider = () => {
305
305
  },
306
306
  },
307
307
  async (ctx) => {
308
- const { providerId } = ctx.params;
308
+ const { providerId } = ctx.query;
309
309
 
310
310
  const provider = await checkProviderAccess(ctx, providerId);
311
311
 
@@ -387,12 +387,13 @@ function mergeOIDCConfig(
387
387
 
388
388
  export const updateSSOProvider = (options: SSOOptions) => {
389
389
  return createAuthEndpoint(
390
- "/sso/providers/:providerId",
390
+ "/sso/update-provider",
391
391
  {
392
- method: "PATCH",
392
+ method: "POST",
393
393
  use: [sessionMiddleware],
394
- params: getSSOProviderParamsSchema,
395
- body: updateSSOProviderBodySchema,
394
+ body: updateSSOProviderBodySchema.extend({
395
+ providerId: z.string(),
396
+ }),
396
397
  metadata: {
397
398
  openapi: {
398
399
  operationId: "updateSSOProvider",
@@ -414,8 +415,7 @@ export const updateSSOProvider = (options: SSOOptions) => {
414
415
  },
415
416
  },
416
417
  async (ctx) => {
417
- const { providerId } = ctx.params;
418
- const body = ctx.body;
418
+ const { providerId, ...body } = ctx.body;
419
419
 
420
420
  const { issuer, domain, samlConfig, oidcConfig } = body;
421
421
  if (!issuer && !domain && !samlConfig && !oidcConfig) {
@@ -525,11 +525,13 @@ export const updateSSOProvider = (options: SSOOptions) => {
525
525
 
526
526
  export const deleteSSOProvider = () => {
527
527
  return createAuthEndpoint(
528
- "/sso/providers/:providerId",
528
+ "/sso/delete-provider",
529
529
  {
530
- method: "DELETE",
530
+ method: "POST",
531
531
  use: [sessionMiddleware],
532
- params: getSSOProviderParamsSchema,
532
+ body: z.object({
533
+ providerId: z.string(),
534
+ }),
533
535
  metadata: {
534
536
  openapi: {
535
537
  operationId: "deleteSSOProvider",
@@ -550,7 +552,7 @@ export const deleteSSOProvider = () => {
550
552
  },
551
553
  },
552
554
  async (ctx) => {
553
- const { providerId } = ctx.params;
555
+ const { providerId } = ctx.body;
554
556
 
555
557
  await checkProviderAccess(ctx, providerId);
556
558