From 1fd49b890c9dbc98036fed5053f3396c8b9e6153 Mon Sep 17 00:00:00 2001 From: Michael Novotny Date: Mon, 13 Jul 2026 22:55:16 -0500 Subject: [PATCH 1/7] fix(backend): Add required provider field to CreateEnterpriseConnectionParams The Backend API validates provider as required on enterprise connection creation, so calls without it type-checked but failed at runtime. Co-Authored-By: Claude Fable 5 --- .changeset/heavy-melons-argue.md | 5 +++++ integration/tests/tanstack-start/enterprise-sso.test.ts | 3 +-- .../src/api/__tests__/EnterpriseConnectionApi.test.ts | 4 ++++ .../backend/src/api/endpoints/EnterpriseConnectionApi.ts | 2 ++ 4 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 .changeset/heavy-melons-argue.md diff --git a/.changeset/heavy-melons-argue.md b/.changeset/heavy-melons-argue.md new file mode 100644 index 00000000000..096cdff2096 --- /dev/null +++ b/.changeset/heavy-melons-argue.md @@ -0,0 +1,5 @@ +--- +'@clerk/backend': patch +--- + +Add the required `provider` field to `CreateEnterpriseConnectionParams`. The Backend API has always required `provider` when creating an enterprise connection, so calls to `createEnterpriseConnection()` without it type-checked but failed at runtime. The parameter type now reflects the API contract. diff --git a/integration/tests/tanstack-start/enterprise-sso.test.ts b/integration/tests/tanstack-start/enterprise-sso.test.ts index 96f83d23fdf..5f607c96b07 100644 --- a/integration/tests/tanstack-start/enterprise-sso.test.ts +++ b/integration/tests/tanstack-start/enterprise-sso.test.ts @@ -13,7 +13,6 @@ const FAKE_IDP_CERTIFICATE = /** * Helper to create and activate a SAML enterprise connection. * The Clerk API requires creating the connection first (inactive), then activating via update. - * The `provider` field is required by the API but missing from the SDK types, so we cast. */ async function createActiveEnterpriseConnection( clerk: ReturnType['services']['clerk'], @@ -28,7 +27,7 @@ async function createActiveEnterpriseConnection( idpSsoUrl: opts.idpSsoUrl, idpCertificate: FAKE_IDP_CERTIFICATE, }, - } as Parameters[0]); + }); return clerk.enterpriseConnections.updateEnterpriseConnection(conn.id, { active: true }); } diff --git a/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts b/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts index 739eeb6445c..2cf4897df61 100644 --- a/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts +++ b/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts @@ -60,6 +60,7 @@ describe('EnterpriseConnectionAPI', () => { expect(body.name).toBe('Clerk'); expect(body.domains).toEqual(['clerk.dev']); + expect(body.provider).toBe('saml_custom'); expect(body.saml).toEqual({ idp_entity_id: 'xxx', idp_metadata_url: 'https://oauth.devsuccess.app/metadata', @@ -74,6 +75,7 @@ describe('EnterpriseConnectionAPI', () => { await apiClient.enterpriseConnections.createEnterpriseConnection({ name: 'Clerk', domains: ['clerk.dev'], + provider: 'saml_custom', saml: { idpEntityId: 'xxx', idpMetadataUrl: 'https://oauth.devsuccess.app/metadata', @@ -89,6 +91,7 @@ describe('EnterpriseConnectionAPI', () => { validateHeaders(async ({ request }) => { const body = (await request.json()) as Record; + expect(body.provider).toBe('oidc_custom'); expect(body.oidc).toEqual({ discovery_url: 'https://oidc.example.com/.well-known/openid-configuration', client_id: 'client_123', @@ -107,6 +110,7 @@ describe('EnterpriseConnectionAPI', () => { await apiClient.enterpriseConnections.createEnterpriseConnection({ name: 'OIDC Connection', domains: ['example.com'], + provider: 'oidc_custom', oidc: { discoveryUrl: 'https://oidc.example.com/.well-known/openid-configuration', clientId: 'client_123', diff --git a/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts b/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts index ccbcc15d0d1..4cc8e3a46ec 100644 --- a/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts +++ b/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts @@ -83,6 +83,8 @@ export type CreateEnterpriseConnectionParams = { active?: boolean; /** Whether the enterprise connection should sync user attributes between the IdP and Clerk. */ syncUserAttributes?: boolean; + /** The identity provider (IdP) of the enterprise connection. For example, `'saml_custom'` or `'oidc_custom'`. */ + provider: string; /** Configuration for if the enterprise connection uses OAuth (OIDC). */ oidc?: EnterpriseConnectionOidcParams; /** Configuration for if the enterprise connection uses SAML. */ From 2092c3a2f1c1780939118560be08302638f549a7 Mon Sep 17 00:00:00 2001 From: Michael Novotny Date: Mon, 13 Jul 2026 23:09:50 -0500 Subject: [PATCH 2/7] fix(backend): Narrow provider to supported values and lock in type contract Reuses the OrganizationEnterpriseConnectionProvider union from @clerk/shared/types (matching the sibling SamlConnectionApi pattern) and adds type-level tests so provider can't silently become optional or widen back to string. Co-Authored-By: Claude Fable 5 --- .changeset/heavy-melons-argue.md | 2 +- .../src/api/__tests__/EnterpriseConnectionApi.test.ts | 9 ++++++++- .../backend/src/api/endpoints/EnterpriseConnectionApi.ts | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.changeset/heavy-melons-argue.md b/.changeset/heavy-melons-argue.md index 096cdff2096..d2baf5ee0cc 100644 --- a/.changeset/heavy-melons-argue.md +++ b/.changeset/heavy-melons-argue.md @@ -2,4 +2,4 @@ '@clerk/backend': patch --- -Add the required `provider` field to `CreateEnterpriseConnectionParams`. The Backend API has always required `provider` when creating an enterprise connection, so calls to `createEnterpriseConnection()` without it type-checked but failed at runtime. The parameter type now reflects the API contract. +Add the required `provider` field to `CreateEnterpriseConnectionParams`. The Backend API has always required `provider` when creating an enterprise connection, so calls to `createEnterpriseConnection()` without it type-checked but failed at runtime. The field is typed to the supported provider values (`'saml_custom'`, `'saml_okta'`, `'saml_google'`, `'saml_microsoft'`, `'oidc_custom'`, `'oidc_github_enterprise'`, `'oidc_gitlab'`), so unsupported values are also caught at compile time. diff --git a/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts b/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts index 2cf4897df61..d9675e0080c 100644 --- a/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts +++ b/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts @@ -1,7 +1,8 @@ import { http, HttpResponse } from 'msw'; -import { describe, expect, it } from 'vitest'; +import { describe, expect, expectTypeOf, it } from 'vitest'; import { server, validateHeaders } from '../../mock-server'; +import type { CreateEnterpriseConnectionParams } from '../endpoints/EnterpriseConnectionApi'; import { createBackendApiClient } from '../factory'; describe('EnterpriseConnectionAPI', () => { @@ -122,6 +123,12 @@ describe('EnterpriseConnectionAPI', () => { }, }); }); + + it('requires provider and rejects unsupported values at the type level', () => { + expectTypeOf<{ name: string; domains: string[] }>().not.toExtend(); + expectTypeOf<'saml_bogus'>().not.toExtend(); + expectTypeOf<'saml_okta'>().toExtend(); + }); }); describe('updateEnterpriseConnection', () => { diff --git a/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts b/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts index 4cc8e3a46ec..3a4a246fce2 100644 --- a/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts +++ b/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts @@ -1,4 +1,4 @@ -import type { ClerkPaginationRequest } from '@clerk/shared/types'; +import type { ClerkPaginationRequest, OrganizationEnterpriseConnectionProvider } from '@clerk/shared/types'; import { joinPaths } from '../../util/path'; import type { EnterpriseConnection } from '../resources'; @@ -84,7 +84,7 @@ export type CreateEnterpriseConnectionParams = { /** Whether the enterprise connection should sync user attributes between the IdP and Clerk. */ syncUserAttributes?: boolean; /** The identity provider (IdP) of the enterprise connection. For example, `'saml_custom'` or `'oidc_custom'`. */ - provider: string; + provider: OrganizationEnterpriseConnectionProvider; /** Configuration for if the enterprise connection uses OAuth (OIDC). */ oidc?: EnterpriseConnectionOidcParams; /** Configuration for if the enterprise connection uses SAML. */ From c6348b1e3dd3cc67a881d5b5eef35df88069142a Mon Sep 17 00:00:00 2001 From: Michael Novotny Date: Mon, 13 Jul 2026 23:00:47 -0500 Subject: [PATCH 3/7] fix(backend): Require name and domains when creating enterprise connections Stacked on #9153 (required provider field). Aligns the remaining CreateEnterpriseConnectionParams gaps with the Backend API contract, which validates name and domains (min 1) as required. Deprecates syncUserAttributes on create and provider on update, since the Backend API ignores both. Co-Authored-By: Claude Fable 5 --- .changeset/violet-planes-repeat.md | 9 +++++++++ .../src/api/endpoints/EnterpriseConnectionApi.ts | 16 +++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 .changeset/violet-planes-repeat.md diff --git a/.changeset/violet-planes-repeat.md b/.changeset/violet-planes-repeat.md new file mode 100644 index 00000000000..4aee6753981 --- /dev/null +++ b/.changeset/violet-planes-repeat.md @@ -0,0 +1,9 @@ +--- +'@clerk/backend': patch +--- + +Align `CreateEnterpriseConnectionParams` and `UpdateEnterpriseConnectionParams` with the Backend API contract: + +- `name` and `domains` are now required on `CreateEnterpriseConnectionParams`. The Backend API already rejected requests missing either of them, so calls that omitted these fields failed at runtime; the types now surface this at compile time. +- Deprecated `syncUserAttributes` on `CreateEnterpriseConnectionParams`. The Backend API ignores this parameter on create; use `updateEnterpriseConnection()` to set it. +- Deprecated `provider` on `UpdateEnterpriseConnectionParams`. The Backend API ignores this parameter on update; the provider cannot be changed after creation. diff --git a/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts b/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts index 3a4a246fce2..7e3fdacab91 100644 --- a/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts +++ b/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts @@ -74,14 +74,17 @@ export interface EnterpriseConnectionSamlParams { /** @generateWithEmptyComment */ export type CreateEnterpriseConnectionParams = { /** The name of the enterprise connection. */ - name?: string; - /** The [Verified Domains](https://clerk.com/docs/guides/organizations/add-members/verified-domains) of the enterprise connection. */ - domains?: string[]; + name: string; + /** The [Verified Domains](https://clerk.com/docs/guides/organizations/add-members/verified-domains) of the enterprise connection. Must contain at least one domain. */ + domains: string[]; /** The organization ID of the enterprise connection. */ organizationId?: string; /** Whether the enterprise connection should be active. */ active?: boolean; - /** Whether the enterprise connection should sync user attributes between the IdP and Clerk. */ + /** + * Whether the enterprise connection should sync user attributes between the IdP and Clerk. + * @deprecated The Backend API does not support this parameter on create and ignores it. Use `updateEnterpriseConnection()` to set it. + */ syncUserAttributes?: boolean; /** The identity provider (IdP) of the enterprise connection. For example, `'saml_custom'` or `'oidc_custom'`. */ provider: OrganizationEnterpriseConnectionProvider; @@ -103,7 +106,10 @@ export type UpdateEnterpriseConnectionParams = { active?: boolean; /** Whether the enterprise connection should sync user attributes between the IdP and Clerk. */ syncUserAttributes?: boolean; - /** The identity provider (IdP) of the enterprise connection. For example, `'saml_custom'` or `'oidc_custom'`. */ + /** + * The identity provider (IdP) of the enterprise connection. For example, `'saml_custom'` or `'oidc_custom'`. + * @deprecated The Backend API does not support this parameter on update and ignores it. The provider cannot be changed after creation. + */ provider?: string; /** Configuration for if the enterprise connection uses OAuth (OIDC). */ oidc?: EnterpriseConnectionOidcParams; From 7b6b5c002591bfeeb6629ab5c38c54c016acc5a0 Mon Sep 17 00:00:00 2001 From: Michael Novotny Date: Mon, 13 Jul 2026 23:12:34 -0500 Subject: [PATCH 4/7] fix(backend): Add missing optional enterprise connection params Adds the optional create/update params the Backend API supports but the SDK types omitted: allowOrganizationAccountLinking, customAttributes, authenticatable, disableJitProvisioning, disableAdditionalIdentifications (update only), and saml.loginHint. Verified against BAPI's CreateParams/UpdateParams/SAMLParams in clerk_go. Co-Authored-By: Claude Fable 5 --- .changeset/tidy-donuts-attend.md | 5 + .../__tests__/EnterpriseConnectionApi.test.ts | 94 +++++++++++++++++++ .../api/endpoints/EnterpriseConnectionApi.ts | 42 +++++++++ 3 files changed, 141 insertions(+) create mode 100644 .changeset/tidy-donuts-attend.md diff --git a/.changeset/tidy-donuts-attend.md b/.changeset/tidy-donuts-attend.md new file mode 100644 index 00000000000..82cccf3a5e8 --- /dev/null +++ b/.changeset/tidy-donuts-attend.md @@ -0,0 +1,5 @@ +--- +'@clerk/backend': patch +--- + +Add the remaining optional enterprise connection parameters supported by the Backend API. `CreateEnterpriseConnectionParams` and `UpdateEnterpriseConnectionParams` now accept `allowOrganizationAccountLinking`, `customAttributes`, `authenticatable`, and `disableJitProvisioning` (update also accepts `disableAdditionalIdentifications`), and SAML params accept `loginHint` for configuring the `login_hint` sent to the IdP. diff --git a/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts b/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts index d9675e0080c..90ce3e6ec88 100644 --- a/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts +++ b/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts @@ -129,6 +129,59 @@ describe('EnterpriseConnectionAPI', () => { expectTypeOf<'saml_bogus'>().not.toExtend(); expectTypeOf<'saml_okta'>().toExtend(); }); + + it('sends provisioning, custom attribute, and login hint params in snake_case', async () => { + server.use( + http.post( + 'https://api.clerk.test/v1/enterprise_connections', + validateHeaders(async ({ request }) => { + const body = (await request.json()) as Record; + + expect(body.allow_organization_account_linking).toBe(true); + expect(body.authenticatable).toBe(false); + expect(body.disable_jit_provisioning).toBe(true); + expect(body.custom_attributes).toEqual([ + { + name: 'Employee Number', + key: 'employee_number', + sso_path: 'user.employeeNumber', + multi_valued: false, + }, + ]); + expect((body.saml as Record).login_hint).toEqual({ + mode: 'custom_attribute', + source: 'employee_number', + }); + + return HttpResponse.json(mockEnterpriseConnectionResponse); + }), + ), + ); + + await apiClient.enterpriseConnections.createEnterpriseConnection({ + name: 'Clerk', + domains: ['clerk.dev'], + provider: 'saml_custom', + allowOrganizationAccountLinking: true, + authenticatable: false, + disableJitProvisioning: true, + customAttributes: [ + { + name: 'Employee Number', + key: 'employee_number', + ssoPath: 'user.employeeNumber', + multiValued: false, + }, + ], + saml: { + idpEntityId: 'xxx', + loginHint: { + mode: 'custom_attribute', + source: 'employee_number', + }, + }, + }); + }); }); describe('updateEnterpriseConnection', () => { @@ -157,6 +210,47 @@ describe('EnterpriseConnectionAPI', () => { }, }); }); + + it('sends provisioning and custom attribute params in snake_case', async () => { + server.use( + http.patch( + 'https://api.clerk.test/v1/enterprise_connections/entconn_123', + validateHeaders(async ({ request }) => { + const body = (await request.json()) as Record; + + expect(body.sync_user_attributes).toBe(true); + expect(body.disable_additional_identifications).toBe(true); + expect(body.allow_organization_account_linking).toBe(false); + expect(body.authenticatable).toBe(true); + expect(body.disable_jit_provisioning).toBe(false); + expect(body.custom_attributes).toEqual([ + { + name: 'Department', + key: 'department', + scim_path: 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:department', + }, + ]); + + return HttpResponse.json(mockEnterpriseConnectionResponse); + }), + ), + ); + + await apiClient.enterpriseConnections.updateEnterpriseConnection('entconn_123', { + syncUserAttributes: true, + disableAdditionalIdentifications: true, + allowOrganizationAccountLinking: false, + authenticatable: true, + disableJitProvisioning: false, + customAttributes: [ + { + name: 'Department', + key: 'department', + scimPath: 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:department', + }, + ], + }); + }); }); describe('getEnterpriseConnectionList', () => { diff --git a/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts b/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts index 7e3fdacab91..467b164e29e 100644 --- a/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts +++ b/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts @@ -49,6 +49,28 @@ export interface EnterpriseConnectionSamlAttributeMappingParams { lastName?: string | null; } +/** @inline */ +export interface EnterpriseConnectionSamlLoginHintParams { + /** How the SAML connection emits the `login_hint` sent to the IdP: `'email_address'` sends the typed identifier, `'custom_attribute'` sends the value stored at the user `publicMetadata` key named by `source`, and `'off'` omits the `login_hint`. */ + mode: 'email_address' | 'custom_attribute' | 'off'; + /** The user `publicMetadata` key to read the `login_hint` value from. Required when `mode` is `'custom_attribute'`, and must be omitted otherwise. */ + source?: string; +} + +/** @inline */ +export interface EnterpriseConnectionCustomAttributeParams { + /** The display name of the custom attribute. */ + name: string; + /** The key to store the custom attribute under. */ + key: string; + /** The SSO (SAML or OIDC) attribute path to read the value from. */ + ssoPath?: string; + /** The SCIM attribute path to read the value from. */ + scimPath?: string; + /** Whether the custom attribute holds multiple values. */ + multiValued?: boolean; +} + /** @inline */ export interface EnterpriseConnectionSamlParams { /** Whether the SAML connection allows Identity Provider (IdP) initiated flows. */ @@ -69,6 +91,8 @@ export interface EnterpriseConnectionSamlParams { idpMetadataUrl?: string; /** The IdP Single-Sign On URL for the SAML connection. */ idpSsoUrl?: string; + /** Configuration for the `login_hint` the SAML connection sends to the IdP. */ + loginHint?: EnterpriseConnectionSamlLoginHintParams; } /** @generateWithEmptyComment */ @@ -88,6 +112,14 @@ export type CreateEnterpriseConnectionParams = { syncUserAttributes?: boolean; /** The identity provider (IdP) of the enterprise connection. For example, `'saml_custom'` or `'oidc_custom'`. */ provider: OrganizationEnterpriseConnectionProvider; + /** Whether existing users who are members of the organization can link their account to their enterprise identity. If `false`, only sign-up flows apply. */ + allowOrganizationAccountLinking?: boolean; + /** The custom attribute mappings for the enterprise connection. */ + customAttributes?: EnterpriseConnectionCustomAttributeParams[]; + /** Whether the enterprise connection can be used for sign-in and sign-up. Requires the authenticatable enterprise connections feature to be enabled for the instance. */ + authenticatable?: boolean; + /** Whether Just-in-Time (JIT) provisioning of users is disabled for the enterprise connection. */ + disableJitProvisioning?: boolean; /** Configuration for if the enterprise connection uses OAuth (OIDC). */ oidc?: EnterpriseConnectionOidcParams; /** Configuration for if the enterprise connection uses SAML. */ @@ -106,6 +138,16 @@ export type UpdateEnterpriseConnectionParams = { active?: boolean; /** Whether the enterprise connection should sync user attributes between the IdP and Clerk. */ syncUserAttributes?: boolean; + /** Whether additional identifications are disabled for the enterprise connection. */ + disableAdditionalIdentifications?: boolean; + /** Whether existing users who are members of the organization can link their account to their enterprise identity. If `false`, only sign-up flows apply. */ + allowOrganizationAccountLinking?: boolean; + /** The custom attribute mappings for the enterprise connection. */ + customAttributes?: EnterpriseConnectionCustomAttributeParams[]; + /** Whether the enterprise connection can be used for sign-in and sign-up. Requires the authenticatable enterprise connections feature to be enabled for the instance. */ + authenticatable?: boolean; + /** Whether Just-in-Time (JIT) provisioning of users is disabled for the enterprise connection. */ + disableJitProvisioning?: boolean; /** * The identity provider (IdP) of the enterprise connection. For example, `'saml_custom'` or `'oidc_custom'`. * @deprecated The Backend API does not support this parameter on update and ignores it. The provider cannot be changed after creation. From 1508711f22743a0d26cf39f2900a70432f3af8f9 Mon Sep 17 00:00:00 2001 From: Michael Novotny Date: Mon, 13 Jul 2026 23:41:33 -0500 Subject: [PATCH 5/7] fix(backend): Enforce login hint source/mode pairing at the type level Codex review: BAPI requires login_hint.source exactly when mode is custom_attribute and rejects it otherwise; model as a discriminated union. Also lock name/domains as required with type-level tests. Co-Authored-By: Claude Fable 5 --- .../__tests__/EnterpriseConnectionApi.test.ts | 22 ++++++++++++++++++- .../api/endpoints/EnterpriseConnectionApi.ts | 19 +++++++++++----- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts b/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts index 90ce3e6ec88..f46f0281e8f 100644 --- a/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts +++ b/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts @@ -2,7 +2,10 @@ import { http, HttpResponse } from 'msw'; import { describe, expect, expectTypeOf, it } from 'vitest'; import { server, validateHeaders } from '../../mock-server'; -import type { CreateEnterpriseConnectionParams } from '../endpoints/EnterpriseConnectionApi'; +import type { + CreateEnterpriseConnectionParams, + EnterpriseConnectionSamlLoginHintParams, +} from '../endpoints/EnterpriseConnectionApi'; import { createBackendApiClient } from '../factory'; describe('EnterpriseConnectionAPI', () => { @@ -130,6 +133,23 @@ describe('EnterpriseConnectionAPI', () => { expectTypeOf<'saml_okta'>().toExtend(); }); + it('requires name and domains at the type level', () => { + expectTypeOf<{ + name: string; + domains: string[]; + provider: 'saml_custom'; + }>().toExtend(); + expectTypeOf<{ domains: string[]; provider: 'saml_custom' }>().not.toExtend(); + expectTypeOf<{ name: string; provider: 'saml_custom' }>().not.toExtend(); + }); + + it('requires a login hint source exactly when mode is custom_attribute at the type level', () => { + expectTypeOf<{ mode: 'custom_attribute'; source: string }>().toExtend(); + expectTypeOf<{ mode: 'email_address' }>().toExtend(); + expectTypeOf<{ mode: 'custom_attribute' }>().not.toExtend(); + expectTypeOf<{ mode: 'off'; source: string }>().not.toExtend(); + }); + it('sends provisioning, custom attribute, and login hint params in snake_case', async () => { server.use( http.post( diff --git a/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts b/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts index 467b164e29e..644fc0c88d8 100644 --- a/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts +++ b/packages/backend/src/api/endpoints/EnterpriseConnectionApi.ts @@ -50,12 +50,19 @@ export interface EnterpriseConnectionSamlAttributeMappingParams { } /** @inline */ -export interface EnterpriseConnectionSamlLoginHintParams { - /** How the SAML connection emits the `login_hint` sent to the IdP: `'email_address'` sends the typed identifier, `'custom_attribute'` sends the value stored at the user `publicMetadata` key named by `source`, and `'off'` omits the `login_hint`. */ - mode: 'email_address' | 'custom_attribute' | 'off'; - /** The user `publicMetadata` key to read the `login_hint` value from. Required when `mode` is `'custom_attribute'`, and must be omitted otherwise. */ - source?: string; -} +export type EnterpriseConnectionSamlLoginHintParams = + | { + /** Sends the value stored at the user `publicMetadata` key named by `source` as the `login_hint`. */ + mode: 'custom_attribute'; + /** The user `publicMetadata` key to read the `login_hint` value from. */ + source: string; + } + | { + /** How the SAML connection emits the `login_hint` sent to the IdP: `'email_address'` sends the typed identifier and `'off'` omits the `login_hint`. */ + mode: 'email_address' | 'off'; + /** Only supported when `mode` is `'custom_attribute'`. */ + source?: never; + }; /** @inline */ export interface EnterpriseConnectionCustomAttributeParams { From 9d3a99e12480b433aa2f13af7773c5a1312e938c Mon Sep 17 00:00:00 2001 From: Michael Novotny Date: Mon, 13 Jul 2026 23:18:34 -0500 Subject: [PATCH 6/7] fix(backend): Align EnterpriseConnection resource with Backend API response The resource classes and JSON types drifted from BAPI's serializer (clerk_go api/serialize/enterprise_connection.go): several properties read fields BAPI never sends, and several returned fields were missing. New constructor params are appended to preserve positional compatibility. Co-Authored-By: Claude Fable 5 --- .changeset/major-poets-refuse.md | 11 ++ .../__tests__/EnterpriseConnectionApi.test.ts | 55 ++++++- .../src/api/resources/EnterpriseConnection.ts | 153 +++++++++++++++--- packages/backend/src/api/resources/JSON.ts | 62 +++++-- packages/backend/src/index.ts | 4 + 5 files changed, 247 insertions(+), 38 deletions(-) create mode 100644 .changeset/major-poets-refuse.md diff --git a/.changeset/major-poets-refuse.md b/.changeset/major-poets-refuse.md new file mode 100644 index 00000000000..6283cf651bd --- /dev/null +++ b/.changeset/major-poets-refuse.md @@ -0,0 +1,11 @@ +--- +'@clerk/backend': patch +--- + +Align the `EnterpriseConnection` response resource with what the Backend API actually returns: + +- `EnterpriseConnection` now exposes `provider`, `logoPublicUrl`, `allowOrganizationAccountLinking`, `authenticatable`, `disableJitProvisioning`, and `customAttributes`. +- `EnterpriseConnectionSamlConnection` now exposes `active`, `forceAuthn`, and `loginHint`. +- `EnterpriseConnectionOauthConfig` now exposes `providerKey`, `authUrl`, `tokenUrl`, `userInfoUrl`, and `requiresPkce`. +- Deprecated properties the Backend API never returns, which were always `undefined` despite their declared types: `allowSubdomains` on `EnterpriseConnection` (use `samlConnection.allowSubdomains`), and `idpMetadata` and `syncUserAttributes` on `EnterpriseConnectionSamlConnection` (use the top-level `syncUserAttributes`). +- `organizationId` is now normalized to `null` when the Backend API omits it, matching its declared `string | null` type. Properties backed by optional API fields (for example `oauthConfig.clientId` and the SAML IdP fields) are now typed as possibly `undefined` to match runtime behavior. diff --git a/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts b/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts index f46f0281e8f..2b125f3d527 100644 --- a/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts +++ b/packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts @@ -18,14 +18,26 @@ describe('EnterpriseConnectionAPI', () => { object: 'enterprise_connection', id: 'entconn_123', name: 'Clerk', + provider: 'saml_custom', + logo_public_url: 'https://img.example.com/connection-logo.png', domains: ['clerk.dev'], - organization_id: null, created_at: 1672531200000, updated_at: 1672531200000, active: true, sync_user_attributes: false, - allow_subdomains: false, disable_additional_identifications: false, + allow_organization_account_linking: true, + authenticatable: true, + disable_jit_provisioning: false, + custom_attributes: [ + { + name: 'Employee Number', + key: 'employee_number', + sso_path: 'user.employeeNumber', + scim_path: '', + multi_valued: false, + }, + ], saml_connection: { id: 'samlc_1', name: 'Acme SAML', @@ -35,20 +47,29 @@ describe('EnterpriseConnectionAPI', () => { idp_certificate_issued_at: 1672531200000, idp_certificate_expires_at: 1704067200000, idp_metadata_url: 'https://idp.example.com/metadata', - idp_metadata: '', acs_url: 'https://clerk.example.com/v1/saml/acs', sp_entity_id: 'https://clerk.example.com', sp_metadata_url: 'https://clerk.example.com/v1/saml/metadata', - sync_user_attributes: true, + active: true, allow_subdomains: true, allow_idp_initiated: false, + force_authn: false, + login_hint: { + mode: 'custom_attribute', + source: 'employee_number', + }, }, oauth_config: { id: 'eaoc_1', + provider_key: 'custom_oidc', name: 'Acme OIDC', client_id: 'client_abc', discovery_url: 'https://oauth.example.com/.well-known/openid-configuration', + auth_url: 'https://oauth.example.com/authorize', + token_url: 'https://oauth.example.com/token', + user_info_url: 'https://oauth.example.com/userinfo', logo_public_url: 'https://img.example.com/logo.png', + requires_pkce: false, created_at: 1672531200000, updated_at: 1672531200000, }, @@ -326,17 +347,43 @@ describe('EnterpriseConnectionAPI', () => { expect(response.id).toBe('entconn_123'); expect(response.name).toBe('Clerk'); + expect(response.provider).toBe('saml_custom'); + expect(response.logoPublicUrl).toBe('https://img.example.com/connection-logo.png'); expect(response.domains).toEqual(['clerk.dev']); expect(response.active).toBe(true); + // organization_id is omitted by the Backend API when unset and normalized to null expect(response.organizationId).toBeNull(); + expect(response.allowOrganizationAccountLinking).toBe(true); + expect(response.authenticatable).toBe(true); + expect(response.disableJitProvisioning).toBe(false); + expect(response.customAttributes).toEqual([ + { + name: 'Employee Number', + key: 'employee_number', + ssoPath: 'user.employeeNumber', + scimPath: '', + multiValued: false, + }, + ]); expect(response.samlConnection).not.toBeNull(); expect(response.samlConnection?.id).toBe('samlc_1'); expect(response.samlConnection?.idpEntityId).toBe('https://idp.example.com'); expect(response.samlConnection?.idpCertificateIssuedAt).toBe(1672531200000); expect(response.samlConnection?.idpCertificateExpiresAt).toBe(1704067200000); + expect(response.samlConnection?.active).toBe(true); + expect(response.samlConnection?.forceAuthn).toBe(false); + expect(response.samlConnection?.loginHint).toEqual({ + mode: 'custom_attribute', + source: 'employee_number', + }); expect(response.oauthConfig).not.toBeNull(); + expect(response.oauthConfig?.providerKey).toBe('custom_oidc'); expect(response.oauthConfig?.clientId).toBe('client_abc'); expect(response.oauthConfig?.discoveryUrl).toBe('https://oauth.example.com/.well-known/openid-configuration'); + expect(response.oauthConfig?.authUrl).toBe('https://oauth.example.com/authorize'); + expect(response.oauthConfig?.tokenUrl).toBe('https://oauth.example.com/token'); + expect(response.oauthConfig?.userInfoUrl).toBe('https://oauth.example.com/userinfo'); + expect(response.oauthConfig?.requiresPkce).toBe(false); }); }); diff --git a/packages/backend/src/api/resources/EnterpriseConnection.ts b/packages/backend/src/api/resources/EnterpriseConnection.ts index 49c6362d635..1ec538edb54 100644 --- a/packages/backend/src/api/resources/EnterpriseConnection.ts +++ b/packages/backend/src/api/resources/EnterpriseConnection.ts @@ -1,9 +1,55 @@ import type { + EnterpriseConnectionCustomAttributeJSON, EnterpriseConnectionJSON, EnterpriseConnectionOauthConfigJSON, EnterpriseConnectionSamlConnectionJSON, + EnterpriseConnectionSamlConnectionLoginHintJSON, } from './JSON'; +/** + * The `login_hint` configuration included on a Backend API {@link EnterpriseConnectionSamlConnection} response. + */ +export class EnterpriseConnectionSamlConnectionLoginHint { + constructor( + /** How the SAML connection emits the `login_hint` sent to the IdP: `'email_address'` sends the typed identifier, `'custom_attribute'` sends the value stored at the user `publicMetadata` key named by `source`, and `'off'` omits the `login_hint`. */ + readonly mode: 'email_address' | 'custom_attribute' | 'off', + /** The user `publicMetadata` key the `login_hint` value is read from. Only set when `mode` is `'custom_attribute'`. */ + readonly source?: string, + ) {} + + static fromJSON(data: EnterpriseConnectionSamlConnectionLoginHintJSON): EnterpriseConnectionSamlConnectionLoginHint { + return new EnterpriseConnectionSamlConnectionLoginHint(data.mode, data.source); + } +} + +/** + * A custom attribute mapping included on a Backend API {@link EnterpriseConnection} response. + */ +export class EnterpriseConnectionCustomAttribute { + constructor( + /** The display name of the custom attribute. */ + readonly name: string, + /** The key the custom attribute is stored under. */ + readonly key: string, + /** The SSO (SAML or OIDC) attribute path the value is read from. */ + readonly ssoPath: string, + /** The SCIM attribute path the value is read from. */ + readonly scimPath: string, + /** Whether the custom attribute holds multiple values. */ + readonly multiValued: boolean, + ) {} + + static fromJSON(data: EnterpriseConnectionCustomAttributeJSON): EnterpriseConnectionCustomAttribute { + return new EnterpriseConnectionCustomAttribute( + data.name, + data.key, + data.sso_path, + data.scim_path, + data.multi_valued, + ); + } +} + /** * The Backend `EnterpriseConnectionSamlConnection` object holds information about a SAML enterprise connection for an instance or organization. */ @@ -14,31 +60,43 @@ export class EnterpriseConnectionSamlConnection { /** The name to use as a label for the connection. */ readonly name: string, /** The Entity ID as provided by the Identity Provider (IdP). */ - readonly idpEntityId: string, + readonly idpEntityId: string | undefined, /** The Single-Sign On URL as provided by the Identity Provider (IdP). */ - readonly idpSsoUrl: string, + readonly idpSsoUrl: string | undefined, /** The X.509 certificate as provided by the Identity Provider (IdP). */ - readonly idpCertificate: string, + readonly idpCertificate: string | undefined, /** The Unix timestamp when the Identity Provider (IdP) certificate was issued. */ - readonly idpCertificateIssuedAt: number, + readonly idpCertificateIssuedAt: number | undefined, /** The Unix timestamp when the Identity Provider (IdP) certificate expires. */ - readonly idpCertificateExpiresAt: number, + readonly idpCertificateExpiresAt: number | undefined, /** The URL which serves the Identity Provider (IdP) metadata. */ - readonly idpMetadataUrl: string, - /** The XML content of the Identity Provider (IdP) metadata file. */ - readonly idpMetadata: string, + readonly idpMetadataUrl: string | undefined, + /** + * The XML content of the Identity Provider (IdP) metadata file. + * @deprecated The Backend API does not return this field, so it is always `undefined`. + */ + readonly idpMetadata: string | undefined, /** The Assertion Consumer Service (ACS) URL of the connection. */ - readonly acsUrl: string, + readonly acsUrl: string | undefined, /** The Entity ID as provided by the Service Provider (Clerk). */ - readonly spEntityId: string, + readonly spEntityId: string | undefined, /** The metadata URL as provided by the Service Provider (Clerk). */ - readonly spMetadataUrl: string, - /** Whether the connection syncs user attributes between the IdP and Clerk. */ - readonly syncUserAttributes: boolean, + readonly spMetadataUrl: string | undefined, + /** + * Whether the connection syncs user attributes between the IdP and Clerk. + * @deprecated The Backend API does not return this field on the nested SAML connection, so it is always `undefined`. Use the top-level `syncUserAttributes` on {@link EnterpriseConnection} instead. + */ + readonly syncUserAttributes: boolean | undefined, /** Whether users with an email address subdomain are allowed to use this connection. */ readonly allowSubdomains: boolean, /** Whether IdP-initiated SSO is allowed. */ readonly allowIdpInitiated: boolean, + /** Whether the SAML connection is active. */ + readonly active: boolean, + /** Whether the SAML connection requires force authentication. */ + readonly forceAuthn: boolean, + /** The `login_hint` configuration of the SAML connection. */ + readonly loginHint: EnterpriseConnectionSamlConnectionLoginHint | null, ) {} static fromJSON(data: EnterpriseConnectionSamlConnectionJSON): EnterpriseConnectionSamlConnection { @@ -58,6 +116,9 @@ export class EnterpriseConnectionSamlConnection { data.sync_user_attributes, data.allow_subdomains, data.allow_idp_initiated, + data.active, + data.force_authn, + data.login_hint != null ? EnterpriseConnectionSamlConnectionLoginHint.fromJSON(data.login_hint) : null, ); } } @@ -78,15 +139,15 @@ export class EnterpriseConnectionOauthConfig { /** * The OAuth client ID. */ - readonly clientId: string, + readonly clientId: string | undefined, /** * The OpenID Connect discovery URL. */ - readonly discoveryUrl: string, + readonly discoveryUrl: string | undefined, /** * The public URL of the OAuth provider logo, if available. */ - readonly logoPublicUrl: string, + readonly logoPublicUrl: string | undefined, /** * The date when the configuration was first created. */ @@ -95,6 +156,26 @@ export class EnterpriseConnectionOauthConfig { * The date when the configuration was last updated. */ readonly updatedAt: number, + /** + * The OAuth provider key of the configuration. For example, `'custom_oidc'`. + */ + readonly providerKey: string, + /** + * The OAuth authorization URL. + */ + readonly authUrl: string | undefined, + /** + * The OAuth token URL. + */ + readonly tokenUrl: string | undefined, + /** + * The OAuth user info URL. + */ + readonly userInfoUrl: string | undefined, + /** + * Whether the OAuth configuration requires PKCE. + */ + readonly requiresPkce: boolean, ) {} static fromJSON(data: EnterpriseConnectionOauthConfigJSON): EnterpriseConnectionOauthConfig { @@ -106,6 +187,11 @@ export class EnterpriseConnectionOauthConfig { data.logo_public_url, data.created_at, data.updated_at, + data.provider_key, + data.auth_url, + data.token_url, + data.user_info_url, + data.requires_pkce, ); } } @@ -141,8 +227,9 @@ export class EnterpriseConnection { readonly syncUserAttributes: boolean, /** * Whether users with an email address subdomain are allowed to use this connection or not. + * @deprecated The Backend API does not return this field at the top level, so it is always `undefined`. Use `samlConnection.allowSubdomains` instead. */ - readonly allowSubdomains: boolean, + readonly allowSubdomains: boolean | undefined, /** * Whether additional identifications are disabled for this connection. */ @@ -163,6 +250,30 @@ export class EnterpriseConnection { * OAuth (OIDC) configuration when the enterprise connection uses OAuth. */ readonly oauthConfig: EnterpriseConnectionOauthConfig | null, + /** + * The identity provider (IdP) of the connection. For example, `'saml_custom'` or `'oidc_custom'`. + */ + readonly provider: string, + /** + * The public URL of the provider logo, if available. + */ + readonly logoPublicUrl: string | undefined, + /** + * Whether existing users who are members of the organization can link their account to their enterprise identity. + */ + readonly allowOrganizationAccountLinking: boolean, + /** + * Whether the connection can be used for sign-in and sign-up. + */ + readonly authenticatable: boolean, + /** + * Whether Just-in-Time (JIT) provisioning of users is disabled for the connection. + */ + readonly disableJitProvisioning: boolean, + /** + * The custom attribute mappings of the connection. Only returned when the custom attributes feature is enabled for the instance. + */ + readonly customAttributes: EnterpriseConnectionCustomAttribute[] | undefined, ) {} static fromJSON(data: EnterpriseConnectionJSON): EnterpriseConnection { @@ -170,7 +281,7 @@ export class EnterpriseConnection { data.id, data.name, data.domains, - data.organization_id, + data.organization_id ?? null, data.active, data.sync_user_attributes, data.allow_subdomains, @@ -179,6 +290,12 @@ export class EnterpriseConnection { data.updated_at, data.saml_connection != null ? EnterpriseConnectionSamlConnection.fromJSON(data.saml_connection) : null, data.oauth_config != null ? EnterpriseConnectionOauthConfig.fromJSON(data.oauth_config) : null, + data.provider, + data.logo_public_url, + data.allow_organization_account_linking, + data.authenticatable, + data.disable_jit_provisioning, + data.custom_attributes?.map(attr => EnterpriseConnectionCustomAttribute.fromJSON(attr)), ); } } diff --git a/packages/backend/src/api/resources/JSON.ts b/packages/backend/src/api/resources/JSON.ts index 298c4983d0a..6ba602efb76 100644 --- a/packages/backend/src/api/resources/JSON.ts +++ b/packages/backend/src/api/resources/JSON.ts @@ -752,30 +752,53 @@ export interface PaginatedResponseJSON { total_count?: number; } +export interface EnterpriseConnectionSamlConnectionLoginHintJSON { + mode: 'email_address' | 'custom_attribute' | 'off'; + source?: string; +} + +export interface EnterpriseConnectionCustomAttributeJSON { + name: string; + key: string; + sso_path: string; + scim_path: string; + multi_valued: boolean; +} + export interface EnterpriseConnectionSamlConnectionJSON { id: string; name: string; - idp_entity_id: string; - idp_sso_url: string; - idp_certificate: string; - idp_certificate_issued_at: number; - idp_certificate_expires_at: number; - idp_metadata_url: string; - idp_metadata: string; - acs_url: string; - sp_entity_id: string; - sp_metadata_url: string; - sync_user_attributes: boolean; + idp_entity_id?: string; + idp_sso_url?: string; + idp_certificate?: string; + idp_certificate_issued_at?: number; + idp_certificate_expires_at?: number; + idp_metadata_url?: string; + /** @deprecated The Backend API does not return this field. */ + idp_metadata?: string; + acs_url?: string; + sp_entity_id?: string; + sp_metadata_url?: string; + /** @deprecated The Backend API does not return this field on the nested SAML connection. Use the top-level `sync_user_attributes` instead. */ + sync_user_attributes?: boolean; + active: boolean; allow_subdomains: boolean; allow_idp_initiated: boolean; + force_authn: boolean; + login_hint?: EnterpriseConnectionSamlConnectionLoginHintJSON | null; } export interface EnterpriseConnectionOauthConfigJSON { id: string; + provider_key: string; name: string; - client_id: string; - discovery_url: string; - logo_public_url: string; + client_id?: string; + discovery_url?: string; + auth_url?: string; + token_url?: string; + user_info_url?: string; + logo_public_url?: string; + requires_pkce: boolean; created_at: number; updated_at: number; } @@ -783,12 +806,19 @@ export interface EnterpriseConnectionOauthConfigJSON { export interface EnterpriseConnectionJSON extends ClerkResourceJSON { object: typeof ObjectType.EnterpriseConnection; name: string; + provider: string; + logo_public_url?: string; domains: string[]; - organization_id: string | null; + organization_id?: string | null; active: boolean; sync_user_attributes: boolean; - allow_subdomains: boolean; + /** @deprecated The Backend API does not return this field at the top level. Use `saml_connection.allow_subdomains` instead. */ + allow_subdomains?: boolean; disable_additional_identifications: boolean; + allow_organization_account_linking: boolean; + authenticatable: boolean; + disable_jit_provisioning: boolean; + custom_attributes?: EnterpriseConnectionCustomAttributeJSON[]; created_at: number; updated_at: number; saml_connection?: EnterpriseConnectionSamlConnectionJSON | null; diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 7c75cc3ade5..b1a8bbd3a58 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -67,8 +67,10 @@ export type { EmailJSON, EmailAddressJSON, EnterpriseConnectionJSON, + EnterpriseConnectionCustomAttributeJSON, EnterpriseConnectionOauthConfigJSON, EnterpriseConnectionSamlConnectionJSON, + EnterpriseConnectionSamlConnectionLoginHintJSON, ExternalAccountJSON, IdentificationLinkJSON, InstanceJSON, @@ -128,8 +130,10 @@ export type { Domain, EmailAddress, EnterpriseConnection, + EnterpriseConnectionCustomAttribute, EnterpriseConnectionOauthConfig, EnterpriseConnectionSamlConnection, + EnterpriseConnectionSamlConnectionLoginHint, ExternalAccount, Feature, Instance, From f55c1e5fe6365cb31f2b44fedcf2081adda4c5af Mon Sep 17 00:00:00 2001 From: Michael Novotny Date: Tue, 14 Jul 2026 00:30:20 -0500 Subject: [PATCH 7/7] fix(backend): Make login hint required on SAML connection response and bump to minor Codex review: BAPI's serializer always sends login_hint (no omitempty, never nil), so the JSON type and resource property are non-nullable. Changeset bumped to minor to match repo precedent for new resource properties (e.g. hasImage). Co-Authored-By: Claude Fable 5 --- .changeset/major-poets-refuse.md | 2 +- packages/backend/src/api/resources/EnterpriseConnection.ts | 4 ++-- packages/backend/src/api/resources/JSON.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.changeset/major-poets-refuse.md b/.changeset/major-poets-refuse.md index 6283cf651bd..1ebfb7f370b 100644 --- a/.changeset/major-poets-refuse.md +++ b/.changeset/major-poets-refuse.md @@ -1,5 +1,5 @@ --- -'@clerk/backend': patch +'@clerk/backend': minor --- Align the `EnterpriseConnection` response resource with what the Backend API actually returns: diff --git a/packages/backend/src/api/resources/EnterpriseConnection.ts b/packages/backend/src/api/resources/EnterpriseConnection.ts index 1ec538edb54..d12ff01817f 100644 --- a/packages/backend/src/api/resources/EnterpriseConnection.ts +++ b/packages/backend/src/api/resources/EnterpriseConnection.ts @@ -96,7 +96,7 @@ export class EnterpriseConnectionSamlConnection { /** Whether the SAML connection requires force authentication. */ readonly forceAuthn: boolean, /** The `login_hint` configuration of the SAML connection. */ - readonly loginHint: EnterpriseConnectionSamlConnectionLoginHint | null, + readonly loginHint: EnterpriseConnectionSamlConnectionLoginHint, ) {} static fromJSON(data: EnterpriseConnectionSamlConnectionJSON): EnterpriseConnectionSamlConnection { @@ -118,7 +118,7 @@ export class EnterpriseConnectionSamlConnection { data.allow_idp_initiated, data.active, data.force_authn, - data.login_hint != null ? EnterpriseConnectionSamlConnectionLoginHint.fromJSON(data.login_hint) : null, + EnterpriseConnectionSamlConnectionLoginHint.fromJSON(data.login_hint), ); } } diff --git a/packages/backend/src/api/resources/JSON.ts b/packages/backend/src/api/resources/JSON.ts index 6ba602efb76..87d58ab345c 100644 --- a/packages/backend/src/api/resources/JSON.ts +++ b/packages/backend/src/api/resources/JSON.ts @@ -785,7 +785,7 @@ export interface EnterpriseConnectionSamlConnectionJSON { allow_subdomains: boolean; allow_idp_initiated: boolean; force_authn: boolean; - login_hint?: EnterpriseConnectionSamlConnectionLoginHintJSON | null; + login_hint: EnterpriseConnectionSamlConnectionLoginHintJSON; } export interface EnterpriseConnectionOauthConfigJSON {