Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fair-doodles-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/backend': patch
---

Introduce `samlConnection` and `oauthConfig` into the `EnterpriseConnection` resource.
30 changes: 30 additions & 0 deletions packages/backend/src/api/__tests__/EnterpriseConnectionApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,30 @@ describe('EnterpriseConnectionAPI', () => {
sync_user_attributes: false,
allow_subdomains: false,
disable_additional_identifications: false,
saml_connection: {
id: 'samlc_1',
name: 'Acme SAML',
idp_entity_id: 'https://idp.example.com',
idp_sso_url: 'https://idp.example.com/sso',
idp_certificate: '-----BEGIN CERTIFICATE-----',
idp_metadata_url: 'https://idp.example.com/metadata',
idp_metadata: '<xml/>',
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,
allow_subdomains: true,
allow_idp_initiated: false,
},
oauth_config: {
id: 'eaoc_1',
name: 'Acme OIDC',
client_id: 'client_abc',
discovery_url: 'https://oauth.example.com/.well-known/openid-configuration',
logo_public_url: 'https://img.example.com/logo.png',
created_at: 1672531200000,
updated_at: 1672531200000,
},
};

describe('createEnterpriseConnection', () => {
Expand Down Expand Up @@ -178,6 +202,12 @@ describe('EnterpriseConnectionAPI', () => {
expect(response.domains).toEqual(['clerk.dev']);
expect(response.active).toBe(true);
expect(response.organizationId).toBeNull();
expect(response.samlConnection).not.toBeNull();
expect(response.samlConnection?.id).toBe('samlc_1');
expect(response.samlConnection?.idpEntityId).toBe('https://idp.example.com');
expect(response.oauthConfig).not.toBeNull();
expect(response.oauthConfig?.clientId).toBe('client_abc');
expect(response.oauthConfig?.discoveryUrl).toBe('https://oauth.example.com/.well-known/openid-configuration');
});
});

Expand Down
139 changes: 138 additions & 1 deletion packages/backend/src/api/resources/EnterpriseConnection.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,131 @@
import type { EnterpriseConnectionJSON } from './JSON';
import type {
EnterpriseConnectionJSON,
EnterpriseConnectionOauthConfigJSON,
EnterpriseConnectionSamlConnectionJSON,
} from './JSON';

export class EnterpriseConnectionSamlConnection {
constructor(
/**
* The unique identifier for the SAML connection.
*/
readonly id: string,
/**
* 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,
/**
* The Single-Sign On URL as provided by the Identity Provider (IdP).
*/
readonly idpSsoUrl: string,
/**
* The X.509 certificate as provided by the Identity Provider (IdP).
*/
readonly idpCertificate: string,
/**
* 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,
/**
* The Assertion Consumer Service (ACS) URL of the connection.
*/
readonly acsUrl: string,
/**
* The Entity ID as provided by the Service Provider (Clerk).
*/
readonly spEntityId: string,
/**
* The metadata URL as provided by the Service Provider (Clerk).
*/
readonly spMetadataUrl: string,
/**
* Indicates whether the connection syncs user attributes between the IdP and Clerk.
*/
readonly syncUserAttributes: boolean,
/**
* Indicates whether users with an email address subdomain are allowed to use this connection.
*/
readonly allowSubdomains: boolean,
/**
* Indicates whether Identity Provider (IdP) initiated flows are allowed.
*/
readonly allowIdpInitiated: boolean,
) {}

static fromJSON(data: EnterpriseConnectionSamlConnectionJSON): EnterpriseConnectionSamlConnection {
return new EnterpriseConnectionSamlConnection(
data.id,
data.name,
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.sync_user_attributes,
data.allow_subdomains,
data.allow_idp_initiated,
);
}
}

/**
* OAuth configuration included on a Backend API {@link EnterpriseConnection} response.
*/
export class EnterpriseConnectionOauthConfig {
constructor(
/**
* The unique identifier for the OAuth configuration.
*/
readonly id: string,
/**
* The name to use as a label for the configuration.
*/
readonly name: string,
/**
* The OAuth client ID.
*/
readonly clientId: string,
/**
* The OpenID Connect discovery URL.
*/
readonly discoveryUrl: string,
/**
* The public URL of the OAuth provider logo, if available.
*/
readonly logoPublicUrl: string,
/**
* The date when the configuration was first created.
*/
readonly createdAt: number,
/**
* The date when the configuration was last updated.
*/
readonly updatedAt: number,
) {}

static fromJSON(data: EnterpriseConnectionOauthConfigJSON): EnterpriseConnectionOauthConfig {
return new EnterpriseConnectionOauthConfig(
data.id,
data.name,
data.client_id,
data.discovery_url,
data.logo_public_url,
data.created_at,
data.updated_at,
);
}
}

/**
* The Backend `EnterpriseConnection` object holds information about an enterprise connection (SAML or OAuth) for an instance or organization.
Expand Down Expand Up @@ -45,6 +172,14 @@ export class EnterpriseConnection {
* The date when the connection was last updated.
*/
readonly updatedAt: number,
/**
* SAML connection details when the enterprise connection uses SAML.
*/
readonly samlConnection: EnterpriseConnectionSamlConnection | null,
/**
* OAuth (OIDC) configuration when the enterprise connection uses OAuth.
*/
readonly oauthConfig: EnterpriseConnectionOauthConfig | null,
) {}

