Skip to content

Commit

Permalink
feat(backend): Create SamlConnectionApi and SamlConnection resource (#…
Browse files Browse the repository at this point in the history
…2980)

* feat(backend): Create SamlConnectionApi and SamlConnection resource

* feat(backend): Use camelCase in class properties

* Create afraid-stingrays-suffer.md

* feat(backend): Create SamlConnectionApi and SamlConnection resource

* feat(backend): Use camelCase in class properties

* feat(backend): Add idpMetadata property

* feat(backend): Move attribute mapping class in the saml connection resource file

* Update packages/backend/src/api/resources/SamlConnection.ts

Co-authored-by: Haris Chaniotakis <chanioxaris@gmail.com>

---------

Co-authored-by: Haris Chaniotakis <chanioxaris@gmail.com>
  • Loading branch information
EmmanouelaPothitou and chanioxaris committed Mar 15, 2024
1 parent 66b2836 commit 8c23651
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .changeset/afraid-stingrays-suffer.md
@@ -0,0 +1,11 @@
---
"@clerk/backend": patch
---

Introduce `clerkClient.samlConnections` to expose `getSamlConnectionList`, `createSamlConnection`, `getSamlConnection`, `updateSamlConnection` and `deleteSamlConnection` endpoints. Introduce `SamlConnection` resource for BAPI.

Example:
```
import { clerkClient } from '@clerk/nextjs/server';
const samlConnection = await clerkClient.samlConnections.getSamlConnectionList();
```
92 changes: 92 additions & 0 deletions packages/backend/src/api/endpoints/SamlConnectionApi.ts
@@ -0,0 +1,92 @@
import type { SamlIdpSlug } from '@clerk/types';

import { joinPaths } from '../../util/path';
import type { SamlConnection } from '../resources';
import { AbstractAPI } from './AbstractApi';

const basePath = '/saml_connections';

type SamlConnectionListParams = {
limit?: number;
offset?: number;
};
type CreateSamlConnectionParams = {
name: string;
provider: SamlIdpSlug;
domain: string;
idpEntityId?: string;
idpSsoUrl?: string;
idpCertificate?: string;
idpMetadataUrl?: string;
idpMetadata?: string;
attributeMapping?: {
emailAddress?: string;
firstName?: string;
lastName?: string;
userId?: string;
};
};

type UpdateSamlConnectionParams = {
name?: string;
provider?: SamlIdpSlug;
domain?: string;
idpEntityId?: string;
idpSsoUrl?: string;
idpCertificate?: string;
idpMetadataUrl?: string;
idpMetadata?: string;
attributeMapping?: {
emailAddress?: string;
firstName?: string;
lastName?: string;
userId?: string;
};
active?: boolean;
syncUserAttributes?: boolean;
allowSubdomains?: boolean;
allowIdpInitiated?: boolean;
};

export class SamlConnectionAPI extends AbstractAPI {
public async getSamlConnectionList(params: SamlConnectionListParams = {}) {
return this.request<SamlConnection[]>({
method: 'GET',
path: basePath,
queryParams: params,
});
}

public async createSamlConnection(params: CreateSamlConnectionParams) {
return this.request<SamlConnection>({
method: 'POST',
path: basePath,
bodyParams: params,
});
}

public async getSamlConnection(samlConnectionId: string) {
this.requireId(samlConnectionId);
return this.request<SamlConnection>({
method: 'GET',
path: joinPaths(basePath, samlConnectionId),
});
}

public async updateSamlConnection(samlConnectionId: string, params: UpdateSamlConnectionParams = {}) {
this.requireId(samlConnectionId);

return this.request<SamlConnection>({
method: 'PATCH',
path: joinPaths(basePath, samlConnectionId),
bodyParams: params,
});
}
public async deleteSamlConnection(samlConnectionId: string) {
this.requireId(samlConnectionId);
return this.request<SamlConnection>({
method: 'DELETE',
path: joinPaths(basePath, samlConnectionId),
});
}
}
1 change: 1 addition & 0 deletions packages/backend/src/api/endpoints/index.ts
Expand Up @@ -10,3 +10,4 @@ export * from './RedirectUrlApi';
export * from './SessionApi';
export * from './SignInTokenApi';
export * from './UserApi';
export * from './SamlConnectionApi';
2 changes: 2 additions & 0 deletions packages/backend/src/api/factory.ts
Expand Up @@ -7,6 +7,7 @@ import {
OrganizationAPI,
PhoneNumberAPI,
RedirectUrlAPI,
SamlConnectionAPI,
SessionAPI,
SignInTokenAPI,
UserAPI,
Expand All @@ -32,5 +33,6 @@ export function createBackendApiClient(options: CreateBackendApiOptions) {
signInTokens: new SignInTokenAPI(request),
users: new UserAPI(request),
domains: new DomainAPI(request),
samlConnections: new SamlConnectionAPI(request),
};
}
29 changes: 29 additions & 0 deletions packages/backend/src/api/resources/JSON.ts
Expand Up @@ -327,3 +327,32 @@ export interface PaginatedResponseJSON {
data: object[];
total_count?: number;
}

