diff --git a/.changeset/thirty-candies-lick.md b/.changeset/thirty-candies-lick.md
new file mode 100644
index 00000000000..250d28dd911
--- /dev/null
+++ b/.changeset/thirty-candies-lick.md
@@ -0,0 +1,12 @@
+---
+'@clerk/localizations': minor
+'@clerk/clerk-js': minor
+'@clerk/shared': minor
+'@clerk/astro': minor
+'@clerk/react': minor
+'@clerk/nuxt': minor
+'@clerk/vue': minor
+'@clerk/ui': minor
+---
+
+Add experimental `` component. Not ready for usage yet.
diff --git a/packages/astro/src/astro-components/index.ts b/packages/astro/src/astro-components/index.ts
index 0f02bca09ff..facc4145374 100644
--- a/packages/astro/src/astro-components/index.ts
+++ b/packages/astro/src/astro-components/index.ts
@@ -31,3 +31,4 @@ export { default as Waitlist } from './interactive/Waitlist.astro';
export { default as OAuthConsent } from './interactive/OAuthConsent.astro';
export { default as PricingTable } from './interactive/PricingTable.astro';
export { default as APIKeys } from './interactive/APIKeys.astro';
+export { default as __experimental_ConfigureSSO } from './interactive/ConfigureSSO.astro';
diff --git a/packages/astro/src/astro-components/interactive/ConfigureSSO.astro b/packages/astro/src/astro-components/interactive/ConfigureSSO.astro
new file mode 100644
index 00000000000..9fdb7bf37f0
--- /dev/null
+++ b/packages/astro/src/astro-components/interactive/ConfigureSSO.astro
@@ -0,0 +1,11 @@
+---
+import type { __experimental_ConfigureSSOProps } from '@clerk/shared/types';
+type Props = __experimental_ConfigureSSOProps;
+
+import InternalUIComponentRenderer from './InternalUIComponentRenderer.astro';
+---
+
+
diff --git a/packages/astro/src/internal/mount-clerk-astro-js-components.ts b/packages/astro/src/internal/mount-clerk-astro-js-components.ts
index 97720d3de67..c4a6ac81ed8 100644
--- a/packages/astro/src/internal/mount-clerk-astro-js-components.ts
+++ b/packages/astro/src/internal/mount-clerk-astro-js-components.ts
@@ -21,7 +21,7 @@ const mountAllClerkAstroJSComponents = () => {
waitlist: 'mountWaitlist',
'pricing-table': 'mountPricingTable',
'api-keys': 'mountAPIKeys',
- 'oauth-consent': 'mountOAuthConsent',
+ 'configure-sso': '__experimental_mountConfigureSSO',
} as const satisfies Record;
Object.entries(mountFns).forEach(([category, mountFn]) => {
diff --git a/packages/astro/src/types.ts b/packages/astro/src/types.ts
index 5807f6c3b3e..d2a2a89a22b 100644
--- a/packages/astro/src/types.ts
+++ b/packages/astro/src/types.ts
@@ -120,4 +120,4 @@ export type InternalUIComponentId =
| 'waitlist'
| 'pricing-table'
| 'api-keys'
- | 'oauth-consent';
+ | 'configure-sso';
diff --git a/packages/clerk-js/bundlewatch.config.json b/packages/clerk-js/bundlewatch.config.json
index 3aef7fb1570..bcea517d7e1 100644
--- a/packages/clerk-js/bundlewatch.config.json
+++ b/packages/clerk-js/bundlewatch.config.json
@@ -2,8 +2,8 @@
"files": [
{ "path": "./dist/clerk.js", "maxSize": "543KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "70KB" },
- { "path": "./dist/clerk.legacy.browser.js", "maxSize": "110KB" },
- { "path": "./dist/clerk.no-rhc.js", "maxSize": "309KB" },
+ { "path": "./dist/clerk.legacy.browser.js", "maxSize": "112KB" },
+ { "path": "./dist/clerk.no-rhc.js", "maxSize": "311KB" },
{ "path": "./dist/clerk.native.js", "maxSize": "70KB" },
{ "path": "./dist/vendors*.js", "maxSize": "7KB" },
{ "path": "./dist/coinbase*.js", "maxSize": "36KB" },
diff --git a/packages/clerk-js/sandbox/app.ts b/packages/clerk-js/sandbox/app.ts
index 37b6433e226..8277c29a117 100644
--- a/packages/clerk-js/sandbox/app.ts
+++ b/packages/clerk-js/sandbox/app.ts
@@ -32,6 +32,7 @@ const AVAILABLE_COMPONENTS = [
'waitlist',
'pricingTable',
'apiKeys',
+ 'configureSSO',
'oauthConsent',
'taskChooseOrganization',
'taskResetPassword',
@@ -136,6 +137,7 @@ const componentControls: Record = {
waitlist: buildComponentControls('waitlist'),
pricingTable: buildComponentControls('pricingTable'),
apiKeys: buildComponentControls('apiKeys'),
+ configureSSO: buildComponentControls('configureSSO'),
oauthConsent: buildComponentControls('oauthConsent'),
taskChooseOrganization: buildComponentControls('taskChooseOrganization'),
taskResetPassword: buildComponentControls('taskResetPassword'),
@@ -468,6 +470,9 @@ void (async () => {
'/api-keys': () => {
Clerk.mountAPIKeys(app, componentControls.apiKeys.getProps() ?? {});
},
+ '/configure-sso': () => {
+ Clerk.__experimental_mountConfigureSSO(app, componentControls.configureSSO.getProps() ?? {});
+ },
'/oauth-consent': () => {
const searchParams = new URLSearchParams(window.location.search);
const scopes = (searchParams.get('scope')?.split(',') ?? []).map(scope => ({
diff --git a/packages/clerk-js/sandbox/template.html b/packages/clerk-js/sandbox/template.html
index 422e7496cb8..9591fe7e852 100644
--- a/packages/clerk-js/sandbox/template.html
+++ b/packages/clerk-js/sandbox/template.html
@@ -177,6 +177,14 @@
API Keys
+
+
+ ConfigureSSO
+
+
ui.ensureMounted()).then(controls => controls.unmountComponent({ node }));
};
- public mountOAuthConsent = (node: HTMLDivElement, props?: OAuthConsentProps) => {
+ public mountOAuthConsent = (node: HTMLDivElement, props?: __internal_OAuthConsentProps) => {
if (noUserExists(this)) {
if (this.#instanceType === 'development') {
throw new ClerkRuntimeError(warnings.cannotRenderOAuthConsentComponentWhenUserDoesNotExist, {
@@ -1450,6 +1455,59 @@ export class Clerk implements ClerkInterface {
void this.#clerkUI?.then(ui => ui.ensureMounted()).then(controls => controls.unmountComponent({ node }));
};
+ /**
+ * Mount a configure SSO component at the target element.
+ *
+ * @experimental
+ * @param targetNode Target to mount the ConfigureSSO component.
+ * @param props Configuration parameters.
+ */
+ public __experimental_mountConfigureSSO = (node: HTMLDivElement, props?: __experimental_ConfigureSSOProps) => {
+ if (disabledSelfServeSSOFeature(this, this.environment)) {
+ if (this.#instanceType === 'development') {
+ throw new ClerkRuntimeError(warnings.cannotRenderConfigureSSOComponentWhenDisabled, {
+ code: CANNOT_RENDER_SELF_SERVE_SSO_DISABLED_ERROR_CODE,
+ });
+ }
+ return;
+ }
+
+ if (disabledEmailAddressAttribute(this, this.environment)) {
+ if (this.#instanceType === 'development') {
+ throw new ClerkRuntimeError(warnings.cannotRenderConfigureSSOComponentWhenEmailAddressDisabled, {
+ code: CANNOT_RENDER_CONFIGURE_SSO_EMAIL_ADDRESS_DISABLED_ERROR_CODE,
+ });
+ }
+ return;
+ }
+
+ this.assertComponentsReady(this.#clerkUI);
+ const component = 'ConfigureSSO';
+ void this.#clerkUI
+ .then(ui => ui.ensureMounted({ preloadHint: component }))
+ .then(controls =>
+ controls.mountComponent({
+ name: component,
+ appearanceKey: '__experimental_configureSSO',
+ node,
+ props,
+ }),
+ );
+
+ this.telemetry?.record(eventPrebuiltComponentMounted(component, props));
+ };
+
+ /**
+ * Unmount a configure SSO component from the target element.
+ * If there is no component mounted at the target node, results in a noop.
+ *
+ * @experimental
+ * @param targetNode Target node to unmount the ConfigureSSO component from.
+ */
+ public __experimental_unmountConfigureSSO = (node: HTMLDivElement) => {
+ void this.#clerkUI?.then(ui => ui.ensureMounted()).then(controls => controls.unmountComponent({ node }));
+ };
+
public mountTaskChooseOrganization = (node: HTMLDivElement, props?: TaskChooseOrganizationProps) => {
const { isEnabled: isOrganizationsEnabled } = this.__internal_attemptToEnableEnvironmentSetting({
for: 'organizations',
diff --git a/packages/clerk-js/src/core/resources/UserSettings.ts b/packages/clerk-js/src/core/resources/UserSettings.ts
index 48a8c85a426..aaabb6738b6 100644
--- a/packages/clerk-js/src/core/resources/UserSettings.ts
+++ b/packages/clerk-js/src/core/resources/UserSettings.ts
@@ -105,6 +105,7 @@ export class UserSettings extends BaseResource implements UserSettingsResource {
};
enterpriseSSO: EnterpriseSSOSettings = {
enabled: false,
+ self_serve_sso: false,
};
passkeySettings: PasskeySettingsData = {
allow_autofill: false,
diff --git a/packages/clerk-js/src/test/fixture-helpers.ts b/packages/clerk-js/src/test/fixture-helpers.ts
index b1564bcd841..f3498850197 100644
--- a/packages/clerk-js/src/test/fixture-helpers.ts
+++ b/packages/clerk-js/src/test/fixture-helpers.ts
@@ -536,7 +536,7 @@ const createUserSettingsFixtureHelpers = (environment: EnvironmentJSON) => {
const withEnterpriseSso = () => {
us.saml = { enabled: true };
- us.enterprise_sso = { enabled: true };
+ us.enterprise_sso = { enabled: true, self_serve_sso: false };
};
const withBackupCode = (opts?: Partial) => {
diff --git a/packages/localizations/src/ar-SA.ts b/packages/localizations/src/ar-SA.ts
index 79c8c63c469..e32c9bfc2b7 100644
--- a/packages/localizations/src/ar-SA.ts
+++ b/packages/localizations/src/ar-SA.ts
@@ -178,6 +178,11 @@ export const arSA: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'تكوين تسجيل الدخول الموحد (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'أنشاء منظمة',
invitePage: {
diff --git a/packages/localizations/src/be-BY.ts b/packages/localizations/src/be-BY.ts
index c5b109d1dca..2b16a7ae936 100644
--- a/packages/localizations/src/be-BY.ts
+++ b/packages/localizations/src/be-BY.ts
@@ -178,6 +178,11 @@ export const beBY: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Налада адзінага ўваходу (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Стварыць арганізацыю',
invitePage: {
diff --git a/packages/localizations/src/bg-BG.ts b/packages/localizations/src/bg-BG.ts
index 49004e24135..96704ca286f 100644
--- a/packages/localizations/src/bg-BG.ts
+++ b/packages/localizations/src/bg-BG.ts
@@ -179,6 +179,11 @@ export const bgBG: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Конфигуриране на единен вход (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Създаване на организация',
invitePage: {
diff --git a/packages/localizations/src/bn-IN.ts b/packages/localizations/src/bn-IN.ts
index b9a2463165b..765c3d7815a 100644
--- a/packages/localizations/src/bn-IN.ts
+++ b/packages/localizations/src/bn-IN.ts
@@ -178,6 +178,11 @@ export const bnIN: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'একক সাইন-অন (SSO) কনফিগার করুন',
+ },
+ },
createOrganization: {
formButtonSubmit: 'সংগঠন তৈরি করুন',
invitePage: {
diff --git a/packages/localizations/src/ca-ES.ts b/packages/localizations/src/ca-ES.ts
index ab92189175a..fd021b11257 100644
--- a/packages/localizations/src/ca-ES.ts
+++ b/packages/localizations/src/ca-ES.ts
@@ -185,6 +185,11 @@ export const caES: LocalizationResource = {
viewPayment: 'Veure pagament',
year: 'Any',
},
+ configureSSO: {
+ navbar: {
+ title: "Configura l'inici de sessió únic (SSO)",
+ },
+ },
createOrganization: {
formButtonSubmit: 'Crea organització',
invitePage: {
diff --git a/packages/localizations/src/cs-CZ.ts b/packages/localizations/src/cs-CZ.ts
index 34da5326211..e23888e312f 100644
--- a/packages/localizations/src/cs-CZ.ts
+++ b/packages/localizations/src/cs-CZ.ts
@@ -182,6 +182,11 @@ export const csCZ: LocalizationResource = {
viewPayment: undefined,
year: 'Rok',
},
+ configureSSO: {
+ navbar: {
+ title: 'Nastavit jednotné přihlášení (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Vytvořit organizaci',
invitePage: {
diff --git a/packages/localizations/src/da-DK.ts b/packages/localizations/src/da-DK.ts
index 472f49f2ae6..5df63b312ed 100644
--- a/packages/localizations/src/da-DK.ts
+++ b/packages/localizations/src/da-DK.ts
@@ -178,6 +178,11 @@ export const daDK: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Konfigurer single sign-on (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Opret organisation',
invitePage: {
diff --git a/packages/localizations/src/de-DE.ts b/packages/localizations/src/de-DE.ts
index f4fb1d2ba13..db24f051d2e 100644
--- a/packages/localizations/src/de-DE.ts
+++ b/packages/localizations/src/de-DE.ts
@@ -184,6 +184,11 @@ export const deDE: LocalizationResource = {
viewPayment: 'Zahlung anzeigen',
year: 'Jahr',
},
+ configureSSO: {
+ navbar: {
+ title: 'Single Sign-On (SSO) konfigurieren',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Organisation erstellen',
invitePage: {
diff --git a/packages/localizations/src/el-GR.ts b/packages/localizations/src/el-GR.ts
index 4ba17bb6493..9147179a512 100644
--- a/packages/localizations/src/el-GR.ts
+++ b/packages/localizations/src/el-GR.ts
@@ -178,6 +178,11 @@ export const elGR: LocalizationResource = {
viewPayment: 'Προβολή πληρωμής',
year: 'έτος',
},
+ configureSSO: {
+ navbar: {
+ title: 'Διαμόρφωση Ενιαίας Σύνδεσης (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Δημιουργία οργανισμού',
invitePage: {
diff --git a/packages/localizations/src/en-GB.ts b/packages/localizations/src/en-GB.ts
index b0aa4889f53..d529df0a938 100644
--- a/packages/localizations/src/en-GB.ts
+++ b/packages/localizations/src/en-GB.ts
@@ -178,6 +178,11 @@ export const enGB: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Configure Single Sign-On (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Create organisation',
invitePage: {
diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts
index 3b5b3e1bc61..21f706f2883 100644
--- a/packages/localizations/src/en-US.ts
+++ b/packages/localizations/src/en-US.ts
@@ -197,6 +197,11 @@ export const enUS: LocalizationResource = {
yearAbbreviation: 'yr',
yearPerUnit: 'Year per {{unitName}}',
},
+ configureSSO: {
+ navbar: {
+ title: 'Configure Single Sign-On (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Create organization',
invitePage: {
diff --git a/packages/localizations/src/es-CR.ts b/packages/localizations/src/es-CR.ts
index e305c0d0e6c..8b1028c51f1 100644
--- a/packages/localizations/src/es-CR.ts
+++ b/packages/localizations/src/es-CR.ts
@@ -178,6 +178,11 @@ export const esCR: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Configurar inicio de sesión único (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Crear organización',
invitePage: {
diff --git a/packages/localizations/src/es-ES.ts b/packages/localizations/src/es-ES.ts
index 45982e3c4be..6e0736e7078 100644
--- a/packages/localizations/src/es-ES.ts
+++ b/packages/localizations/src/es-ES.ts
@@ -184,6 +184,11 @@ export const esES: LocalizationResource = {
viewPayment: 'Ver pago',
year: 'Año',
},
+ configureSSO: {
+ navbar: {
+ title: 'Configurar inicio de sesión único (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Crear organización',
invitePage: {
diff --git a/packages/localizations/src/es-MX.ts b/packages/localizations/src/es-MX.ts
index cb340de4858..12a91d526e5 100644
--- a/packages/localizations/src/es-MX.ts
+++ b/packages/localizations/src/es-MX.ts
@@ -179,6 +179,11 @@ export const esMX: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Configurar inicio de sesión único (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Crear organización',
invitePage: {
diff --git a/packages/localizations/src/es-UY.ts b/packages/localizations/src/es-UY.ts
index a4a387ef619..dc9a5f1fac2 100644
--- a/packages/localizations/src/es-UY.ts
+++ b/packages/localizations/src/es-UY.ts
@@ -178,6 +178,11 @@ export const esUY: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Configurar inicio de sesión único (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Crear organización',
invitePage: {
diff --git a/packages/localizations/src/fa-IR.ts b/packages/localizations/src/fa-IR.ts
index 04c9b1ef62b..1389120f971 100644
--- a/packages/localizations/src/fa-IR.ts
+++ b/packages/localizations/src/fa-IR.ts
@@ -183,6 +183,11 @@ export const faIR: LocalizationResource = {
viewPayment: 'مشاهده پرداخت',
year: 'سال',
},
+ configureSSO: {
+ navbar: {
+ title: 'پیکربندی ورود یکپارچه (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'ایجاد سازمان',
invitePage: {
diff --git a/packages/localizations/src/fi-FI.ts b/packages/localizations/src/fi-FI.ts
index e4fa4e1a821..d835761ecbc 100644
--- a/packages/localizations/src/fi-FI.ts
+++ b/packages/localizations/src/fi-FI.ts
@@ -206,6 +206,11 @@ export const fiFI: LocalizationResource = {
yearAbbreviation: 'v',
yearPerUnit: 'Vuosi per {{unitName}}',
},
+ configureSSO: {
+ navbar: {
+ title: 'Määritä kertakirjautuminen (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Luo organisaatio',
invitePage: {
diff --git a/packages/localizations/src/fr-FR.ts b/packages/localizations/src/fr-FR.ts
index 5e4b3c05764..9f7fdfaee50 100644
--- a/packages/localizations/src/fr-FR.ts
+++ b/packages/localizations/src/fr-FR.ts
@@ -186,6 +186,11 @@ export const frFR: LocalizationResource = {
viewPayment: 'Voir le paiement',
year: 'An',
},
+ configureSSO: {
+ navbar: {
+ title: "Configurer l'authentification unique (SSO)",
+ },
+ },
createOrganization: {
formButtonSubmit: 'Créer l’organisation',
invitePage: {
diff --git a/packages/localizations/src/he-IL.ts b/packages/localizations/src/he-IL.ts
index 29913555481..6771d4daf90 100644
--- a/packages/localizations/src/he-IL.ts
+++ b/packages/localizations/src/he-IL.ts
@@ -178,6 +178,11 @@ export const heIL: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'הגדרת כניסה אחידה (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'צור ארגון',
invitePage: {
diff --git a/packages/localizations/src/hi-IN.ts b/packages/localizations/src/hi-IN.ts
index 94039ba7ee2..29651d6cbd3 100644
--- a/packages/localizations/src/hi-IN.ts
+++ b/packages/localizations/src/hi-IN.ts
@@ -178,6 +178,11 @@ export const hiIN: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'सिंगल साइन-ऑन (SSO) कॉन्फ़िगर करें',
+ },
+ },
createOrganization: {
formButtonSubmit: 'संगठन बनाएँ',
invitePage: {
diff --git a/packages/localizations/src/hr-HR.ts b/packages/localizations/src/hr-HR.ts
index da8a1f39024..1af45a26c6e 100644
--- a/packages/localizations/src/hr-HR.ts
+++ b/packages/localizations/src/hr-HR.ts
@@ -207,6 +207,11 @@ export const hrHR: LocalizationResource = {
yearAbbreviation: 'god',
yearPerUnit: 'Godina po {{unitName}}',
},
+ configureSSO: {
+ navbar: {
+ title: 'Konfiguriraj jedinstvenu prijavu (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'kreiraj organizaciju',
invitePage: {
diff --git a/packages/localizations/src/hu-HU.ts b/packages/localizations/src/hu-HU.ts
index 9b634dc17de..8ba7b812c75 100644
--- a/packages/localizations/src/hu-HU.ts
+++ b/packages/localizations/src/hu-HU.ts
@@ -207,6 +207,11 @@ export const huHU: LocalizationResource = {
yearAbbreviation: 'év',
yearPerUnit: 'Év / {{unitName}}',
},
+ configureSSO: {
+ navbar: {
+ title: 'Egyszeri bejelentkezés (SSO) beállítása',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Szervezet létrehozása',
invitePage: {
diff --git a/packages/localizations/src/id-ID.ts b/packages/localizations/src/id-ID.ts
index 1297208c560..0b9880267ad 100644
--- a/packages/localizations/src/id-ID.ts
+++ b/packages/localizations/src/id-ID.ts
@@ -178,6 +178,11 @@ export const idID: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Konfigurasi Single Sign-On (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Buat organisasi',
invitePage: {
diff --git a/packages/localizations/src/is-IS.ts b/packages/localizations/src/is-IS.ts
index 686dc893e31..e32720033ca 100644
--- a/packages/localizations/src/is-IS.ts
+++ b/packages/localizations/src/is-IS.ts
@@ -206,6 +206,11 @@ export const isIS: LocalizationResource = {
yearAbbreviation: 'ár',
yearPerUnit: 'Ár á {{unitName}}',
},
+ configureSSO: {
+ navbar: {
+ title: 'Stilla einnar innskráningar (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Stofna samtök',
invitePage: {
diff --git a/packages/localizations/src/it-IT.ts b/packages/localizations/src/it-IT.ts
index 7fd8e514f1c..93ee04f749c 100644
--- a/packages/localizations/src/it-IT.ts
+++ b/packages/localizations/src/it-IT.ts
@@ -184,6 +184,11 @@ export const itIT: LocalizationResource = {
viewPayment: undefined,
year: 'Anno',
},
+ configureSSO: {
+ navbar: {
+ title: 'Configura Single Sign-On (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Crea organizzazione',
invitePage: {
diff --git a/packages/localizations/src/ja-JP.ts b/packages/localizations/src/ja-JP.ts
index 053cc788f0d..a9f62ce514f 100644
--- a/packages/localizations/src/ja-JP.ts
+++ b/packages/localizations/src/ja-JP.ts
@@ -189,6 +189,11 @@ export const jaJP: LocalizationResource = {
viewPayment: '支払いを表示',
year: '年',
},
+ configureSSO: {
+ navbar: {
+ title: 'シングルサインオン(SSO)を設定',
+ },
+ },
createOrganization: {
formButtonSubmit: '組織を作成する',
invitePage: {
diff --git a/packages/localizations/src/kk-KZ.ts b/packages/localizations/src/kk-KZ.ts
index d75f6034f2c..1c7c752c36a 100644
--- a/packages/localizations/src/kk-KZ.ts
+++ b/packages/localizations/src/kk-KZ.ts
@@ -178,6 +178,11 @@ export const kkKZ: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Бірыңғай кіруді конфигурациялау (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Ұйым құру',
invitePage: {
diff --git a/packages/localizations/src/ko-KR.ts b/packages/localizations/src/ko-KR.ts
index 28d9d3d309d..ddfec4d8212 100644
--- a/packages/localizations/src/ko-KR.ts
+++ b/packages/localizations/src/ko-KR.ts
@@ -182,6 +182,11 @@ export const koKR: LocalizationResource = {
viewPayment: '결제 보기',
year: '년',
},
+ configureSSO: {
+ navbar: {
+ title: '싱글 사인온(SSO) 구성',
+ },
+ },
createOrganization: {
formButtonSubmit: '조직 만들기',
invitePage: {
diff --git a/packages/localizations/src/mn-MN.ts b/packages/localizations/src/mn-MN.ts
index 66ac4813eb4..4ccdebd039d 100644
--- a/packages/localizations/src/mn-MN.ts
+++ b/packages/localizations/src/mn-MN.ts
@@ -178,6 +178,11 @@ export const mnMN: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Нэгдсэн нэвтрэлт (SSO) тохируулах',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Байгуулга үүсгэх',
invitePage: {
diff --git a/packages/localizations/src/ms-MY.ts b/packages/localizations/src/ms-MY.ts
index ddd520f34f9..0e8da7e7832 100644
--- a/packages/localizations/src/ms-MY.ts
+++ b/packages/localizations/src/ms-MY.ts
@@ -178,6 +178,11 @@ export const msMY: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Konfigurasi Log Masuk Tunggal (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Cipta organisasi',
invitePage: {
diff --git a/packages/localizations/src/nb-NO.ts b/packages/localizations/src/nb-NO.ts
index da2737185f0..b063903b209 100644
--- a/packages/localizations/src/nb-NO.ts
+++ b/packages/localizations/src/nb-NO.ts
@@ -207,6 +207,11 @@ export const nbNO: LocalizationResource = {
yearAbbreviation: 'år',
yearPerUnit: 'År per {{unitName}}',
},
+ configureSSO: {
+ navbar: {
+ title: 'Konfigurer enkeltpålogging (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Opprett organisasjon',
invitePage: {
diff --git a/packages/localizations/src/nl-BE.ts b/packages/localizations/src/nl-BE.ts
index cf172ff19cb..10df71a968a 100644
--- a/packages/localizations/src/nl-BE.ts
+++ b/packages/localizations/src/nl-BE.ts
@@ -178,6 +178,11 @@ export const nlBE: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Single sign-on (SSO) configureren',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Creëer organisatie',
invitePage: {
diff --git a/packages/localizations/src/nl-NL.ts b/packages/localizations/src/nl-NL.ts
index 860e62983d6..128189d82db 100644
--- a/packages/localizations/src/nl-NL.ts
+++ b/packages/localizations/src/nl-NL.ts
@@ -178,6 +178,11 @@ export const nlNL: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Single sign-on (SSO) configureren',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Creëer organisatie',
invitePage: {
diff --git a/packages/localizations/src/pl-PL.ts b/packages/localizations/src/pl-PL.ts
index 7a4e2d3d116..d87215cc89a 100644
--- a/packages/localizations/src/pl-PL.ts
+++ b/packages/localizations/src/pl-PL.ts
@@ -178,6 +178,11 @@ export const plPL: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Skonfiguruj logowanie jednokrotne (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Utwórz organizację',
invitePage: {
diff --git a/packages/localizations/src/pt-BR.ts b/packages/localizations/src/pt-BR.ts
index c4c17027071..604fde40ec2 100644
--- a/packages/localizations/src/pt-BR.ts
+++ b/packages/localizations/src/pt-BR.ts
@@ -184,6 +184,11 @@ export const ptBR: LocalizationResource = {
viewPayment: 'Ver pagamento',
year: 'Ano',
},
+ configureSSO: {
+ navbar: {
+ title: 'Configurar logon único (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Criar organização',
invitePage: {
diff --git a/packages/localizations/src/pt-PT.ts b/packages/localizations/src/pt-PT.ts
index 0dc1f68eaae..76519707741 100644
--- a/packages/localizations/src/pt-PT.ts
+++ b/packages/localizations/src/pt-PT.ts
@@ -186,6 +186,11 @@ export const ptPT: LocalizationResource = {
viewPayment: 'Ver pagamento',
year: 'Ano',
},
+ configureSSO: {
+ navbar: {
+ title: 'Configurar autenticação única (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Criar organização',
invitePage: {
diff --git a/packages/localizations/src/ro-RO.ts b/packages/localizations/src/ro-RO.ts
index eadcabedded..c54f0159634 100644
--- a/packages/localizations/src/ro-RO.ts
+++ b/packages/localizations/src/ro-RO.ts
@@ -184,6 +184,11 @@ export const roRO: LocalizationResource = {
viewPayment: 'Vezi plata',
year: 'An',
},
+ configureSSO: {
+ navbar: {
+ title: 'Configurați autentificarea unică (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Creează organizație',
invitePage: {
diff --git a/packages/localizations/src/ru-RU.ts b/packages/localizations/src/ru-RU.ts
index 3dcfeb98df0..439dbabad3f 100644
--- a/packages/localizations/src/ru-RU.ts
+++ b/packages/localizations/src/ru-RU.ts
@@ -178,6 +178,11 @@ export const ruRU: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Настроить единый вход (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Создать организацию',
invitePage: {
diff --git a/packages/localizations/src/sk-SK.ts b/packages/localizations/src/sk-SK.ts
index 6fcd15b73e9..6d141338a80 100644
--- a/packages/localizations/src/sk-SK.ts
+++ b/packages/localizations/src/sk-SK.ts
@@ -178,6 +178,11 @@ export const skSK: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Nastaviť jednotné prihlasovanie (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Vytvoriť organizáciu',
invitePage: {
diff --git a/packages/localizations/src/sr-RS.ts b/packages/localizations/src/sr-RS.ts
index fbcca7e1d6c..5edc8c961d6 100644
--- a/packages/localizations/src/sr-RS.ts
+++ b/packages/localizations/src/sr-RS.ts
@@ -178,6 +178,11 @@ export const srRS: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Konfiguriši jedinstvenu prijavu (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Kreiraj organizaciju',
invitePage: {
diff --git a/packages/localizations/src/sv-SE.ts b/packages/localizations/src/sv-SE.ts
index a5e80ff65ed..fb3d7b2d18a 100644
--- a/packages/localizations/src/sv-SE.ts
+++ b/packages/localizations/src/sv-SE.ts
@@ -178,6 +178,11 @@ export const svSE: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Konfigurera enkel inloggning (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Skapa organisation',
invitePage: {
diff --git a/packages/localizations/src/ta-IN.ts b/packages/localizations/src/ta-IN.ts
index 5baa4de9e6c..77fa6116a45 100644
--- a/packages/localizations/src/ta-IN.ts
+++ b/packages/localizations/src/ta-IN.ts
@@ -178,6 +178,11 @@ export const taIN: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'ஒற்றை உள்நுழைவை (SSO) உள்ளமை',
+ },
+ },
createOrganization: {
formButtonSubmit: 'நிறுவனத்தை உருவாக்கு',
invitePage: {
diff --git a/packages/localizations/src/te-IN.ts b/packages/localizations/src/te-IN.ts
index 4d63ab5b552..a019b92757a 100644
--- a/packages/localizations/src/te-IN.ts
+++ b/packages/localizations/src/te-IN.ts
@@ -178,6 +178,11 @@ export const teIN: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'సింగిల్ సైన్-ఆన్ (SSO) కాన్ఫిగర్ చేయండి',
+ },
+ },
createOrganization: {
formButtonSubmit: 'సంస్థను సృష్టించండి',
invitePage: {
diff --git a/packages/localizations/src/th-TH.ts b/packages/localizations/src/th-TH.ts
index b074c63a6a9..d8c8264b878 100644
--- a/packages/localizations/src/th-TH.ts
+++ b/packages/localizations/src/th-TH.ts
@@ -182,6 +182,11 @@ export const thTH: LocalizationResource = {
viewPayment: 'ดูการชำระเงิน',
year: 'ปี',
},
+ configureSSO: {
+ navbar: {
+ title: 'กำหนดค่าการลงชื่อเข้าใช้แบบครั้งเดียว (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'สร้างองค์กร',
invitePage: {
diff --git a/packages/localizations/src/tr-TR.ts b/packages/localizations/src/tr-TR.ts
index e5af54c494c..cfddf9e7a04 100644
--- a/packages/localizations/src/tr-TR.ts
+++ b/packages/localizations/src/tr-TR.ts
@@ -178,6 +178,11 @@ export const trTR: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Tek Oturum Açmayı (SSO) Yapılandır',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Oluştur',
invitePage: {
diff --git a/packages/localizations/src/uk-UA.ts b/packages/localizations/src/uk-UA.ts
index 01495d07413..d1f62de46c8 100644
--- a/packages/localizations/src/uk-UA.ts
+++ b/packages/localizations/src/uk-UA.ts
@@ -178,6 +178,11 @@ export const ukUA: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: 'Налаштувати єдиний вхід (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Створити організацію',
invitePage: {
diff --git a/packages/localizations/src/vi-VN.ts b/packages/localizations/src/vi-VN.ts
index 512e3b2672d..411ca53019b 100644
--- a/packages/localizations/src/vi-VN.ts
+++ b/packages/localizations/src/vi-VN.ts
@@ -182,6 +182,11 @@ export const viVN: LocalizationResource = {
viewPayment: undefined,
year: 'Năm',
},
+ configureSSO: {
+ navbar: {
+ title: 'Cấu hình đăng nhập một lần (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: 'Tạo tổ chức',
invitePage: {
diff --git a/packages/localizations/src/zh-CN.ts b/packages/localizations/src/zh-CN.ts
index f11b0913eda..8835fdfc716 100644
--- a/packages/localizations/src/zh-CN.ts
+++ b/packages/localizations/src/zh-CN.ts
@@ -178,6 +178,11 @@ export const zhCN: LocalizationResource = {
viewPayment: undefined,
year: undefined,
},
+ configureSSO: {
+ navbar: {
+ title: '配置单点登录 (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: '创建组织',
invitePage: {
diff --git a/packages/localizations/src/zh-TW.ts b/packages/localizations/src/zh-TW.ts
index c37d6efd9ea..5bd804bfe98 100644
--- a/packages/localizations/src/zh-TW.ts
+++ b/packages/localizations/src/zh-TW.ts
@@ -184,6 +184,11 @@ export const zhTW: LocalizationResource = {
viewPayment: '查看付款',
year: '年',
},
+ configureSSO: {
+ navbar: {
+ title: '設定單一登入 (SSO)',
+ },
+ },
createOrganization: {
formButtonSubmit: '創建組織',
invitePage: {
diff --git a/packages/nuxt/src/module.ts b/packages/nuxt/src/module.ts
index 897b2ff9f03..ccabf817440 100644
--- a/packages/nuxt/src/module.ts
+++ b/packages/nuxt/src/module.ts
@@ -198,5 +198,22 @@ export default defineNuxtModule({
filePath: '@clerk/vue',
});
});
+
+ /**
+ * Experimental components from `@clerk/vue/experimental`.
+ * @experimental These components and their prop types are unstable and may change in future releases.
+ */
+ // eslint-disable-next-line @typescript-eslint/consistent-type-imports
+ const experimentalComponents: Array = [
+ // SSO
+ 'ConfigureSSO',
+ ];
+ experimentalComponents.forEach(component => {
+ void addComponent({
+ name: component,
+ export: component,
+ filePath: '@clerk/vue/experimental',
+ });
+ });
},
});
diff --git a/packages/react/src/components/uiComponents.tsx b/packages/react/src/components/uiComponents.tsx
index a87b83af675..ba7c941618b 100644
--- a/packages/react/src/components/uiComponents.tsx
+++ b/packages/react/src/components/uiComponents.tsx
@@ -1,4 +1,5 @@
import type {
+ __experimental_ConfigureSSOProps,
__internal_OAuthConsentProps,
APIKeysProps,
CreateOrganizationProps,
@@ -644,6 +645,37 @@ export const APIKeys = withClerk(
{ component: 'ApiKeys', renderWhileLoading: true },
);
+/**
+ * @experimental This component is in early access and may change in future releases.
+ */
+export const ConfigureSSO = withClerk(
+ ({ clerk, component, fallback, ...props }: WithClerkProp<__experimental_ConfigureSSOProps & FallbackProp>) => {
+ const mountingStatus = useWaitForComponentMount(component);
+ const shouldShowFallback = mountingStatus === 'rendering' || !clerk.loaded;
+
+ const rendererRootProps = {
+ ...(shouldShowFallback && fallback && { style: { display: 'none' } }),
+ };
+
+ return (
+ <>
+ {shouldShowFallback && fallback}
+ {clerk.loaded && (
+
+ )}
+ >
+ );
+ },
+ { component: 'ConfigureSSO', renderWhileLoading: true },
+);
+
export const OAuthConsent = withClerk(
({ clerk, component, fallback, ...props }: WithClerkProp<__internal_OAuthConsentProps & FallbackProp>) => {
const mountingStatus = useWaitForComponentMount(component);
diff --git a/packages/react/src/experimental.ts b/packages/react/src/experimental.ts
index 001206478e7..c5deea83347 100644
--- a/packages/react/src/experimental.ts
+++ b/packages/react/src/experimental.ts
@@ -2,10 +2,21 @@ export { CheckoutButton } from './components/CheckoutButton';
export { PlanDetailsButton } from './components/PlanDetailsButton';
export { SubscriptionDetailsButton } from './components/SubscriptionDetailsButton';
+/**
+ * @experimental
+ * This component and its prop types are unstable and may change in future releases.
+ */
+export { ConfigureSSO } from './components/uiComponents';
+
export type {
__experimental_CheckoutButtonProps as CheckoutButtonProps,
__experimental_SubscriptionDetailsButtonProps as SubscriptionDetailsButtonProps,
__experimental_PlanDetailsButtonProps as PlanDetailsButtonProps,
+ /**
+ * @experimental
+ * This type is unstable and may change in future releases.
+ */
+ __experimental_ConfigureSSOProps as ConfigureSSOProps,
} from '@clerk/shared/types';
export {
diff --git a/packages/react/src/isomorphicClerk.ts b/packages/react/src/isomorphicClerk.ts
index b47acb36f15..513a79653fc 100644
--- a/packages/react/src/isomorphicClerk.ts
+++ b/packages/react/src/isomorphicClerk.ts
@@ -2,6 +2,7 @@ import { inBrowser } from '@clerk/shared/browser';
import { clerkEvents, createClerkEventBus } from '@clerk/shared/clerkEventBus';
import { loadClerkJSScript, loadClerkUIScript } from '@clerk/shared/loadClerkJsScript';
import type {
+ __experimental_ConfigureSSOProps,
__internal_AttemptToEnableEnvironmentSettingParams,
__internal_AttemptToEnableEnvironmentSettingResult,
__internal_CheckoutProps,
@@ -159,6 +160,7 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk {
private premountWaitlistNodes = new Map();
private premountPricingTableNodes = new Map();
private premountAPIKeysNodes = new Map();
+ private premountConfigureSSONodes = new Map();
private premountOAuthConsentNodes = new Map();
private premountTaskChooseOrganizationNodes = new Map();
private premountTaskResetPasswordNodes = new Map();
@@ -747,6 +749,10 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk {
clerkjs.mountAPIKeys(node, props);
});
+ this.premountConfigureSSONodes.forEach((props, node) => {
+ clerkjs.__experimental_mountConfigureSSO(node, props);
+ });
+
this.premountOAuthConsentNodes.forEach((props, node) => {
clerkjs.__internal_mountOAuthConsent(node, props);
});
@@ -1283,7 +1289,23 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk {
}
};
- __internal_mountOAuthConsent = (node: HTMLDivElement, props?: __internal_OAuthConsentProps) => {
+ __experimental_mountConfigureSSO = (node: HTMLDivElement, props?: __experimental_ConfigureSSOProps): void => {
+ if (this.clerkjs && this.loaded) {
+ this.clerkjs.__experimental_mountConfigureSSO(node, props);
+ } else {
+ this.premountConfigureSSONodes.set(node, props);
+ }
+ };
+
+ __experimental_unmountConfigureSSO = (node: HTMLDivElement): void => {
+ if (this.clerkjs && this.loaded) {
+ this.clerkjs.__experimental_unmountConfigureSSO(node);
+ } else {
+ this.premountConfigureSSONodes.delete(node);
+ }
+ };
+
+ __internal_mountOAuthConsent = (node: HTMLDivElement, props?: OAuthConsentProps) => {
if (this.clerkjs && this.loaded) {
this.clerkjs.__internal_mountOAuthConsent(node, props);
} else {
diff --git a/packages/shared/src/internal/clerk-js/componentGuards.ts b/packages/shared/src/internal/clerk-js/componentGuards.ts
index 9b3fec8f82b..06f9ac443b9 100644
--- a/packages/shared/src/internal/clerk-js/componentGuards.ts
+++ b/packages/shared/src/internal/clerk-js/componentGuards.ts
@@ -45,3 +45,11 @@ export const disabledOrganizationAPIKeysFeature: ComponentGuard = (_, environmen
export const disabledAllAPIKeysFeatures: ComponentGuard = (_, environment) => {
return disabledUserAPIKeysFeature(_, environment) && disabledOrganizationAPIKeysFeature(_, environment);
};
+
+export const disabledSelfServeSSOFeature: ComponentGuard = (_, environment) => {
+ return !environment?.userSettings.enterpriseSSO.self_serve_sso;
+};
+
+export const disabledEmailAddressAttribute: ComponentGuard = (_, environment) => {
+ return !environment?.userSettings.attributes.email_address?.enabled;
+};
diff --git a/packages/shared/src/internal/clerk-js/warnings.ts b/packages/shared/src/internal/clerk-js/warnings.ts
index 2686713eaf7..94ba1e4e7e9 100644
--- a/packages/shared/src/internal/clerk-js/warnings.ts
+++ b/packages/shared/src/internal/clerk-js/warnings.ts
@@ -64,6 +64,10 @@ const warnings = {
'The component cannot be rendered when organization API keys are disabled. Since organization API keys are disabled, this is no-op.',
cannotRenderOAuthConsentComponentWhenUserDoesNotExist:
' cannot render unless a user is signed in. Since no user is signed in, this is no-op.',
+ cannotRenderConfigureSSOComponentWhenDisabled:
+ 'The component cannot be rendered when self-serve SSO is disabled. Visit `https://dashboard.clerk.com` to enable the feature. Since self-serve SSO is disabled, this is no-op.',
+ cannotRenderConfigureSSOComponentWhenEmailAddressDisabled:
+ 'The component cannot be rendered when email addresses are disabled on the instance. Visit `https://dashboard.clerk.com` to enable email addresses. Since email addresses are disabled, this is no-op.',
};
type SerializableWarnings = Serializable;
diff --git a/packages/shared/src/types/clerk.ts b/packages/shared/src/types/clerk.ts
index be87e83f76f..88613446bcb 100644
--- a/packages/shared/src/types/clerk.ts
+++ b/packages/shared/src/types/clerk.ts
@@ -661,6 +661,26 @@ export interface Clerk {
*/
unmountAPIKeys: (targetNode: HTMLDivElement) => void;
+ /**
+ * Mount a configure SSO component at the target element.
+ *
+ * @experimental This method is in early access and may change in future releases.
+ *
+ * @param targetNode - Target to mount the ConfigureSSO component.
+ * @param props - Configuration parameters.
+ */
+ __experimental_mountConfigureSSO: (targetNode: HTMLDivElement, props?: __experimental_ConfigureSSOProps) => void;
+
+ /**
+ * Unmount a configure SSO component from the target element.
+ * If there is no component mounted at the target node, results in a noop.
+ *
+ * @experimental This method is in early access and may change in future releases.
+ *
+ * @param targetNode - Target node to unmount the ConfigureSSO component from.
+ */
+ __experimental_unmountConfigureSSO: (targetNode: HTMLDivElement) => void;
+
/**
* Mounts a OAuth consent component at the target element.
*
@@ -2149,6 +2169,18 @@ export type APIKeysProps = {
showDescription?: boolean;
};
+/**
+ * @experimental This type is in early access and may change in future releases.
+ */
+export type __experimental_ConfigureSSOProps = {
+ /**
+ * Customisation options to fully match the Clerk components to your own brand.
+ * These options serve as overrides and will be merged with the global `appearance`
+ * prop of ClerkProvider (if one is provided)
+ */
+ appearance?: ClerkAppearanceTheme;
+};
+
export type GetAPIKeysParams = ClerkPaginationParams<{
subject?: string;
query?: string;
diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts
index 222509565bb..33f3d1d6e21 100644
--- a/packages/shared/src/types/localization.ts
+++ b/packages/shared/src/types/localization.ts
@@ -1292,6 +1292,11 @@ export type __internal_LocalizationResource = {
message: LocalizationValue;
};
};
+ configureSSO: {
+ navbar: {
+ title: LocalizationValue;
+ };
+ };
apiKeys: {
formTitle: LocalizationValue;
formHint: LocalizationValue;
diff --git a/packages/shared/src/types/userSettings.ts b/packages/shared/src/types/userSettings.ts
index f8424d1eba6..dafa0190251 100644
--- a/packages/shared/src/types/userSettings.ts
+++ b/packages/shared/src/types/userSettings.ts
@@ -92,6 +92,7 @@ export type OAuthProviders = {
};
export type EnterpriseSSOSettings = {
enabled: boolean;
+ self_serve_sso: boolean;
};
export type AttributesJSON = {
diff --git a/packages/ui/src/components/ConfigureSSO/ConfigureSSO.tsx b/packages/ui/src/components/ConfigureSSO/ConfigureSSO.tsx
new file mode 100644
index 00000000000..4b744a8a8d0
--- /dev/null
+++ b/packages/ui/src/components/ConfigureSSO/ConfigureSSO.tsx
@@ -0,0 +1,117 @@
+import { useOrganization } from '@clerk/shared/react/index';
+import type { __experimental_ConfigureSSOProps } from '@clerk/shared/types';
+import React from 'react';
+
+import { useEnvironment, withCoreUserGuard } from '@/contexts';
+import { Box, Col, Flex, Flow, Icon, localizationKeys, Text, useAppearance } from '@/customizables';
+import { ApplicationLogo } from '@/elements/ApplicationLogo';
+import { withCardStateProvider } from '@/elements/contexts';
+import { NavBar, NavbarContextProvider } from '@/elements/Navbar';
+import { ProfileCard } from '@/elements/ProfileCard';
+import { BoxIcon } from '@/icons';
+import { Route, Switch } from '@/router';
+
+const ConfigureSSOInternal = () => {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+};
+
+const AuthenticatedContent = withCoreUserGuard(() => {
+ const contentRef = React.useRef(null);
+ const { applicationName, logoImageUrl } = useEnvironment().displayConfig;
+ const { organizationSettings } = useEnvironment();
+ const { parsedOptions } = useAppearance();
+ const hasLogo = Boolean(parsedOptions.logoImageUrl || logoImageUrl);
+
+ return (
+ ({ display: 'grid', gridTemplateColumns: '1fr 3fr', height: t.sizes.$176, overflow: 'hidden' })}
+ >
+
+ ({
+ gap: t.space.$2,
+ padding: `${t.space.$none} ${t.space.$3}`,
+ maxWidth: '100%',
+ })}
+ >
+ {hasLogo ? (
+ ({ width: t.space.$9, height: t.space.$9, borderRadius: t.radii.$md, overflow: 'hidden' })}
+ />
+ ) : (
+ ({
+ width: t.space.$9,
+ height: t.space.$9,
+ flexShrink: 0,
+ borderRadius: t.radii.$md,
+ backgroundColor: t.colors.$primary500,
+ color: t.colors.$colorPrimaryForeground,
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ })}
+ aria-hidden
+ >
+ ({ width: t.sizes.$4, height: t.sizes.$4 })}
+ />
+
+ )}
+
+
+
+ {applicationName}
+
+ {organizationSettings.enabled && }
+
+
+ }
+ titleSx={t => ({ fontSize: t.fontSizes.$lg })}
+ title={localizationKeys('configureSSO.navbar.title')}
+ routes={[]}
+ contentRef={contentRef}
+ />
+
+
+
+ );
+});
+
+const OrganizationSidebarSubtitle = () => {
+ const { organization } = useOrganization();
+
+ if (!organization) {
+ return null;
+ }
+
+ return (
+ ({ color: t.colors.$colorMutedForeground })}
+ >
+ {organization?.name}
+
+ );
+};
+
+export const ConfigureSSO: React.ComponentType<__experimental_ConfigureSSOProps> =
+ withCardStateProvider(ConfigureSSOInternal);
diff --git a/packages/ui/src/contexts/ClerkUIComponentsContext.tsx b/packages/ui/src/contexts/ClerkUIComponentsContext.tsx
index 282160cf2af..24a3760c385 100644
--- a/packages/ui/src/contexts/ClerkUIComponentsContext.tsx
+++ b/packages/ui/src/contexts/ClerkUIComponentsContext.tsx
@@ -1,5 +1,6 @@
import type {
OAuthConsentProps,
+ __experimental_ConfigureSSOProps,
APIKeysProps,
PricingTableProps,
TaskChooseOrganizationProps,
@@ -13,6 +14,7 @@ import type { ReactNode } from 'react';
import type { AvailableComponentName, AvailableComponentProps } from '../types';
import {
APIKeysContext,
+ ConfigureSSOContext,
CreateOrganizationContext,
GoogleOneTapContext,
OAuthConsentContext,
@@ -114,6 +116,12 @@ export function ComponentContextProvider({
{children}
);
+ case 'ConfigureSSO':
+ return (
+
+ {children}
+
+ );
case 'OAuthConsent': {
// Translate capital-A `oAuth*` props from the accounts portal into
// the lowercase `oauth*` context shape the component reads.
diff --git a/packages/ui/src/contexts/components/ConfigureSSO.ts b/packages/ui/src/contexts/components/ConfigureSSO.ts
new file mode 100644
index 00000000000..7ce177a6d85
--- /dev/null
+++ b/packages/ui/src/contexts/components/ConfigureSSO.ts
@@ -0,0 +1,20 @@
+import { createContext, useContext } from 'react';
+
+import type { ConfigureSSOCtx } from '../../types';
+
+export const ConfigureSSOContext = createContext(null);
+
+export const useConfigureSSOContext = () => {
+ const context = useContext(ConfigureSSOContext);
+
+ if (!context || context.componentName !== 'ConfigureSSO') {
+ throw new Error('Clerk: useConfigureSSOContext called outside ConfigureSSO.');
+ }
+
+ const { componentName, ...ctx } = context;
+
+ return {
+ ...ctx,
+ componentName,
+ };
+};
diff --git a/packages/ui/src/contexts/components/index.ts b/packages/ui/src/contexts/components/index.ts
index 4242c494ad6..25b15a20fab 100644
--- a/packages/ui/src/contexts/components/index.ts
+++ b/packages/ui/src/contexts/components/index.ts
@@ -1,5 +1,6 @@
export * from './APIKeys';
export * from './Checkout';
+export * from './ConfigureSSO';
export * from './CreateOrganization';
export * from './GoogleOneTap';
export * from './OAuthConsent';
diff --git a/packages/ui/src/elements/Navbar.tsx b/packages/ui/src/elements/Navbar.tsx
index 8b2a577c792..1871c0c5825 100644
--- a/packages/ui/src/elements/Navbar.tsx
+++ b/packages/ui/src/elements/Navbar.tsx
@@ -7,7 +7,7 @@ import type { ElementDescriptor, ElementId } from '../customizables/elementDescr
import { useNavigateToFlowStart, usePopover } from '../hooks';
import { Menu } from '../icons';
import { useRouter } from '../router';
-import type { PropsOfComponent } from '../styledSystem';
+import type { PropsOfComponent, ThemableCssProp } from '../styledSystem';
import { animations, common, mqu } from '../styledSystem';
import { colors } from '../utils/colors';
import { Card } from './Card';
@@ -44,14 +44,15 @@ export type NavbarRoute = {
};
type NavBarProps = {
title: LocalizationKey;
- description: LocalizationKey;
+ titleSx?: ThemableCssProp;
+ description?: LocalizationKey;
contentRef: React.RefObject;
routes: NavbarRoute[];
header?: React.ReactNode;
};
export const NavBar = (props: NavBarProps) => {
- const { contentRef, title, description, routes, header } = props;
+ const { contentRef, title, titleSx, description, routes, header } = props;
const { close } = useNavbarContext();
const { navigate } = useRouter();
const { navigateToFlowStart } = useNavigateToFlowStart();
@@ -126,6 +127,7 @@ export const NavBar = (props: NavBarProps) => {
<>
{header}
@@ -140,9 +142,13 @@ export const NavBar = (props: NavBarProps) => {
};
const NavbarContainer = (
- props: React.PropsWithChildren<{ title: LocalizationKey | string; description: LocalizationKey | string }>,
+ props: React.PropsWithChildren<{
+ title: LocalizationKey | string;
+ titleSx?: ThemableCssProp;
+ description?: LocalizationKey | string;
+ }>,
) => {
- const { title, description } = props;
+ const { title, titleSx, description } = props;
return (
-
+ {description ? (
+
+ ) : null}
{props.children}
diff --git a/packages/ui/src/elements/contexts/index.tsx b/packages/ui/src/elements/contexts/index.tsx
index cecccfe3d88..44eef53bf88 100644
--- a/packages/ui/src/elements/contexts/index.tsx
+++ b/packages/ui/src/elements/contexts/index.tsx
@@ -98,6 +98,7 @@ export type FlowMetadata = {
| 'planDetails'
| 'pricingTable'
| 'apiKeys'
+ | 'configureSSO'
| 'oauthConsent'
| 'subscriptionDetails'
| 'tasks'
diff --git a/packages/ui/src/icons/box.svg b/packages/ui/src/icons/box.svg
new file mode 100644
index 00000000000..b000531e8b0
--- /dev/null
+++ b/packages/ui/src/icons/box.svg
@@ -0,0 +1 @@
+
diff --git a/packages/ui/src/icons/index.ts b/packages/ui/src/icons/index.ts
index 497b15f1abf..e282f04aae8 100644
--- a/packages/ui/src/icons/index.ts
+++ b/packages/ui/src/icons/index.ts
@@ -13,6 +13,7 @@ export { default as ArrowsUpDown } from './arrows-up-down.svg';
export { default as AuthApp } from './auth-app.svg';
export { default as Billing } from './billing.svg';
export { default as Block } from './block.svg';
+export { default as BoxIcon } from './box.svg';
export { default as Caret } from './caret.svg';
export { default as CaretLeft } from './caret-left.svg';
export { default as CaretRight } from './caret-right.svg';
diff --git a/packages/ui/src/internal/appearance.ts b/packages/ui/src/internal/appearance.ts
index 71bc4815a94..cd0ce04dcfe 100644
--- a/packages/ui/src/internal/appearance.ts
+++ b/packages/ui/src/internal/appearance.ts
@@ -1014,6 +1014,7 @@ export type CheckoutTheme = Theme;
export type PlanDetailTheme = Theme;
export type SubscriptionDetailsTheme = Theme;
export type APIKeysTheme = Theme;
+export type __experimental_ConfigureSSOTheme = Theme;
export type OAuthConsentTheme = Theme;
export type TaskChooseOrganizationTheme = Theme;
export type TaskResetPasswordTheme = Theme;
@@ -1090,6 +1091,10 @@ export type Appearance = T &
* Theme overrides that only apply to the `` component
*/
apiKeys?: T;
+ /**
+ * Theme overrides that only apply to the `` component
+ */
+ __experimental_configureSSO?: T;
/**
* Theme overrides that only apply to the `` component
*/
diff --git a/packages/ui/src/lazyModules/components.ts b/packages/ui/src/lazyModules/components.ts
index 0cc57f424ca..3c8e62f7e39 100644
--- a/packages/ui/src/lazyModules/components.ts
+++ b/packages/ui/src/lazyModules/components.ts
@@ -29,6 +29,7 @@ const componentImportPaths = {
PlanDetails: () => import(/* webpackChunkName: "planDetails" */ '../components/Plans/PlanDetails'),
SubscriptionDetails: () => import(/* webpackChunkName: "subscriptionDetails" */ '../components/SubscriptionDetails'),
APIKeys: () => import(/* webpackChunkName: "apiKeys" */ '../components/APIKeys/APIKeys'),
+ ConfigureSSO: () => import(/* webpackChunkName: "configureSSO" */ '../components/ConfigureSSO/ConfigureSSO'),
OAuthConsent: () => import(/* webpackChunkName: "oauthConsent" */ '../components/OAuthConsent/OAuthConsent'),
EnableOrganizationsPrompt: () =>
import(/* webpackChunkName: "enableOrganizationsPrompt" */ '../components/devPrompts/EnableOrganizationsPrompt'),
@@ -120,6 +121,10 @@ export const PricingTable = lazy(() =>
export const APIKeys = lazy(() => componentImportPaths.APIKeys().then(module => ({ default: module.APIKeys })));
+export const ConfigureSSO = lazy(() =>
+ componentImportPaths.ConfigureSSO().then(module => ({ default: module.ConfigureSSO })),
+);
+
export const Checkout = lazy(() => componentImportPaths.Checkout().then(module => ({ default: module.Checkout })));
export const TaskChooseOrganization = lazy(() =>
@@ -180,6 +185,7 @@ export const ClerkComponents = {
Checkout,
PlanDetails,
APIKeys,
+ ConfigureSSO,
OAuthConsent,
SubscriptionDetails,
TaskChooseOrganization,
diff --git a/packages/ui/src/types.ts b/packages/ui/src/types.ts
index 8bf8cbddd30..28b3d26c07a 100644
--- a/packages/ui/src/types.ts
+++ b/packages/ui/src/types.ts
@@ -1,4 +1,5 @@
import type {
+ __experimental_ConfigureSSOProps,
__internal_CheckoutProps,
OAuthConsentProps,
__internal_PlanDetailsProps,
@@ -64,6 +65,7 @@ export type AvailableComponentProps =
| __internal_SubscriptionDetailsProps
| __internal_PlanDetailsProps
| APIKeysProps
+ | __experimental_ConfigureSSOProps
| OAuthConsentProps
| TaskChooseOrganizationProps
| TaskResetPasswordProps
@@ -145,6 +147,11 @@ export type APIKeysCtx = APIKeysProps & {
mode?: ComponentMode;
};
+export type ConfigureSSOCtx = __experimental_ConfigureSSOProps & {
+ componentName: 'ConfigureSSO';
+ mode?: ComponentMode;
+};
+
export type CheckoutCtx = __internal_CheckoutProps & {
componentName: 'Checkout';
} & NewSubscriptionRedirectUrl;
@@ -249,6 +256,7 @@ export type AvailableComponentCtx =
| PricingTableCtx
| CheckoutCtx
| APIKeysCtx
+ | ConfigureSSOCtx
| OAuthConsentCtx
| SubscriptionDetailsCtx
| PlanDetailsCtx
diff --git a/packages/vue/src/components/ui-components/ConfigureSSO.vue b/packages/vue/src/components/ui-components/ConfigureSSO.vue
new file mode 100644
index 00000000000..bcdd2eea036
--- /dev/null
+++ b/packages/vue/src/components/ui-components/ConfigureSSO.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/packages/vue/src/experimental.ts b/packages/vue/src/experimental.ts
index 63264348f21..285e05a3d09 100644
--- a/packages/vue/src/experimental.ts
+++ b/packages/vue/src/experimental.ts
@@ -19,6 +19,13 @@ export { default as CheckoutButton } from './components/CheckoutButton.vue';
*/
export { default as PlanDetailsButton } from './components/PlanDetailsButton.vue';
+/**
+ * @experimental
+ * These components and their prop types are unstable and may change in future releases.
+ * They are part of Clerk's self-serve SSO feature which is not available yet.
+ * */
+export { default as ConfigureSSO } from './components/ui-components/ConfigureSSO.vue';
+
export type {
/**
* @experimental
@@ -31,11 +38,17 @@ export type {
* These components and their prop types are unstable and may change in future releases.
* They are part of Clerk's Billing feature which is available under public beta.
*/
- __experimental_PlanDetailsButtonProps as PlanDetailsButtonProps,
+ __experimental_ConfigureSSOProps as ConfigureSSOProps,
/**
* @experimental
* These components and their prop types are unstable and may change in future releases.
* They are part of Clerk's Billing feature which is available under public beta.
*/
+ __experimental_PlanDetailsButtonProps as PlanDetailsButtonProps,
+ /**
+ * @experimental
+ * These components and their prop types are unstable and may change in future releases.
+ * They are part of Clerk's self-serve SSO feature which is not available yet.
+ */
__experimental_SubscriptionDetailsButtonProps as SubscriptionDetailsButtonProps,
} from '@clerk/shared/types';