diff --git a/.changeset/twelve-sides-cheer.md b/.changeset/twelve-sides-cheer.md new file mode 100644 index 00000000000..163841dae07 --- /dev/null +++ b/.changeset/twelve-sides-cheer.md @@ -0,0 +1,5 @@ +--- +'@clerk/backend': patch +--- + +Fix `attributeMapping` field in the `CreateSamlConnectionParams` and `UpdateSamlConnectionParams` types. diff --git a/packages/backend/src/api/__tests__/SamlConnectionApi.test.ts b/packages/backend/src/api/__tests__/SamlConnectionApi.test.ts index c275927c45e..94b8b7987ce 100644 --- a/packages/backend/src/api/__tests__/SamlConnectionApi.test.ts +++ b/packages/backend/src/api/__tests__/SamlConnectionApi.test.ts @@ -73,4 +73,148 @@ describe('SamlConnectionAPI', () => { expect(response.totalCount).toBe(1); }); }); + + describe('createSamlConnection', () => { + it('successfully creates a SAML connection', async () => { + const mockSamlConnectionResponse = { + object: 'saml_connection', + id: 'samlc_123', + name: 'Test Connection', + provider: 'saml_custom', + domain: 'test.example.com', + organization_id: 'org_123', + created_at: 1672531200000, + updated_at: 1672531200000, + active: true, + sync_user_attributes: false, + allow_subdomains: false, + allow_idp_initiated: false, + idp_entity_id: 'entity_123', + idp_sso_url: 'https://idp.example.com/sso', + idp_certificate: 'cert_data', + idp_metadata_url: null, + idp_metadata: null, + attribute_mapping: { + user_id: 'userId', + email_address: 'email', + first_name: 'firstName', + last_name: 'lastName', + }, + }; + + server.use( + http.post( + 'https://api.clerk.test/v1/saml_connections', + validateHeaders(async ({ request }) => { + const body = await request.json(); + + expect(body).toEqual({ + name: 'Test Connection', + provider: 'saml_custom', + domain: 'test.example.com', + attribute_mapping: { + user_id: 'userId', + email_address: 'email', + first_name: 'firstName', + last_name: 'lastName', + }, + }); + return HttpResponse.json(mockSamlConnectionResponse); + }), + ), + ); + + const response = await apiClient.samlConnections.createSamlConnection({ + name: 'Test Connection', + provider: 'saml_custom', + domain: 'test.example.com', + attributeMapping: { + user_id: 'userId', + email_address: 'email', + first_name: 'firstName', + last_name: 'lastName', + }, + }); + + expect(response.id).toBe('samlc_123'); + expect(response.name).toBe('Test Connection'); + expect(response.organizationId).toBe('org_123'); + }); + }); + + describe('updateSamlConnection', () => { + it('successfully updates a SAML connection', async () => { + const mockSamlConnectionResponse = { + object: 'saml_connection', + id: 'samlc_123', + name: 'Test Connection', + provider: 'saml_custom', + domain: 'test.example.com', + organization_id: 'org_123', + created_at: 1672531200000, + updated_at: 1672531200000, + active: true, + sync_user_attributes: false, + allow_subdomains: false, + allow_idp_initiated: false, + idp_entity_id: 'entity_123', + idp_sso_url: 'https://idp.example.com/sso', + idp_certificate: 'cert_data', + idp_metadata_url: null, + idp_metadata: null, + attribute_mapping: { + user_id: 'userId', + email_address: 'email', + first_name: 'firstName', + last_name: 'lastName', + }, + }; + + server.use( + http.patch( + 'https://api.clerk.test/v1/saml_connections/samlc_123', + validateHeaders(async ({ request }) => { + const body = await request.json(); + + expect(body).toEqual({ + name: 'Test Connection', + provider: 'saml_custom', + domain: 'test.example.com', + organization_id: 'org_123', + idp_entity_id: 'entity_123', + idp_sso_url: 'https://idp.example.com/sso', + idp_certificate: 'cert_data', + attribute_mapping: { + user_id: 'userId', + email_address: 'email', + first_name: 'firstName', + last_name: 'lastName', + }, + }); + return HttpResponse.json(mockSamlConnectionResponse); + }), + ), + ); + + const response = await apiClient.samlConnections.updateSamlConnection('samlc_123', { + name: 'Test Connection', + provider: 'saml_custom', + domain: 'test.example.com', + organizationId: 'org_123', + idpEntityId: 'entity_123', + idpSsoUrl: 'https://idp.example.com/sso', + idpCertificate: 'cert_data', + attributeMapping: { + user_id: 'userId', + email_address: 'email', + first_name: 'firstName', + last_name: 'lastName', + }, + }); + + expect(response.id).toBe('samlc_123'); + expect(response.name).toBe('Test Connection'); + expect(response.organizationId).toBe('org_123'); + }); + }); }); diff --git a/packages/backend/src/api/endpoints/SamlConnectionApi.ts b/packages/backend/src/api/endpoints/SamlConnectionApi.ts index b800b344667..c5a39b30f1a 100644 --- a/packages/backend/src/api/endpoints/SamlConnectionApi.ts +++ b/packages/backend/src/api/endpoints/SamlConnectionApi.ts @@ -39,10 +39,10 @@ type CreateSamlConnectionParams = { idpMetadataUrl?: string; idpMetadata?: string; attributeMapping?: { - emailAddress?: string; - firstName?: string; - lastName?: string; - userId?: string; + email_address?: string; + first_name?: string; + last_name?: string; + user_id?: string; }; }; @@ -57,10 +57,10 @@ type UpdateSamlConnectionParams = { idpMetadataUrl?: string; idpMetadata?: string; attributeMapping?: { - emailAddress?: string; - firstName?: string; - lastName?: string; - userId?: string; + email_address?: string; + first_name?: string; + last_name?: string; + user_id?: string; }; active?: boolean; syncUserAttributes?: boolean; @@ -102,6 +102,7 @@ export class SamlConnectionAPI extends AbstractAPI { bodyParams: params, }); } + public async deleteSamlConnection(samlConnectionId: string) { this.requireId(samlConnectionId); return this.request({