export interface SamlConnectionJSON extends ClerkResourceJSON {
name: string;
domain: string;
idp_entity_id: string;
idp_sso_url: string;
idp_certificate: string;
idp_metadata_url: string;
idp_metadata: string;
acs_url: string;
sp_entity_id: string;
sp_metadata_url: string;
active: boolean;
provider: string;
user_count: number;
sync_user_attributes: boolean;
allow_subdomains: boolean;
allow_idp_initiated: boolean;
created_at: number;
updated_at: number;
attribute_mapping: AttributeMappingJSON;
}

export interface AttributeMappingJSON {
user_id: string;
email_address: string;
first_name: string;
last_name: string;
}
63 changes: 63 additions & 0 deletions packages/backend/src/api/resources/SamlConnection.ts
@@ -0,0 +1,63 @@
import type { AttributeMappingJSON, SamlConnectionJSON } from './JSON';

export class SamlConnection {
constructor(
readonly id: string,
readonly name: string,
readonly domain: string,
readonly idpEntityId: string | null,
readonly idpSsoUrl: string | null,
readonly idpCertificate: string | null,
readonly idpMetadataUrl: string | null,
readonly idpMetadata: string | null,
readonly acsUrl: string,
readonly spEntityId: string,
readonly spMetadataUrl: string,
readonly active: boolean,
readonly provider: string,
readonly userCount: number,
readonly syncUserAttributes: boolean,
readonly allowSubdomains: boolean,
readonly allowIdpInitiated: boolean,
readonly createdAt: number,
readonly updatedAt: number,
readonly attributeMapping: AttributeMapping,
) {}
static fromJSON(data: SamlConnectionJSON): SamlConnection {
return new SamlConnection(
data.id,
data.name,
data.domain,
data.idp_entity_id,
data.idp_sso_url,
data.idp_certificate,
data.idp_metadata_url,
data.idp_metadata,
data.acs_url,
data.sp_entity_id,
data.sp_metadata_url,
data.active,
data.provider,
data.user_count,
data.sync_user_attributes,
data.allow_subdomains,
data.allow_idp_initiated,
data.created_at,
data.updated_at,
data.attribute_mapping && AttributeMapping.fromJSON(data.attribute_mapping),
);
}
}

class AttributeMapping {
constructor(
readonly userId: string,
readonly emailAddress: string,
readonly firstName: string,
readonly lastName: string,
) {}

static fromJSON(data: AttributeMappingJSON): AttributeMapping {
return new AttributeMapping(data.user_id, data.email_address, data.first_name, data.last_name);
}
}
1 change: 1 addition & 0 deletions packages/backend/src/api/resources/index.ts
Expand Up @@ -30,6 +30,7 @@ export * from './SMSMessage';
export * from './Token';
export * from './User';
export * from './Verification';
export * from './SamlConnection';

export type {
EmailWebhookEvent,
Expand Down

0 comments on commit 8c23651

Please sign in to comment.