static fromJSON(data: EnterpriseConnectionJSON): EnterpriseConnection {
Expand All @@ -59,6 +194,8 @@ export class EnterpriseConnection {
data.disable_additional_identifications,
data.created_at,
data.updated_at,
data.saml_connection != null ? EnterpriseConnectionSamlConnection.fromJSON(data.saml_connection) : null,
data.oauth_config != null ? EnterpriseConnectionOauthConfig.fromJSON(data.oauth_config) : null,
);
}
}
53 changes: 28 additions & 25 deletions packages/backend/src/api/resources/JSON.ts
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,32 @@ export interface PaginatedResponseJSON {
total_count?: number;
}

export interface EnterpriseConnectionSamlConnectionJSON {
id: string;
name: 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;
sync_user_attributes: boolean;
allow_subdomains: boolean;
allow_idp_initiated: boolean;
}

export interface EnterpriseConnectionOauthConfigJSON {
id: string;
name: string;
client_id: string;
discovery_url: string;
logo_public_url: string;
created_at: number;
updated_at: number;
}

export interface EnterpriseConnectionJSON extends ClerkResourceJSON {
object: typeof ObjectType.EnterpriseConnection;
name: string;
Expand All @@ -715,31 +741,8 @@ export interface EnterpriseConnectionJSON extends ClerkResourceJSON {
disable_additional_identifications: boolean;
created_at: number;
updated_at: number;
saml_connection?: Pick<
SamlConnectionJSON,
| 'id'
| 'name'
| 'idp_entity_id'
| 'idp_sso_url'
| 'idp_certificate'
| 'idp_metadata_url'
| 'idp_metadata'
| 'acs_url'
| 'sp_entity_id'
| 'sp_metadata_url'
| 'sync_user_attributes'
| 'allow_subdomains'
| 'allow_idp_initiated'
>;
oauth_config?: {
id: string;
name: string;
client_id: string;
discovery_url: string;
logo_public_url: string;
created_at: number;
updated_at: number;
};
saml_connection?: EnterpriseConnectionSamlConnectionJSON | null;
oauth_config?: EnterpriseConnectionOauthConfigJSON | null;
}

export interface SamlConnectionJSON extends ClerkResourceJSON {
Expand Down
4 changes: 4 additions & 0 deletions packages/backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ export type {
EmailJSON,
EmailAddressJSON,
EnterpriseConnectionJSON,
EnterpriseConnectionOauthConfigJSON,
EnterpriseConnectionSamlConnectionJSON,
ExternalAccountJSON,
IdentificationLinkJSON,
InstanceJSON,
Expand Down Expand Up @@ -123,6 +125,8 @@ export type {
Domain,
EmailAddress,
EnterpriseConnection,
EnterpriseConnectionOauthConfig,
EnterpriseConnectionSamlConnection,
ExternalAccount,
Feature,
Instance,
Expand Down
Loading