From 09cfbe74bc83b7889215e630f4ee7cd81d86e03f Mon Sep 17 00:00:00 2001 From: Nicolas Lopes Date: Mon, 20 Jul 2026 16:57:30 -0300 Subject: [PATCH 1/8] feat(ui): add OIDC ConfigureSSO wizard skeleton --- .changeset/cool-dragons-march.md | 2 + .changeset/spotty-items-dream.md | 2 + packages/localizations/src/en-US.ts | 19 +++ packages/shared/src/types/localization.ts | 19 +++ .../organizationEnterpriseConnection.test.ts | 68 ++++++++ .../organizationEnterpriseConnection.ts | 29 +++- ...eOrganizationEnterpriseConnection.test.tsx | 10 +- .../__tests__/ConfigureStep.test.tsx | 90 ++++++++++ .../steps/ConfigureStep/index.tsx | 42 +++-- .../oidc/OidcCustomConfigureSteps.tsx | 157 ++++++++++++++++++ .../steps/ConfigureStep/oidc/index.tsx | 1 + .../ConfigureSSO/steps/SelectProviderStep.tsx | 43 ++++- .../__tests__/SelectProviderStep.test.tsx | 27 +++ .../ui/src/components/ConfigureSSO/types.ts | 23 ++- 14 files changed, 505 insertions(+), 27 deletions(-) create mode 100644 .changeset/cool-dragons-march.md create mode 100644 .changeset/spotty-items-dream.md create mode 100644 packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx create mode 100644 packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx create mode 100644 packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/index.tsx diff --git a/.changeset/cool-dragons-march.md b/.changeset/cool-dragons-march.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/cool-dragons-march.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/spotty-items-dream.md b/.changeset/spotty-items-dream.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/spotty-items-dream.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts index d766d4ce383..e7419100697 100644 --- a/packages/localizations/src/en-US.ts +++ b/packages/localizations/src/en-US.ts @@ -239,6 +239,21 @@ export const enUS: LocalizationResource = { required: 'Required', }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: 'Set the claims your identity provider includes in the ID token', + }, + credentialsStep: { + headerSubtitle: 'Add your application credentials', + }, + endpointsStep: { + headerSubtitle: 'Add your identity provider’s endpoints', + }, + mainHeaderTitle: 'Configure your identity provider', + redirectUriStep: { + headerSubtitle: 'Create a new OIDC application in your identity provider’s dashboard', + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: 'Assign users or groups to your SAML application', @@ -694,6 +709,10 @@ export const enUS: LocalizationResource = { title: 'Reset connection', }, selectProviderStep: { + oidc: { + groupLabel: 'OpenID Connect (OIDC)', + oidcProvider: 'OIDC Provider', + }, saml: { customSaml: 'Custom SAML Provider', google: 'Google Workspace', diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts index 9ca7ecee35e..88df4c9b294 100644 --- a/packages/shared/src/types/localization.ts +++ b/packages/shared/src/types/localization.ts @@ -1403,6 +1403,10 @@ export type __internal_LocalizationResource = { google: LocalizationValue; microsoft: LocalizationValue; }; + oidc: { + groupLabel: LocalizationValue; + oidcProvider: LocalizationValue; + }; warning: LocalizationValue; }; changeProviderDialog: { @@ -1521,6 +1525,21 @@ export type __internal_LocalizationResource = { title: LocalizationValue; dismiss: LocalizationValue; }; + oidcCustom: { + mainHeaderTitle: LocalizationValue; + redirectUriStep: { + headerSubtitle: LocalizationValue; + }; + claimsStep: { + headerSubtitle: LocalizationValue; + }; + endpointsStep: { + headerSubtitle: LocalizationValue; + }; + credentialsStep: { + headerSubtitle: LocalizationValue; + }; + }; samlOkta: { mainHeaderTitle: LocalizationValue; createAppStep: { diff --git a/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts b/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts index 23dbbb2841a..847acd860b1 100644 --- a/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts +++ b/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts @@ -1,6 +1,7 @@ import type { EmailAddressResource, EnterpriseConnectionResource, + EnterpriseOAuthConfigResource, OrganizationDomainResource, SamlAccountConnectionResource, UserResource, @@ -24,6 +25,14 @@ const makeSamlConnection = (overrides: Partial = ...overrides, }) as SamlAccountConnectionResource; +const makeOauthConfig = (overrides: Partial = {}): EnterpriseOAuthConfigResource => + ({ + id: 'oauth_1', + name: 'oidc', + clientId: '', + ...overrides, + }) as EnterpriseOAuthConfigResource; + const makeConnection = (overrides: Partial = {}): EnterpriseConnectionResource => ({ id: 'enc_1', @@ -49,6 +58,11 @@ const fullyConfiguredSaml = makeSamlConnection({ idpMetadataUrl: 'https://idp.example.com/metadata', }); +const configuredOidc = makeOauthConfig({ clientId: 'client_abc' }); + +const makeOidcConnection = (overrides: Partial = {}): EnterpriseConnectionResource => + makeConnection({ provider: 'oidc_custom', samlConnection: null, oauthConfig: configuredOidc, ...overrides }); + // Builds the entity with sensible defaults; each test overrides what it cares // about. const derive = (overrides: Partial[0]> = {}) => @@ -79,6 +93,11 @@ describe('organizationEnterpriseConnection', () => { it('connection → its provider', () => { expect(derive({ connection: makeConnection({ provider: 'saml_custom' }) }).provider).toBe('saml_custom'); }); + it('carries a derived OIDC key verbatim — the open family, not the oidc_custom alias', () => { + // The backend derives `oidc_` from the connection name; the entity must + // expose that real value so dispatch can prefix-match it. + expect(derive({ connection: makeConnection({ provider: 'oidc_clerk_dev' }) }).provider).toBe('oidc_clerk_dev'); + }); }); describe('isActive', () => { @@ -122,6 +141,17 @@ describe('organizationEnterpriseConnection', () => { }).hasMinimumConfiguration, ).toBe(false); }); + it('oidc client id present → true', () => { + expect(derive({ connection: makeOidcConnection() }).hasMinimumConfiguration).toBe(true); + }); + it('oidc without oauth config → false', () => { + expect(derive({ connection: makeOidcConnection({ oauthConfig: null }) }).hasMinimumConfiguration).toBe(false); + }); + it('oidc with empty client id → false', () => { + expect( + derive({ connection: makeOidcConnection({ oauthConfig: makeOauthConfig() }) }).hasMinimumConfiguration, + ).toBe(false); + }); }); describe('hasSuccessfulTestRun', () => { @@ -197,6 +227,17 @@ describe('organizationEnterpriseConnection', () => { }).status, ).toBe('active'); }); + it('oidc configured + successfully tested + not active → inactive', () => { + expect( + derive({ + connection: makeOidcConnection({ active: false }), + hasSuccessfulTestRun: true, + }).status, + ).toBe('inactive'); + }); + it('active oidc connection → active', () => { + expect(derive({ connection: makeOidcConnection({ active: true }) }).status).toBe('active'); + }); }); it('is pure: identical inputs produce a deep-equal entity', () => { @@ -247,10 +288,37 @@ describe('isEnterpriseConnectionConfigured', () => { it('idpSsoUrl + idpEntityId present → true', () => { expect(isEnterpriseConnectionConfigured(makeConnection({ samlConnection: fullyConfiguredSaml }))).toBe(true); }); + it('oidc with no oauth config → false', () => { + expect(isEnterpriseConnectionConfigured(makeOidcConnection({ oauthConfig: null }))).toBe(false); + }); + it('oidc with empty client id → false', () => { + expect(isEnterpriseConnectionConfigured(makeOidcConnection({ oauthConfig: makeOauthConfig() }))).toBe(false); + }); + it('oidc with client id present → true', () => { + expect(isEnterpriseConnectionConfigured(makeOidcConnection())).toBe(true); + }); + it('branches on provider: an oidc connection is not satisfied by saml fields', () => { + expect( + isEnterpriseConnectionConfigured( + makeOidcConnection({ oauthConfig: makeOauthConfig(), samlConnection: fullyConfiguredSaml }), + ), + ).toBe(false); + }); + it('branches on provider: a saml connection is not satisfied by oauth fields', () => { + expect( + isEnterpriseConnectionConfigured( + makeConnection({ provider: 'saml_okta', samlConnection: null, oauthConfig: configuredOidc }), + ), + ).toBe(false); + }); it('matches the derived `hasMinimumConfiguration` field', () => { const connection = makeConnection({ samlConnection: fullyConfiguredSaml }); expect(isEnterpriseConnectionConfigured(connection)).toBe(derive({ connection }).hasMinimumConfiguration); }); + it('matches the derived `hasMinimumConfiguration` field for oidc', () => { + const connection = makeOidcConnection(); + expect(isEnterpriseConnectionConfigured(connection)).toBe(derive({ connection }).hasMinimumConfiguration); + }); }); describe('areAllOrganizationDomainsVerified', () => { diff --git a/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts b/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts index fd9f7c7bd56..cf285e5b4cf 100644 --- a/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts +++ b/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts @@ -5,7 +5,15 @@ import type { UserResource, } from '@clerk/shared/types'; -import type { ProviderType } from '../types'; +import type { EnterpriseConnectionProviderType, OidcProviderType } from '../types'; + +/** + * OIDC providers are recognized by protocol prefix, never by literal: the backend + * stores a derived `oidc_` key (open family), so the read-back provider is + * not a fixed enum. SAML providers stay exact literals. Single source of the + * prefix notion — dispatch and configuration checks both read it from here. + */ +export const isOidcProvider = (provider: string): provider is OidcProviderType => provider.startsWith('oidc'); /** * The email whose domain backs the connection: the user's primary address if @@ -40,7 +48,7 @@ export type OrganizationEnterpriseConnectionStatus = 'unconfigured' | 'in_progre * object the wizard makes every flow decision from. A snapshot of flattened booleans/values. */ export interface OrganizationEnterpriseConnection { - readonly provider: ProviderType | undefined; + readonly provider: EnterpriseConnectionProviderType | undefined; readonly hasConnection: boolean; readonly isActive: boolean; readonly hasMinimumConfiguration: boolean; @@ -48,10 +56,18 @@ export interface OrganizationEnterpriseConnection { readonly status: OrganizationEnterpriseConnectionStatus; } -// TODO - Update to support OpenID Connect export const isEnterpriseConnectionConfigured = ( connection: EnterpriseConnectionResource | null | undefined, -): boolean => Boolean(connection?.samlConnection?.idpSsoUrl && connection?.samlConnection?.idpEntityId); +): boolean => { + if (!connection) { + return false; + } + // OIDC exposes only the client ID on the resource; the secret and manual endpoints are write-only. + if (isOidcProvider(connection.provider)) { + return Boolean(connection.oauthConfig?.clientId); + } + return Boolean(connection.samlConnection?.idpSsoUrl && connection.samlConnection?.idpEntityId); +}; export const areAllOrganizationDomainsVerified = (domains: OrganizationDomainResource[] | null | undefined): boolean => !!domains?.length && domains.every(domain => domain.ownershipVerification?.status === 'verified'); @@ -86,7 +102,10 @@ export const organizationEnterpriseConnection = ({ const hasMinimumConfiguration = isEnterpriseConnectionConfigured(connection); return { - provider: connection?.provider as ProviderType | undefined, + // Boundary cast at the FAPI edge: SAML returns exact literals, OIDC an open + // `oidc_` family. An unrecognized value degrades downstream (dispatch + // falls back), so the honest open type — not the `oidc_custom` input alias — holds here. + provider: connection?.provider as EnterpriseConnectionProviderType | undefined, hasConnection, isActive, hasMinimumConfiguration, diff --git a/packages/ui/src/components/ConfigureSSO/hooks/__tests__/useOrganizationEnterpriseConnection.test.tsx b/packages/ui/src/components/ConfigureSSO/hooks/__tests__/useOrganizationEnterpriseConnection.test.tsx index bb9579ad215..5288dd01549 100644 --- a/packages/ui/src/components/ConfigureSSO/hooks/__tests__/useOrganizationEnterpriseConnection.test.tsx +++ b/packages/ui/src/components/ConfigureSSO/hooks/__tests__/useOrganizationEnterpriseConnection.test.tsx @@ -7,20 +7,22 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; // test-runs query's `enabled` and folds its loading into the global gate. // A connection shaped enough for the umbrella's gating: the derived -// "configured" predicate reads `samlConnection.idpSsoUrl` + `idpEntityId`, and -// the active path reads `active`. +// "configured" predicate branches on `provider`, then reads +// `samlConnection.idpSsoUrl` + `idpEntityId`, and the active path reads `active`. type MockConnection = { id: string; + provider: string; active?: boolean; samlConnection?: { idpSsoUrl?: string; idpEntityId?: string } | null; }; const configuredConnection = (id: string): MockConnection => ({ id, + provider: 'saml_okta', samlConnection: { idpSsoUrl: 'https://idp.example.com/sso', idpEntityId: 'https://idp.example.com/entity' }, }); -const unconfiguredConnection = (id: string): MockConnection => ({ id, samlConnection: null }); +const unconfiguredConnection = (id: string): MockConnection => ({ id, provider: 'saml_okta', samlConnection: null }); // Mutable state the connection-source mock reads from, so a test can flip from // "no connection at load" to "connection created mid-flow" between renders. @@ -119,7 +121,7 @@ describe('useOrganizationEnterpriseConnection — test-runs gating', () => { }); it('(a2) active (but unconfigured) connection at load → test-runs active via the isActive path', () => { - connectionsState.data = [{ id: 'ent_active', active: true, samlConnection: null }]; + connectionsState.data = [{ id: 'ent_active', provider: 'saml_okta', active: true, samlConnection: null }]; const { result } = renderHook(() => useOrganizationEnterpriseConnection()); diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx new file mode 100644 index 00000000000..f4b4c5c0d8c --- /dev/null +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx @@ -0,0 +1,90 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { Flow } from '@/customizables'; +import { bindCreateFixtures } from '@/test/create-fixtures'; +import { render, screen } from '@/test/utils'; +import { CardStateProvider } from '@/ui/elements/contexts'; + +import type { EnterpriseConnectionProviderType } from '../../../types'; + +// The dispatch reads `organizationEnterpriseConnection.provider`. The nested +// sub-flows also read `enterpriseConnection` (via `Step.Footer.Reset`), which is +// left undefined so that footer self-hides in this isolated render. +const contextState = vi.hoisted(() => ({ provider: undefined as string | undefined })); + +vi.mock('../../../ConfigureSSOContext', () => ({ + useConfigureSSO: () => ({ + enterpriseConnection: undefined, + contentRef: { current: null }, + enterpriseConnectionMutations: {}, + organizationEnterpriseConnection: { + provider: contextState.provider, + hasConnection: true, + }, + }), +})); + +import { ConfigureProviderStep, resolveConfigureSteps } from '../index'; +import { OidcCustomConfigureSteps } from '../oidc'; +import { + SamlCustomConfigureSteps, + SamlGoogleConfigureSteps, + SamlMicrosoftConfigureSteps, + SamlOktaConfigureSteps, +} from '../saml'; + +const { createFixtures } = bindCreateFixtures('ConfigureSSO'); + +describe('resolveConfigureSteps', () => { + it('dispatches a derived OIDC provider key to the OIDC sub-flow by prefix (not the oidc_custom literal)', () => { + // The regression: the backend returns `oidc_` derived from the connection + // name (e.g. `clerk.dev` → `oidc_clerk_dev`), never the `oidc_custom` input alias. + expect(resolveConfigureSteps('oidc_clerk_dev')).toBe(OidcCustomConfigureSteps); + expect(resolveConfigureSteps('oidc_ghe_acme')).toBe(OidcCustomConfigureSteps); + expect(resolveConfigureSteps('oidc_gitlab_ent_acme')).toBe(OidcCustomConfigureSteps); + expect(resolveConfigureSteps('oidc_custom')).toBe(OidcCustomConfigureSteps); + }); + + it('dispatches SAML providers by exact literal', () => { + expect(resolveConfigureSteps('saml_okta')).toBe(SamlOktaConfigureSteps); + expect(resolveConfigureSteps('saml_custom')).toBe(SamlCustomConfigureSteps); + expect(resolveConfigureSteps('saml_google')).toBe(SamlGoogleConfigureSteps); + expect(resolveConfigureSteps('saml_microsoft')).toBe(SamlMicrosoftConfigureSteps); + }); + + it('returns undefined for an unrecognized provider so the caller can degrade', () => { + expect(resolveConfigureSteps('ldap_enterprise' as EnterpriseConnectionProviderType)).toBeUndefined(); + }); +}); + +describe('ConfigureProviderStep', () => { + const renderStep = (wrapper: React.ComponentType<{ children?: React.ReactNode }>) => + render( + + + + + , + { wrapper }, + ); + + it('renders the OIDC configure steps for a derived provider key without throwing', async () => { + contextState.provider = 'oidc_clerk_dev'; + const { wrapper } = await createFixtures(); + + renderStep(wrapper); + + // The OIDC sub-flow mounts on its first step. Before the fix this threw + // `No steps found for provider: oidc_clerk_dev` and white-screened the wizard. + expect(await screen.findByText(/create a new oidc application/i)).toBeInTheDocument(); + }); + + it('degrades to the unsupported-provider state for a provider the SDK does not recognize', async () => { + contextState.provider = 'ldap_enterprise'; + const { wrapper } = await createFixtures(); + + renderStep(wrapper); + + expect(await screen.findByText(/unsupported provider/i)).toBeInTheDocument(); + }); +}); diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx index b5f442e7bd5..0afc876b794 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx @@ -4,10 +4,12 @@ import { descriptors, Flow } from '@/customizables'; import { CardStateProvider } from '@/elements/contexts'; import { useConfigureSSO } from '../../ConfigureSSOContext'; +import { isOidcProvider } from '../../domain/organizationEnterpriseConnection'; import { Step } from '../../elements/Step'; import { useWizard, Wizard, type WizardStepConfig } from '../../elements/Wizard'; -import type { ProviderType } from '../../types'; +import type { EnterpriseConnectionProviderType, SamlProviderType } from '../../types'; import { SelectProviderStep } from '../SelectProviderStep'; +import { OidcCustomConfigureSteps } from './oidc'; import { SamlCustomConfigureSteps, SamlGoogleConfigureSteps, @@ -15,13 +17,26 @@ import { SamlOktaConfigureSteps, } from './saml'; -const STEPS_BY_PROVIDER: Record JSX.Element> = { +type ConfigureStepsComponent = () => JSX.Element; + +const STEPS_BY_SAML_PROVIDER: Record = { saml_custom: SamlCustomConfigureSteps, saml_okta: SamlOktaConfigureSteps, saml_google: SamlGoogleConfigureSteps, saml_microsoft: SamlMicrosoftConfigureSteps, }; +/** + * Resolves the configure sub-flow for a created connection's provider. OIDC is an + * open, backend-derived family (`oidc_`), so every OIDC provider shares one + * sub-flow and is matched by protocol prefix; SAML stays an exact-literal lookup. + * Returns `undefined` for an unrecognized provider so the caller can degrade. + */ +export const resolveConfigureSteps = ( + provider: EnterpriseConnectionProviderType, +): ConfigureStepsComponent | undefined => + isOidcProvider(provider) ? OidcCustomConfigureSteps : STEPS_BY_SAML_PROVIDER[provider]; + export const ConfigureStep = (): JSX.Element => { const { organizationEnterpriseConnection: c } = useConfigureSSO(); const { direction } = useWizard(); @@ -53,7 +68,7 @@ export const ConfigureStep = (): JSX.Element => { ); }; -const ConfigureProviderStep = (): JSX.Element | null => { +export const ConfigureProviderStep = (): JSX.Element | null => { const { organizationEnterpriseConnection: c } = useConfigureSSO(); // Type guard: the provider should be defined by the time we reach configure. @@ -61,12 +76,7 @@ const ConfigureProviderStep = (): JSX.Element | null => { return null; } - // Adding a provider to the select step without a mapping here fails the build. - const StepsByProvider = STEPS_BY_PROVIDER[c.provider]; - - if (!StepsByProvider) { - throw new Error(`No steps found for provider: ${c.provider}`); - } + const ConfigureSteps = resolveConfigureSteps(c.provider); return ( @@ -74,7 +84,19 @@ const ConfigureProviderStep = (): JSX.Element | null => { elementDescriptor={descriptors.configureSSOStep} elementId={descriptors.configureSSOStep.setId('configure')} > - + {ConfigureSteps ? ( + + ) : ( + // A provider the SDK doesn't recognize (e.g. a newer backend family) + // degrades to a terminal state instead of white-screening the wizard. + <> + + + + )} ); diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx new file mode 100644 index 00000000000..d5100e7c2ca --- /dev/null +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx @@ -0,0 +1,157 @@ +import { type JSX } from 'react'; + +import { localizationKeys } from '@/customizables'; + +import { Step } from '../../../elements/Step'; +import { useWizard, Wizard, type WizardStepConfig } from '../../../elements/Wizard'; +import { InnerStepCounter } from '../../../elements/Wizard/InnerStepCounter'; + +const OIDC_STEPS: WizardStepConfig[] = [ + { id: 'redirect-uri' }, + { id: 'claims' }, + { id: 'endpoints' }, + { id: 'credentials' }, +]; + +export const OidcCustomConfigureSteps = (): JSX.Element => { + return ( + // Linear, guard-less sub-flow: mount on the first step, mirroring the SAML custom inner wizard. + + + + + + + + + + + + + + + + + + ); +}; + +const OidcRedirectUriStep = (): JSX.Element => { + const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); + + return ( + <> + + + + + + + + + goPrev()} + isDisabled={isFirstStep} + /> + goNext()} + isDisabled={isLastStep} + /> + + + ); +}; + +const OidcClaimsStep = (): JSX.Element => { + const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); + + return ( + <> + + + + + + + + + goPrev()} + isDisabled={isFirstStep} + /> + goNext()} + isDisabled={isLastStep} + /> + + + ); +}; + +const OidcEndpointsStep = (): JSX.Element => { + const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); + + return ( + <> + + + + + + + + + goPrev()} + isDisabled={isFirstStep} + /> + goNext()} + isDisabled={isLastStep} + /> + + + ); +}; + +const OidcCredentialsStep = (): JSX.Element => { + const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); + + return ( + <> + + + + + + + + + goPrev()} + isDisabled={isFirstStep} + /> + {/* Terminal step: the connection submit lands with the credentials step ticket; disabled as a placeholder. */} + goNext()} + isDisabled={isLastStep} + /> + + + ); +}; diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/index.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/index.tsx new file mode 100644 index 00000000000..cd97ad4a843 --- /dev/null +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/index.tsx @@ -0,0 +1 @@ +export { OidcCustomConfigureSteps } from './OidcCustomConfigureSteps'; diff --git a/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx b/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx index 7ba827671b5..877f99c1572 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx @@ -21,13 +21,14 @@ import { handleError } from '@/utils/errorHandler'; import { ChangeProviderDialog } from '../ChangeProviderDialog'; import { useConfigureSSO } from '../ConfigureSSOContext'; +import { isOidcProvider } from '../domain/organizationEnterpriseConnection'; import { Step } from '../elements/Step'; import { useWizard } from '../elements/Wizard'; -import type { ProviderType } from '../types'; +import type { EnterpriseConnectionProviderType, ProviderType } from '../types'; const MONOCHROMATIC_PROVIDER_ICONS: ReadonlySet = new Set(['okta']); const PROVIDER_GROUPS: ReadonlyArray<{ - id: 'saml'; + id: 'saml' | 'oidc'; label: LocalizationKey; options: ReadonlyArray<{ id: ProviderType; label: LocalizationKey; iconId: string }>; }> = [ @@ -53,21 +54,49 @@ const PROVIDER_GROUPS: ReadonlyArray<{ }, ], }, + { + id: 'oidc', + label: localizationKeys('configureSSO.selectProviderStep.oidc.groupLabel'), + options: [ + { + id: 'oidc_custom', + label: localizationKeys('configureSSO.selectProviderStep.oidc.oidcProvider'), + iconId: 'oidc', + }, + ], + }, ]; const providerLabel = (provider: ProviderType): LocalizationKey | undefined => PROVIDER_GROUPS.flatMap(group => group.options).find(option => option.id === provider)?.label; +/** + * The picker works in input aliases; an existing connection reports back its real + * provider (OIDC as an open `oidc_` family), so collapse it onto the card + * that represents it — every OIDC family maps to the single `oidc_custom` card. + */ +const toProviderCard = (provider: EnterpriseConnectionProviderType): ProviderType => + isOidcProvider(provider) ? 'oidc_custom' : provider; + export const SelectProviderStep = (): JSX.Element => { const { organizationEnterpriseConnection: c, enterpriseConnectionMutations: { createConnection, changeProvider }, contentRef, + isOIDCFlowEnabled, } = useConfigureSSO(); const { goNext, goPrev, isFirstStep } = useWizard(); const { t } = useLocalizations(); - const [selected, setSelected] = React.useState(c.provider ?? null); + // OIDC is gated behind the experimental self-serve flag; SAML always shows. + const providerGroups = React.useMemo( + () => PROVIDER_GROUPS.filter(group => group.id !== 'oidc' || isOIDCFlowEnabled), + [isOIDCFlowEnabled], + ); + + const currentCard = c.provider ? toProviderCard(c.provider) : null; + + const [selected, setSelected] = React.useState(currentCard); const card = useCardState(); const [isSubmitting, setIsSubmitting] = React.useState(false); @@ -78,20 +107,20 @@ export const SelectProviderStep = (): JSX.Element => { setSelected(next); }; - const isChangingProvider = c.hasConnection && selected !== null && selected !== c.provider; + const isChangingProvider = c.hasConnection && selected !== null && selected !== currentCard; const handleContinue = async (): Promise => { if (!selected) { return; } - if (c.hasConnection && selected === c.provider) { + if (c.hasConnection && selected === currentCard) { void goNext(); return; } if (isChangingProvider) { - setChangeFromProvider(c.provider ?? null); + setChangeFromProvider(currentCard); setIsChangeDialogOpen(true); return; } @@ -143,7 +172,7 @@ export const SelectProviderStep = (): JSX.Element => { ({ gap: theme.space.$5 })}> - {PROVIDER_GROUPS.map(group => ( + {providerGroups.map(group => ( ({ provider: undefined as 'saml_okta' | 'saml_custom' | 'saml_google' | undefined, hasConnection: false, + isOIDCFlowEnabled: false, })); vi.mock('../../ConfigureSSOContext', () => ({ @@ -39,6 +40,7 @@ vi.mock('../../ConfigureSSOContext', () => ({ provider: contextState.provider, hasConnection: contextState.hasConnection, }, + isOIDCFlowEnabled: contextState.isOIDCFlowEnabled, }), })); @@ -62,6 +64,7 @@ const resetMocks = () => { changeProvider.mockResolvedValue(undefined); contextState.provider = undefined; contextState.hasConnection = false; + contextState.isOIDCFlowEnabled = false; }; describe('SelectProviderStep', () => { @@ -105,6 +108,30 @@ describe('SelectProviderStep', () => { expect(collectedStyles).toMatch(/img\.clerk\.com\/static\/google\.svg/); }); + describe('OIDC provider (experimental flag)', () => { + it('hides the OIDC provider tile when the flag is off', async () => { + resetMocks(); + const { wrapper } = await createFixtures(); + renderStep(wrapper); + + // SAML is unaffected by the gate; only OIDC is hidden. + expect(screen.getByRole('radio', { name: 'Okta Workforce' })).toBeInTheDocument(); + expect(screen.queryByRole('radio', { name: 'OIDC Provider' })).not.toBeInTheDocument(); + }); + + it('shows the OIDC provider tile when the flag is on', async () => { + resetMocks(); + contextState.isOIDCFlowEnabled = true; + const { wrapper } = await createFixtures(); + const { container } = renderStep(wrapper); + + expect(screen.getByRole('radio', { name: 'OIDC Provider' })).toBeInTheDocument(); + // Four SAML tiles plus the single OIDC tile. + const iconSpans = Array.from(container.querySelectorAll('label span[aria-hidden]')); + expect(iconSpans).toHaveLength(5); + }); + }); + it('disables Continue when no provider is selected', async () => { resetMocks(); const { wrapper } = await createFixtures(); diff --git a/packages/ui/src/components/ConfigureSSO/types.ts b/packages/ui/src/components/ConfigureSSO/types.ts index 190fa6cd26e..fac467ce444 100644 --- a/packages/ui/src/components/ConfigureSSO/types.ts +++ b/packages/ui/src/components/ConfigureSSO/types.ts @@ -1,4 +1,25 @@ -export type ProviderType = 'saml_okta' | 'saml_custom' | 'saml_google' | 'saml_microsoft'; +/** SAML providers are exact backend literals — the read-back key matches the input alias. */ +export type SamlProviderType = 'saml_okta' | 'saml_custom' | 'saml_google' | 'saml_microsoft'; + +/** + * The OIDC provider family a created connection reports back. The backend derives + * the key from the connection name (`oidc_`, plus `oidc_ghe_` and + * `oidc_gitlab_ent_`), so it is an open string, never the `oidc_custom` + * input alias the picker sends. + */ +export type OidcProviderType = `oidc_${string}`; + +/** + * The provider the SELECT step SENDS on create. OIDC always creates through the + * single `oidc_custom` input alias; the backend then derives the real key. + */ +export type ProviderType = SamlProviderType | 'oidc_custom'; + +/** + * The provider a created connection READS BACK. SAML narrows to the exact literals; + * OIDC is the open, backend-derived family — dispatch on this by protocol, not literal. + */ +export type EnterpriseConnectionProviderType = SamlProviderType | OidcProviderType; export type WizardStepId = | 'verify-domain' From 30ea9204eaf023d6b5735f872b5b454e7be8c8ec Mon Sep 17 00:00:00 2001 From: Nicolas Lopes Date: Tue, 28 Jul 2026 13:22:03 -0300 Subject: [PATCH 2/8] fix(ui): address OIDC ConfigureSSO review feedback --- packages/localizations/src/ar-SA.ts | 23 +++++++ packages/localizations/src/be-BY.ts | 23 +++++++ packages/localizations/src/bg-BG.ts | 23 +++++++ packages/localizations/src/bn-IN.ts | 23 +++++++ packages/localizations/src/ca-ES.ts | 23 +++++++ packages/localizations/src/cs-CZ.ts | 23 +++++++ packages/localizations/src/da-DK.ts | 23 +++++++ packages/localizations/src/de-DE.ts | 23 +++++++ packages/localizations/src/el-GR.ts | 23 +++++++ packages/localizations/src/en-GB.ts | 23 +++++++ packages/localizations/src/en-US.ts | 5 ++ packages/localizations/src/es-CR.ts | 23 +++++++ packages/localizations/src/es-ES.ts | 23 +++++++ packages/localizations/src/es-MX.ts | 23 +++++++ packages/localizations/src/es-UY.ts | 23 +++++++ packages/localizations/src/fa-IR.ts | 23 +++++++ packages/localizations/src/fi-FI.ts | 23 +++++++ packages/localizations/src/fr-FR.ts | 23 +++++++ packages/localizations/src/he-IL.ts | 23 +++++++ packages/localizations/src/hi-IN.ts | 23 +++++++ packages/localizations/src/hr-HR.ts | 23 +++++++ packages/localizations/src/hu-HU.ts | 23 +++++++ packages/localizations/src/id-ID.ts | 23 +++++++ packages/localizations/src/is-IS.ts | 23 +++++++ packages/localizations/src/it-IT.ts | 23 +++++++ packages/localizations/src/ja-JP.ts | 23 +++++++ packages/localizations/src/kk-KZ.ts | 23 +++++++ packages/localizations/src/ko-KR.ts | 23 +++++++ packages/localizations/src/mn-MN.ts | 23 +++++++ packages/localizations/src/ms-MY.ts | 23 +++++++ packages/localizations/src/nb-NO.ts | 23 +++++++ packages/localizations/src/nl-BE.ts | 23 +++++++ packages/localizations/src/nl-NL.ts | 23 +++++++ packages/localizations/src/pl-PL.ts | 23 +++++++ packages/localizations/src/pt-BR.ts | 23 +++++++ packages/localizations/src/pt-PT.ts | 23 +++++++ packages/localizations/src/ro-RO.ts | 23 +++++++ packages/localizations/src/ru-RU.ts | 23 +++++++ packages/localizations/src/sk-SK.ts | 23 +++++++ packages/localizations/src/sr-RS.ts | 23 +++++++ packages/localizations/src/sv-SE.ts | 23 +++++++ packages/localizations/src/ta-IN.ts | 23 +++++++ packages/localizations/src/te-IN.ts | 23 +++++++ packages/localizations/src/th-TH.ts | 23 +++++++ packages/localizations/src/tr-TR.ts | 23 +++++++ packages/localizations/src/uk-UA.ts | 23 +++++++ packages/localizations/src/vi-VN.ts | 23 +++++++ packages/localizations/src/zh-CN.ts | 23 +++++++ packages/localizations/src/zh-TW.ts | 23 +++++++ packages/shared/src/types/localization.ts | 4 ++ .../organizationEnterpriseConnection.test.ts | 17 ++++- .../organizationEnterpriseConnection.ts | 11 +--- .../__tests__/ConfigureStep.test.tsx | 65 +------------------ .../steps/ConfigureStep/index.tsx | 16 ++--- .../oidc/OidcCustomConfigureSteps.tsx | 14 ++-- .../ConfigureSSO/steps/SelectProviderStep.tsx | 6 -- .../__tests__/SelectProviderStep.test.tsx | 10 +-- .../ui/src/components/ConfigureSSO/types.ts | 15 ----- 58 files changed, 1143 insertions(+), 124 deletions(-) diff --git a/packages/localizations/src/ar-SA.ts b/packages/localizations/src/ar-SA.ts index 9b70f8d0a2d..b1a1814a91a 100644 --- a/packages/localizations/src/ar-SA.ts +++ b/packages/localizations/src/ar-SA.ts @@ -242,6 +242,21 @@ export const arSA: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const arSA: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'تواصل مع مسؤول مؤسستك لترقية أذوناتك.', @@ -678,6 +697,10 @@ export const arSA: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'مزود SAML مخصص', google: undefined, diff --git a/packages/localizations/src/be-BY.ts b/packages/localizations/src/be-BY.ts index 3fb72ae5d54..4b8395b0d6d 100644 --- a/packages/localizations/src/be-BY.ts +++ b/packages/localizations/src/be-BY.ts @@ -242,6 +242,21 @@ export const beBY: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const beBY: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Звярніцеся да адміністратара вашай арганізацыі, каб павысіць вашы дазволы.', @@ -679,6 +698,10 @@ export const beBY: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Карыстальніцкі правайдэр SAML', google: undefined, diff --git a/packages/localizations/src/bg-BG.ts b/packages/localizations/src/bg-BG.ts index 4e14def42ab..b8b1d9ef163 100644 --- a/packages/localizations/src/bg-BG.ts +++ b/packages/localizations/src/bg-BG.ts @@ -243,6 +243,21 @@ export const bgBG: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -627,6 +642,10 @@ export const bgBG: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Свържете се с администратора на вашата организация, за да повишите разрешенията си.', @@ -680,6 +699,10 @@ export const bgBG: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Персонализиран SAML доставчик', google: undefined, diff --git a/packages/localizations/src/bn-IN.ts b/packages/localizations/src/bn-IN.ts index d8a33bdfa92..03ea7cd8299 100644 --- a/packages/localizations/src/bn-IN.ts +++ b/packages/localizations/src/bn-IN.ts @@ -248,6 +248,21 @@ export const bnIN: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -632,6 +647,10 @@ export const bnIN: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'আপনার অনুমতি আপগ্রেড করতে আপনার সংস্থার প্রশাসকের সাথে যোগাযোগ করুন।', @@ -685,6 +704,10 @@ export const bnIN: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'কাস্টম SAML প্রদানকারী', google: undefined, diff --git a/packages/localizations/src/ca-ES.ts b/packages/localizations/src/ca-ES.ts index fe24667d6a5..9a8c8b11ed8 100644 --- a/packages/localizations/src/ca-ES.ts +++ b/packages/localizations/src/ca-ES.ts @@ -249,6 +249,21 @@ export const caES: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -633,6 +648,10 @@ export const caES: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: "Contacta amb l'administrador de la teva organització per ampliar els teus permisos.", @@ -686,6 +705,10 @@ export const caES: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Proveïdor SAML personalitzat', google: undefined, diff --git a/packages/localizations/src/cs-CZ.ts b/packages/localizations/src/cs-CZ.ts index 40ca97e4f47..ae66046af89 100644 --- a/packages/localizations/src/cs-CZ.ts +++ b/packages/localizations/src/cs-CZ.ts @@ -246,6 +246,21 @@ export const csCZ: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -630,6 +645,10 @@ export const csCZ: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Kontaktujte správce vaší organizace pro rozšíření vašich oprávnění.', @@ -683,6 +702,10 @@ export const csCZ: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Vlastní poskytovatel SAML', google: undefined, diff --git a/packages/localizations/src/da-DK.ts b/packages/localizations/src/da-DK.ts index 8f6cd90e1ce..83bcad107e7 100644 --- a/packages/localizations/src/da-DK.ts +++ b/packages/localizations/src/da-DK.ts @@ -242,6 +242,21 @@ export const daDK: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const daDK: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Kontakt din organisations administrator for at opgradere dine tilladelser.', @@ -678,6 +697,10 @@ export const daDK: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Brugerdefineret SAML-udbyder', google: undefined, diff --git a/packages/localizations/src/de-DE.ts b/packages/localizations/src/de-DE.ts index f7c181cf898..cb244d905d4 100644 --- a/packages/localizations/src/de-DE.ts +++ b/packages/localizations/src/de-DE.ts @@ -248,6 +248,21 @@ export const deDE: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -632,6 +647,10 @@ export const deDE: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Wenden Sie sich an Ihren Organisationsadministrator, um Ihre Berechtigungen zu erweitern.', @@ -686,6 +705,10 @@ export const deDE: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Benutzerdefinierter SAML-Anbieter', google: undefined, diff --git a/packages/localizations/src/el-GR.ts b/packages/localizations/src/el-GR.ts index fbc71c2473a..da060abb473 100644 --- a/packages/localizations/src/el-GR.ts +++ b/packages/localizations/src/el-GR.ts @@ -242,6 +242,21 @@ export const elGR: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const elGR: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Επικοινωνήστε με τον διαχειριστή του οργανισμού σας για να αναβαθμίσετε τις άδειές σας.', @@ -679,6 +698,10 @@ export const elGR: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Προσαρμοσμένος πάροχος SAML', google: undefined, diff --git a/packages/localizations/src/en-GB.ts b/packages/localizations/src/en-GB.ts index 74fa7ea9e73..41084beb72a 100644 --- a/packages/localizations/src/en-GB.ts +++ b/packages/localizations/src/en-GB.ts @@ -242,6 +242,21 @@ export const enGB: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const enGB: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: "Contact your organisation's administrator to upgrade your permissions.", @@ -678,6 +697,10 @@ export const enGB: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Custom SAML Provider', google: undefined, diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts index e7419100697..183b6572af9 100644 --- a/packages/localizations/src/en-US.ts +++ b/packages/localizations/src/en-US.ts @@ -654,6 +654,11 @@ export const enUS: LocalizationResource = { }, mainHeaderTitle: 'Configure Okta Workforce', }, + unsupportedProvider: { + description: + 'This identity provider isn’t supported in this version of Clerk. Update to the latest version to finish setting it up.', + title: 'Unsupported provider', + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: "Contact your organization's administrator to upgrade your permissions.", diff --git a/packages/localizations/src/es-CR.ts b/packages/localizations/src/es-CR.ts index 6c465f680a0..c8007f00a63 100644 --- a/packages/localizations/src/es-CR.ts +++ b/packages/localizations/src/es-CR.ts @@ -242,6 +242,21 @@ export const esCR: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const esCR: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Contactá al administrador de tu organización para mejorar tus permisos.', @@ -679,6 +698,10 @@ export const esCR: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Proveedor SAML personalizado', google: undefined, diff --git a/packages/localizations/src/es-ES.ts b/packages/localizations/src/es-ES.ts index 2d6895e5822..7e1524f948f 100644 --- a/packages/localizations/src/es-ES.ts +++ b/packages/localizations/src/es-ES.ts @@ -248,6 +248,21 @@ export const esES: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -632,6 +647,10 @@ export const esES: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Contacte al administrador de su organización para ampliar sus permisos.', @@ -685,6 +704,10 @@ export const esES: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Proveedor SAML personalizado', google: undefined, diff --git a/packages/localizations/src/es-MX.ts b/packages/localizations/src/es-MX.ts index 64b90aa3da2..8709709b798 100644 --- a/packages/localizations/src/es-MX.ts +++ b/packages/localizations/src/es-MX.ts @@ -243,6 +243,21 @@ export const esMX: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -627,6 +642,10 @@ export const esMX: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Contacta al administrador de tu organización para ampliar tus permisos.', @@ -680,6 +699,10 @@ export const esMX: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Proveedor SAML personalizado', google: undefined, diff --git a/packages/localizations/src/es-UY.ts b/packages/localizations/src/es-UY.ts index b027e07069f..fcfe9e8831f 100644 --- a/packages/localizations/src/es-UY.ts +++ b/packages/localizations/src/es-UY.ts @@ -242,6 +242,21 @@ export const esUY: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const esUY: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Contactá al administrador de tu organización para ampliar tus permisos.', @@ -679,6 +698,10 @@ export const esUY: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Proveedor SAML personalizado', google: undefined, diff --git a/packages/localizations/src/fa-IR.ts b/packages/localizations/src/fa-IR.ts index 1cf0c875abf..4ba22a1c772 100644 --- a/packages/localizations/src/fa-IR.ts +++ b/packages/localizations/src/fa-IR.ts @@ -247,6 +247,21 @@ export const faIR: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -631,6 +646,10 @@ export const faIR: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'برای ارتقای مجوزهای خود با مدیر سازمان تماس بگیرید.', @@ -684,6 +703,10 @@ export const faIR: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'ارائه‌دهنده SAML سفارشی', google: undefined, diff --git a/packages/localizations/src/fi-FI.ts b/packages/localizations/src/fi-FI.ts index d02b810a53a..b62270c6ad8 100644 --- a/packages/localizations/src/fi-FI.ts +++ b/packages/localizations/src/fi-FI.ts @@ -248,6 +248,21 @@ export const fiFI: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -632,6 +647,10 @@ export const fiFI: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Ota yhteyttä organisaatiosi järjestelmänvalvojaan päivittääksesi oikeuksiasi.', @@ -685,6 +704,10 @@ export const fiFI: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Mukautettu SAML-palveluntarjoaja', google: undefined, diff --git a/packages/localizations/src/fr-FR.ts b/packages/localizations/src/fr-FR.ts index 3ef7465f900..0be16460b1c 100644 --- a/packages/localizations/src/fr-FR.ts +++ b/packages/localizations/src/fr-FR.ts @@ -250,6 +250,21 @@ export const frFR: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -634,6 +649,10 @@ export const frFR: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: "Contactez l'administrateur de votre organisation pour étendre vos permissions.", @@ -687,6 +706,10 @@ export const frFR: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Fournisseur SAML personnalisé', google: undefined, diff --git a/packages/localizations/src/he-IL.ts b/packages/localizations/src/he-IL.ts index b1763ec3337..286077dfa0e 100644 --- a/packages/localizations/src/he-IL.ts +++ b/packages/localizations/src/he-IL.ts @@ -242,6 +242,21 @@ export const heIL: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const heIL: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'פנה למנהל הארגון שלך כדי לשדרג את ההרשאות שלך.', @@ -678,6 +697,10 @@ export const heIL: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'ספק SAML מותאם אישית', google: undefined, diff --git a/packages/localizations/src/hi-IN.ts b/packages/localizations/src/hi-IN.ts index 98812de0410..87a2c58c840 100644 --- a/packages/localizations/src/hi-IN.ts +++ b/packages/localizations/src/hi-IN.ts @@ -248,6 +248,21 @@ export const hiIN: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -632,6 +647,10 @@ export const hiIN: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'अपनी अनुमतियाँ अपग्रेड करने के लिए अपने संगठन के व्यवस्थापक से संपर्क करें।', @@ -685,6 +704,10 @@ export const hiIN: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'कस्टम SAML प्रदाता', google: undefined, diff --git a/packages/localizations/src/hr-HR.ts b/packages/localizations/src/hr-HR.ts index db93f008960..ef3298fb2db 100644 --- a/packages/localizations/src/hr-HR.ts +++ b/packages/localizations/src/hr-HR.ts @@ -249,6 +249,21 @@ export const hrHR: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -633,6 +648,10 @@ export const hrHR: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Obratite se administratoru vaše organizacije kako biste nadogradili svoja dopuštenja.', @@ -686,6 +705,10 @@ export const hrHR: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Prilagođeni SAML pružatelj', google: undefined, diff --git a/packages/localizations/src/hu-HU.ts b/packages/localizations/src/hu-HU.ts index 3a3aff4cfe8..087def5554d 100644 --- a/packages/localizations/src/hu-HU.ts +++ b/packages/localizations/src/hu-HU.ts @@ -249,6 +249,21 @@ export const huHU: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -633,6 +648,10 @@ export const huHU: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Vegye fel a kapcsolatot szervezete adminisztrátorával a jogosultságai bővítéséhez.', @@ -687,6 +706,10 @@ export const huHU: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Egyéni SAML szolgáltató', google: undefined, diff --git a/packages/localizations/src/id-ID.ts b/packages/localizations/src/id-ID.ts index df03c826a49..ea1ade49305 100644 --- a/packages/localizations/src/id-ID.ts +++ b/packages/localizations/src/id-ID.ts @@ -242,6 +242,21 @@ export const idID: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const idID: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Hubungi administrator organisasi Anda untuk meningkatkan izin Anda.', @@ -679,6 +698,10 @@ export const idID: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Penyedia SAML Khusus', google: undefined, diff --git a/packages/localizations/src/is-IS.ts b/packages/localizations/src/is-IS.ts index a2f5087a28e..5d861a60ebd 100644 --- a/packages/localizations/src/is-IS.ts +++ b/packages/localizations/src/is-IS.ts @@ -248,6 +248,21 @@ export const isIS: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -632,6 +647,10 @@ export const isIS: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Hafðu samband við stjórnanda fyrirtækisins þíns til að uppfæra heimildir þínar.', @@ -685,6 +704,10 @@ export const isIS: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Sérsniðinn SAML þjónustuaðili', google: undefined, diff --git a/packages/localizations/src/it-IT.ts b/packages/localizations/src/it-IT.ts index 305b7cc39d0..e6c2082935b 100644 --- a/packages/localizations/src/it-IT.ts +++ b/packages/localizations/src/it-IT.ts @@ -248,6 +248,21 @@ export const itIT: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -632,6 +647,10 @@ export const itIT: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: "Contatta l'amministratore della tua organizzazione per ampliare i tuoi permessi.", @@ -685,6 +704,10 @@ export const itIT: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Provider SAML personalizzato', google: undefined, diff --git a/packages/localizations/src/ja-JP.ts b/packages/localizations/src/ja-JP.ts index ad9f53c787f..77b3c776f40 100644 --- a/packages/localizations/src/ja-JP.ts +++ b/packages/localizations/src/ja-JP.ts @@ -249,6 +249,21 @@ export const jaJP: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -633,6 +648,10 @@ export const jaJP: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: '権限をアップグレードするには、組織の管理者にお問い合わせください。', @@ -686,6 +705,10 @@ export const jaJP: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'カスタムSAMLプロバイダー', google: undefined, diff --git a/packages/localizations/src/kk-KZ.ts b/packages/localizations/src/kk-KZ.ts index f2ecf7e21fe..8c8bbb5c403 100644 --- a/packages/localizations/src/kk-KZ.ts +++ b/packages/localizations/src/kk-KZ.ts @@ -242,6 +242,21 @@ export const kkKZ: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const kkKZ: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Рұқсаттарыңызды жаңарту үшін ұйым әкімшісіне хабарласыңыз.', @@ -679,6 +698,10 @@ export const kkKZ: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Реттелетін SAML провайдері', google: undefined, diff --git a/packages/localizations/src/ko-KR.ts b/packages/localizations/src/ko-KR.ts index 0bb35f7cee4..354bd6ba7ce 100644 --- a/packages/localizations/src/ko-KR.ts +++ b/packages/localizations/src/ko-KR.ts @@ -246,6 +246,21 @@ export const koKR: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -630,6 +645,10 @@ export const koKR: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: '권한을 업그레이드하려면 조직 관리자에게 문의하세요.', @@ -682,6 +701,10 @@ export const koKR: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: '사용자 지정 SAML 공급자', google: undefined, diff --git a/packages/localizations/src/mn-MN.ts b/packages/localizations/src/mn-MN.ts index 0d25f3cea12..fad52bf569a 100644 --- a/packages/localizations/src/mn-MN.ts +++ b/packages/localizations/src/mn-MN.ts @@ -242,6 +242,21 @@ export const mnMN: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const mnMN: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Эрхээ дээшлүүлэхийн тулд байгууллагынхаа админтай холбогдоно уу.', @@ -679,6 +698,10 @@ export const mnMN: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Хэрэглэгчийн тохируулсан SAML үйлчилгээ үзүүлэгч', google: undefined, diff --git a/packages/localizations/src/ms-MY.ts b/packages/localizations/src/ms-MY.ts index 72e32d5764c..727aa3a265e 100644 --- a/packages/localizations/src/ms-MY.ts +++ b/packages/localizations/src/ms-MY.ts @@ -250,6 +250,21 @@ export const msMY: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -634,6 +649,10 @@ export const msMY: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Hubungi pentadbir organisasi anda untuk menaik taraf kebenaran anda.', @@ -687,6 +706,10 @@ export const msMY: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Pembekal SAML Tersuai', google: undefined, diff --git a/packages/localizations/src/nb-NO.ts b/packages/localizations/src/nb-NO.ts index edd764c32d5..32359d1070d 100644 --- a/packages/localizations/src/nb-NO.ts +++ b/packages/localizations/src/nb-NO.ts @@ -249,6 +249,21 @@ export const nbNO: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -633,6 +648,10 @@ export const nbNO: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Kontakt organisasjonens administrator for å oppgradere tillatelsene dine.', @@ -686,6 +705,10 @@ export const nbNO: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Egendefinert SAML-leverandør', google: undefined, diff --git a/packages/localizations/src/nl-BE.ts b/packages/localizations/src/nl-BE.ts index 4107509c7d1..bc3c54d4b22 100644 --- a/packages/localizations/src/nl-BE.ts +++ b/packages/localizations/src/nl-BE.ts @@ -242,6 +242,21 @@ export const nlBE: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const nlBE: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Neem contact op met de beheerder van uw organisatie om uw rechten uit te breiden.', @@ -679,6 +698,10 @@ export const nlBE: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Aangepaste SAML-provider', google: undefined, diff --git a/packages/localizations/src/nl-NL.ts b/packages/localizations/src/nl-NL.ts index b54ddc59780..6cd838cc351 100644 --- a/packages/localizations/src/nl-NL.ts +++ b/packages/localizations/src/nl-NL.ts @@ -242,6 +242,21 @@ export const nlNL: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const nlNL: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Neem contact op met de beheerder van je organisatie om je rechten uit te breiden.', @@ -679,6 +698,10 @@ export const nlNL: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Aangepaste SAML-provider', google: undefined, diff --git a/packages/localizations/src/pl-PL.ts b/packages/localizations/src/pl-PL.ts index 92adfd113a1..fdf5239dff3 100644 --- a/packages/localizations/src/pl-PL.ts +++ b/packages/localizations/src/pl-PL.ts @@ -242,6 +242,21 @@ export const plPL: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const plPL: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Skontaktuj się z administratorem swojej organizacji, aby rozszerzyć swoje uprawnienia.', @@ -679,6 +698,10 @@ export const plPL: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Niestandardowy dostawca SAML', google: undefined, diff --git a/packages/localizations/src/pt-BR.ts b/packages/localizations/src/pt-BR.ts index 0b9478c97dd..55dffc6c687 100644 --- a/packages/localizations/src/pt-BR.ts +++ b/packages/localizations/src/pt-BR.ts @@ -248,6 +248,21 @@ export const ptBR: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -632,6 +647,10 @@ export const ptBR: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Entre em contato com o administrador da sua organização para ampliar suas permissões.', @@ -685,6 +704,10 @@ export const ptBR: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Provedor SAML personalizado', google: undefined, diff --git a/packages/localizations/src/pt-PT.ts b/packages/localizations/src/pt-PT.ts index f378392dcb4..4bf5313fd09 100644 --- a/packages/localizations/src/pt-PT.ts +++ b/packages/localizations/src/pt-PT.ts @@ -250,6 +250,21 @@ export const ptPT: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -634,6 +649,10 @@ export const ptPT: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Contacte o administrador da sua organização para ampliar as suas permissões.', @@ -687,6 +706,10 @@ export const ptPT: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Fornecedor SAML personalizado', google: undefined, diff --git a/packages/localizations/src/ro-RO.ts b/packages/localizations/src/ro-RO.ts index 6a91ac6bbd0..22eec4f2572 100644 --- a/packages/localizations/src/ro-RO.ts +++ b/packages/localizations/src/ro-RO.ts @@ -248,6 +248,21 @@ export const roRO: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -632,6 +647,10 @@ export const roRO: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Contactați administratorul organizației dumneavoastră pentru a vă extinde permisiunile.', @@ -686,6 +705,10 @@ export const roRO: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Furnizor SAML personalizat', google: undefined, diff --git a/packages/localizations/src/ru-RU.ts b/packages/localizations/src/ru-RU.ts index 545061ad0e5..f4751db247f 100644 --- a/packages/localizations/src/ru-RU.ts +++ b/packages/localizations/src/ru-RU.ts @@ -242,6 +242,21 @@ export const ruRU: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const ruRU: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Обратитесь к администратору вашей организации, чтобы расширить ваши разрешения.', @@ -679,6 +698,10 @@ export const ruRU: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Пользовательский поставщик SAML', google: undefined, diff --git a/packages/localizations/src/sk-SK.ts b/packages/localizations/src/sk-SK.ts index 0c34697e47f..39935e24e75 100644 --- a/packages/localizations/src/sk-SK.ts +++ b/packages/localizations/src/sk-SK.ts @@ -242,6 +242,21 @@ export const skSK: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const skSK: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Kontaktujte správcu vašej organizácie pre rozšírenie vašich oprávnení.', @@ -679,6 +698,10 @@ export const skSK: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Vlastný poskytovateľ SAML', google: undefined, diff --git a/packages/localizations/src/sr-RS.ts b/packages/localizations/src/sr-RS.ts index 92aee810ba2..32c55519848 100644 --- a/packages/localizations/src/sr-RS.ts +++ b/packages/localizations/src/sr-RS.ts @@ -242,6 +242,21 @@ export const srRS: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const srRS: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Kontaktirajte administratora vaše organizacije da biste proširili svoje dozvole.', @@ -679,6 +698,10 @@ export const srRS: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Prilagođeni SAML provajder', google: undefined, diff --git a/packages/localizations/src/sv-SE.ts b/packages/localizations/src/sv-SE.ts index 56d3da38257..552fef606f0 100644 --- a/packages/localizations/src/sv-SE.ts +++ b/packages/localizations/src/sv-SE.ts @@ -242,6 +242,21 @@ export const svSE: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const svSE: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Kontakta administratören för din organisation för att utöka dina behörigheter.', @@ -679,6 +698,10 @@ export const svSE: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Anpassad SAML-leverantör', google: undefined, diff --git a/packages/localizations/src/ta-IN.ts b/packages/localizations/src/ta-IN.ts index 587a71d59e5..29978dad604 100644 --- a/packages/localizations/src/ta-IN.ts +++ b/packages/localizations/src/ta-IN.ts @@ -250,6 +250,21 @@ export const taIN: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -634,6 +649,10 @@ export const taIN: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'உங்கள் அனுமதிகளை மேம்படுத்த உங்கள் நிறுவனத்தின் நிர்வாகியைத் தொடர்பு கொள்ளவும்.', @@ -687,6 +706,10 @@ export const taIN: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'தனிப்பயன் SAML வழங்குநர்', google: undefined, diff --git a/packages/localizations/src/te-IN.ts b/packages/localizations/src/te-IN.ts index de16deaba50..679b1df7cfa 100644 --- a/packages/localizations/src/te-IN.ts +++ b/packages/localizations/src/te-IN.ts @@ -249,6 +249,21 @@ export const teIN: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -633,6 +648,10 @@ export const teIN: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'మీ అనుమతులను అప్‌గ్రేడ్ చేయడానికి మీ సంస్థ నిర్వాహకుడిని సంప్రదించండి.', @@ -686,6 +705,10 @@ export const teIN: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'కస్టమ్ SAML ప్రొవైడర్', google: undefined, diff --git a/packages/localizations/src/th-TH.ts b/packages/localizations/src/th-TH.ts index 8c8b34e16ba..72a638ac4da 100644 --- a/packages/localizations/src/th-TH.ts +++ b/packages/localizations/src/th-TH.ts @@ -246,6 +246,21 @@ export const thTH: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -630,6 +645,10 @@ export const thTH: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'ติดต่อผู้ดูแลระบบขององค์กรของคุณเพื่ออัปเกรดสิทธิ์ของคุณ', @@ -682,6 +701,10 @@ export const thTH: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'ผู้ให้บริการ SAML แบบกำหนดเอง', google: undefined, diff --git a/packages/localizations/src/tr-TR.ts b/packages/localizations/src/tr-TR.ts index 98e08e93e4a..b64537f01ba 100644 --- a/packages/localizations/src/tr-TR.ts +++ b/packages/localizations/src/tr-TR.ts @@ -242,6 +242,21 @@ export const trTR: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const trTR: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'İzinlerinizi yükseltmek için organizasyonunuzun yöneticisiyle iletişime geçin.', @@ -679,6 +698,10 @@ export const trTR: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Özel SAML Sağlayıcısı', google: undefined, diff --git a/packages/localizations/src/uk-UA.ts b/packages/localizations/src/uk-UA.ts index dc6f645e1c5..1aa2b56664f 100644 --- a/packages/localizations/src/uk-UA.ts +++ b/packages/localizations/src/uk-UA.ts @@ -242,6 +242,21 @@ export const ukUA: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const ukUA: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Зверніться до адміністратора вашої організації, щоб розширити ваші дозволи.', @@ -679,6 +698,10 @@ export const ukUA: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Користувацький постачальник SAML', google: undefined, diff --git a/packages/localizations/src/vi-VN.ts b/packages/localizations/src/vi-VN.ts index 4d61f937845..213b026547c 100644 --- a/packages/localizations/src/vi-VN.ts +++ b/packages/localizations/src/vi-VN.ts @@ -248,6 +248,21 @@ export const viVN: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -632,6 +647,10 @@ export const viVN: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: 'Liên hệ với quản trị viên tổ chức của bạn để nâng cấp quyền của bạn.', @@ -685,6 +704,10 @@ export const viVN: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: 'Nhà cung cấp SAML tùy chỉnh', google: undefined, diff --git a/packages/localizations/src/zh-CN.ts b/packages/localizations/src/zh-CN.ts index 50fd9254b16..ebde399f28f 100644 --- a/packages/localizations/src/zh-CN.ts +++ b/packages/localizations/src/zh-CN.ts @@ -242,6 +242,21 @@ export const zhCN: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -626,6 +641,10 @@ export const zhCN: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: '请联系您的组织管理员以升级您的权限。', @@ -678,6 +697,10 @@ export const zhCN: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: '自定义 SAML 提供商', google: undefined, diff --git a/packages/localizations/src/zh-TW.ts b/packages/localizations/src/zh-TW.ts index b79689fb355..9696c4b0d31 100644 --- a/packages/localizations/src/zh-TW.ts +++ b/packages/localizations/src/zh-TW.ts @@ -245,6 +245,21 @@ export const zhTW: LocalizationResource = { required: undefined, }, }, + oidcCustom: { + claimsStep: { + headerSubtitle: undefined, + }, + credentialsStep: { + headerSubtitle: undefined, + }, + endpointsStep: { + headerSubtitle: undefined, + }, + mainHeaderTitle: undefined, + redirectUriStep: { + headerSubtitle: undefined, + }, + }, samlCustom: { assignUsersStep: { headerSubtitle: undefined, @@ -629,6 +644,10 @@ export const zhTW: LocalizationResource = { }, mainHeaderTitle: undefined, }, + unsupportedProvider: { + description: undefined, + title: undefined, + }, }, missingManageEnterpriseConnectionsPermission: { subtitle: '請聯絡您的組織管理員以升級您的權限。', @@ -681,6 +700,10 @@ export const zhTW: LocalizationResource = { title: undefined, }, selectProviderStep: { + oidc: { + groupLabel: undefined, + oidcProvider: undefined, + }, saml: { customSaml: '自訂 SAML 提供者', google: undefined, diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts index e3f1bd7f3ca..bd986c8da97 100644 --- a/packages/shared/src/types/localization.ts +++ b/packages/shared/src/types/localization.ts @@ -1540,6 +1540,10 @@ export type __internal_LocalizationResource = { headerSubtitle: LocalizationValue; }; }; + unsupportedProvider: { + title: LocalizationValue; + description: LocalizationValue; + }; samlOkta: { mainHeaderTitle: LocalizationValue; createAppStep: { diff --git a/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts b/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts index 847acd860b1..5e9f58b678f 100644 --- a/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts +++ b/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts @@ -12,6 +12,7 @@ import { areAllOrganizationDomainsVerified, connectionBackingEmail, isEnterpriseConnectionConfigured, + isOidcProvider, organizationEnterpriseConnection, } from '../organizationEnterpriseConnection'; @@ -74,6 +75,18 @@ const derive = (overrides: Partial { + describe('isOidcProvider', () => { + it('recognizes OIDC provider keys with the oidc_ prefix', () => { + expect(isOidcProvider('oidc_custom')).toBe(true); + expect(isOidcProvider('oidc_clerk_dev')).toBe(true); + }); + + it('rejects malformed OIDC provider keys', () => { + expect(isOidcProvider('oidc')).toBe(false); + expect(isOidcProvider('oidcfoo')).toBe(false); + }); + }); + describe('hasConnection', () => { it('undefined connection → false', () => { expect(derive({ connection: undefined }).hasConnection).toBe(false); @@ -93,9 +106,7 @@ describe('organizationEnterpriseConnection', () => { it('connection → its provider', () => { expect(derive({ connection: makeConnection({ provider: 'saml_custom' }) }).provider).toBe('saml_custom'); }); - it('carries a derived OIDC key verbatim — the open family, not the oidc_custom alias', () => { - // The backend derives `oidc_` from the connection name; the entity must - // expose that real value so dispatch can prefix-match it. + it('carries a derived OIDC key verbatim', () => { expect(derive({ connection: makeConnection({ provider: 'oidc_clerk_dev' }) }).provider).toBe('oidc_clerk_dev'); }); }); diff --git a/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts b/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts index cf285e5b4cf..743e38bf60f 100644 --- a/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts +++ b/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts @@ -7,13 +7,7 @@ import type { import type { EnterpriseConnectionProviderType, OidcProviderType } from '../types'; -/** - * OIDC providers are recognized by protocol prefix, never by literal: the backend - * stores a derived `oidc_` key (open family), so the read-back provider is - * not a fixed enum. SAML providers stay exact literals. Single source of the - * prefix notion — dispatch and configuration checks both read it from here. - */ -export const isOidcProvider = (provider: string): provider is OidcProviderType => provider.startsWith('oidc'); +export const isOidcProvider = (provider: string): provider is OidcProviderType => provider.startsWith('oidc_'); /** * The email whose domain backs the connection: the user's primary address if @@ -102,9 +96,6 @@ export const organizationEnterpriseConnection = ({ const hasMinimumConfiguration = isEnterpriseConnectionConfigured(connection); return { - // Boundary cast at the FAPI edge: SAML returns exact literals, OIDC an open - // `oidc_` family. An unrecognized value degrades downstream (dispatch - // falls back), so the honest open type — not the `oidc_custom` input alias — holds here. provider: connection?.provider as EnterpriseConnectionProviderType | undefined, hasConnection, isActive, diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx index f4b4c5c0d8c..88b1ffb7c5a 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx @@ -1,30 +1,7 @@ -import { describe, expect, it, vi } from 'vitest'; - -import { Flow } from '@/customizables'; -import { bindCreateFixtures } from '@/test/create-fixtures'; -import { render, screen } from '@/test/utils'; -import { CardStateProvider } from '@/ui/elements/contexts'; +import { describe, expect, it } from 'vitest'; import type { EnterpriseConnectionProviderType } from '../../../types'; - -// The dispatch reads `organizationEnterpriseConnection.provider`. The nested -// sub-flows also read `enterpriseConnection` (via `Step.Footer.Reset`), which is -// left undefined so that footer self-hides in this isolated render. -const contextState = vi.hoisted(() => ({ provider: undefined as string | undefined })); - -vi.mock('../../../ConfigureSSOContext', () => ({ - useConfigureSSO: () => ({ - enterpriseConnection: undefined, - contentRef: { current: null }, - enterpriseConnectionMutations: {}, - organizationEnterpriseConnection: { - provider: contextState.provider, - hasConnection: true, - }, - }), -})); - -import { ConfigureProviderStep, resolveConfigureSteps } from '../index'; +import { resolveConfigureSteps } from '../index'; import { OidcCustomConfigureSteps } from '../oidc'; import { SamlCustomConfigureSteps, @@ -33,12 +10,8 @@ import { SamlOktaConfigureSteps, } from '../saml'; -const { createFixtures } = bindCreateFixtures('ConfigureSSO'); - describe('resolveConfigureSteps', () => { - it('dispatches a derived OIDC provider key to the OIDC sub-flow by prefix (not the oidc_custom literal)', () => { - // The regression: the backend returns `oidc_` derived from the connection - // name (e.g. `clerk.dev` → `oidc_clerk_dev`), never the `oidc_custom` input alias. + it('dispatches OIDC provider keys to the OIDC sub-flow', () => { expect(resolveConfigureSteps('oidc_clerk_dev')).toBe(OidcCustomConfigureSteps); expect(resolveConfigureSteps('oidc_ghe_acme')).toBe(OidcCustomConfigureSteps); expect(resolveConfigureSteps('oidc_gitlab_ent_acme')).toBe(OidcCustomConfigureSteps); @@ -56,35 +29,3 @@ describe('resolveConfigureSteps', () => { expect(resolveConfigureSteps('ldap_enterprise' as EnterpriseConnectionProviderType)).toBeUndefined(); }); }); - -describe('ConfigureProviderStep', () => { - const renderStep = (wrapper: React.ComponentType<{ children?: React.ReactNode }>) => - render( - - - - - , - { wrapper }, - ); - - it('renders the OIDC configure steps for a derived provider key without throwing', async () => { - contextState.provider = 'oidc_clerk_dev'; - const { wrapper } = await createFixtures(); - - renderStep(wrapper); - - // The OIDC sub-flow mounts on its first step. Before the fix this threw - // `No steps found for provider: oidc_clerk_dev` and white-screened the wizard. - expect(await screen.findByText(/create a new oidc application/i)).toBeInTheDocument(); - }); - - it('degrades to the unsupported-provider state for a provider the SDK does not recognize', async () => { - contextState.provider = 'ldap_enterprise'; - const { wrapper } = await createFixtures(); - - renderStep(wrapper); - - expect(await screen.findByText(/unsupported provider/i)).toBeInTheDocument(); - }); -}); diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx index 0afc876b794..1b965f20e19 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx @@ -1,6 +1,6 @@ import React, { type JSX } from 'react'; -import { descriptors, Flow } from '@/customizables'; +import { descriptors, Flow, localizationKeys } from '@/customizables'; import { CardStateProvider } from '@/elements/contexts'; import { useConfigureSSO } from '../../ConfigureSSOContext'; @@ -26,12 +26,6 @@ const STEPS_BY_SAML_PROVIDER: Record saml_microsoft: SamlMicrosoftConfigureSteps, }; -/** - * Resolves the configure sub-flow for a created connection's provider. OIDC is an - * open, backend-derived family (`oidc_`), so every OIDC provider shares one - * sub-flow and is matched by protocol prefix; SAML stays an exact-literal lookup. - * Returns `undefined` for an unrecognized provider so the caller can degrade. - */ export const resolveConfigureSteps = ( provider: EnterpriseConnectionProviderType, ): ConfigureStepsComponent | undefined => @@ -68,7 +62,7 @@ export const ConfigureStep = (): JSX.Element => { ); }; -export const ConfigureProviderStep = (): JSX.Element | null => { +const ConfigureProviderStep = (): JSX.Element | null => { const { organizationEnterpriseConnection: c } = useConfigureSSO(); // Type guard: the provider should be defined by the time we reach configure. @@ -87,12 +81,10 @@ export const ConfigureProviderStep = (): JSX.Element | null => { {ConfigureSteps ? ( ) : ( - // A provider the SDK doesn't recognize (e.g. a newer backend family) - // degrades to a terminal state instead of white-screening the wizard. <> diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx index d5100e7c2ca..ce7866c38c0 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx @@ -1,5 +1,3 @@ -import { type JSX } from 'react'; - import { localizationKeys } from '@/customizables'; import { Step } from '../../../elements/Step'; @@ -13,9 +11,8 @@ const OIDC_STEPS: WizardStepConfig[] = [ { id: 'credentials' }, ]; -export const OidcCustomConfigureSteps = (): JSX.Element => { +export const OidcCustomConfigureSteps = () => { return ( - // Linear, guard-less sub-flow: mount on the first step, mirroring the SAML custom inner wizard. { ); }; -const OidcRedirectUriStep = (): JSX.Element => { +const OidcRedirectUriStep = () => { const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); return ( @@ -68,7 +65,7 @@ const OidcRedirectUriStep = (): JSX.Element => { ); }; -const OidcClaimsStep = (): JSX.Element => { +const OidcClaimsStep = () => { const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); return ( @@ -97,7 +94,7 @@ const OidcClaimsStep = (): JSX.Element => { ); }; -const OidcEndpointsStep = (): JSX.Element => { +const OidcEndpointsStep = () => { const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); return ( @@ -126,7 +123,7 @@ const OidcEndpointsStep = (): JSX.Element => { ); }; -const OidcCredentialsStep = (): JSX.Element => { +const OidcCredentialsStep = () => { const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); return ( @@ -146,7 +143,6 @@ const OidcCredentialsStep = (): JSX.Element => { onClick={() => goPrev()} isDisabled={isFirstStep} /> - {/* Terminal step: the connection submit lands with the credentials step ticket; disabled as a placeholder. */} goNext()} isDisabled={isLastStep} diff --git a/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx b/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx index 877f99c1572..7fde28ee673 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx @@ -70,11 +70,6 @@ const PROVIDER_GROUPS: ReadonlyArray<{ const providerLabel = (provider: ProviderType): LocalizationKey | undefined => PROVIDER_GROUPS.flatMap(group => group.options).find(option => option.id === provider)?.label; -/** - * The picker works in input aliases; an existing connection reports back its real - * provider (OIDC as an open `oidc_` family), so collapse it onto the card - * that represents it — every OIDC family maps to the single `oidc_custom` card. - */ const toProviderCard = (provider: EnterpriseConnectionProviderType): ProviderType => isOidcProvider(provider) ? 'oidc_custom' : provider; @@ -88,7 +83,6 @@ export const SelectProviderStep = (): JSX.Element => { const { goNext, goPrev, isFirstStep } = useWizard(); const { t } = useLocalizations(); - // OIDC is gated behind the experimental self-serve flag; SAML always shows. const providerGroups = React.useMemo( () => PROVIDER_GROUPS.filter(group => group.id !== 'oidc' || isOIDCFlowEnabled), [isOIDCFlowEnabled], diff --git a/packages/ui/src/components/ConfigureSSO/steps/__tests__/SelectProviderStep.test.tsx b/packages/ui/src/components/ConfigureSSO/steps/__tests__/SelectProviderStep.test.tsx index e8e5bff62b1..d63a7187d00 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/__tests__/SelectProviderStep.test.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/__tests__/SelectProviderStep.test.tsx @@ -112,11 +112,10 @@ describe('SelectProviderStep', () => { it('hides the OIDC provider tile when the flag is off', async () => { resetMocks(); const { wrapper } = await createFixtures(); - renderStep(wrapper); + const { container } = renderStep(wrapper); - // SAML is unaffected by the gate; only OIDC is hidden. expect(screen.getByRole('radio', { name: 'Okta Workforce' })).toBeInTheDocument(); - expect(screen.queryByRole('radio', { name: 'OIDC Provider' })).not.toBeInTheDocument(); + expect(container.querySelector('input[value="oidc_custom"]')).not.toBeInTheDocument(); }); it('shows the OIDC provider tile when the flag is on', async () => { @@ -125,10 +124,7 @@ describe('SelectProviderStep', () => { const { wrapper } = await createFixtures(); const { container } = renderStep(wrapper); - expect(screen.getByRole('radio', { name: 'OIDC Provider' })).toBeInTheDocument(); - // Four SAML tiles plus the single OIDC tile. - const iconSpans = Array.from(container.querySelectorAll('label span[aria-hidden]')); - expect(iconSpans).toHaveLength(5); + expect(container.querySelector('input[value="oidc_custom"]')).toBeInTheDocument(); }); }); diff --git a/packages/ui/src/components/ConfigureSSO/types.ts b/packages/ui/src/components/ConfigureSSO/types.ts index fac467ce444..6f502b168d9 100644 --- a/packages/ui/src/components/ConfigureSSO/types.ts +++ b/packages/ui/src/components/ConfigureSSO/types.ts @@ -1,24 +1,9 @@ -/** SAML providers are exact backend literals — the read-back key matches the input alias. */ export type SamlProviderType = 'saml_okta' | 'saml_custom' | 'saml_google' | 'saml_microsoft'; -/** - * The OIDC provider family a created connection reports back. The backend derives - * the key from the connection name (`oidc_`, plus `oidc_ghe_` and - * `oidc_gitlab_ent_`), so it is an open string, never the `oidc_custom` - * input alias the picker sends. - */ export type OidcProviderType = `oidc_${string}`; -/** - * The provider the SELECT step SENDS on create. OIDC always creates through the - * single `oidc_custom` input alias; the backend then derives the real key. - */ export type ProviderType = SamlProviderType | 'oidc_custom'; -/** - * The provider a created connection READS BACK. SAML narrows to the exact literals; - * OIDC is the open, backend-derived family — dispatch on this by protocol, not literal. - */ export type EnterpriseConnectionProviderType = SamlProviderType | OidcProviderType; export type WizardStepId = From d81d7b72e8f5b048ebd9de781a9ed0c9ae7943cc Mon Sep 17 00:00:00 2001 From: nicolas lopes <57234795+NicolasLopes7@users.noreply.github.com> Date: Tue, 28 Jul 2026 14:24:46 -0300 Subject: [PATCH 3/8] feat(ui): add OIDC self-serve SSO configuration (#9205) --- .../core/resources/EnterpriseConnection.ts | 8 + packages/localizations/src/en-US.ts | 58 +++- packages/shared/src/types/elementIds.ts | 10 + .../shared/src/types/enterpriseConnection.ts | 8 + packages/shared/src/types/localization.ts | 56 +++- .../organizationEnterpriseConnection.test.ts | 21 +- .../organizationEnterpriseConnection.ts | 4 +- .../__tests__/ConfigureStep.test.tsx | 302 +++++++++++++++++- .../steps/ConfigureStep/index.tsx | 3 +- .../oidc/OidcCustomConfigureSteps.tsx | 155 ++------- .../oidc/shared/OidcCredentialsStep.tsx | 106 ++++++ .../shared/OidcEndpointsConfigurationForm.tsx | 66 ++++ .../oidc/shared/OidcEndpointsStep.tsx | 165 ++++++++++ .../oidc/shared/OidcRedirectUriStep.tsx | 177 ++++++++++ .../saml/SamlCustomConfigureSteps.tsx | 12 +- .../saml/SamlGoogleConfigureSteps.tsx | 12 +- .../saml/SamlMicrosoftConfigureSteps.tsx | 12 +- .../saml/SamlOktaConfigureSteps.tsx | 12 +- .../IdentityProviderConfigurationForm.tsx | 6 +- .../IdentityProviderConfigurationModes.tsx | 58 ---- .../shared/ActiveConnectionAlert.tsx | 2 +- .../IdentityProviderConfigurationModes.tsx | 50 +++ .../ui/src/components/ConfigureSSO/types.ts | 2 +- 23 files changed, 1055 insertions(+), 250 deletions(-) create mode 100644 packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcCredentialsStep.tsx create mode 100644 packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsConfigurationForm.tsx create mode 100644 packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsStep.tsx create mode 100644 packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcRedirectUriStep.tsx delete mode 100644 packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/shared/IdentityProviderConfigurationModes.tsx rename packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/{saml => }/shared/ActiveConnectionAlert.tsx (91%) create mode 100644 packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/shared/IdentityProviderConfigurationModes.tsx diff --git a/packages/clerk-js/src/core/resources/EnterpriseConnection.ts b/packages/clerk-js/src/core/resources/EnterpriseConnection.ts index 109e7775ce1..f50213ded64 100644 --- a/packages/clerk-js/src/core/resources/EnterpriseConnection.ts +++ b/packages/clerk-js/src/core/resources/EnterpriseConnection.ts @@ -59,7 +59,11 @@ function oauthConfigFromJSON(data: EnterpriseOAuthConfigJSON): EnterpriseOAuthCo name: data.name, clientId: data.client_id, providerKey: data.provider_key, + redirectUri: data.redirect_uri, discoveryUrl: data.discovery_url, + authUrl: data.auth_url, + tokenUrl: data.token_url, + userInfoUrl: data.user_info_url, logoPublicUrl: data.logo_public_url, requiresPkce: data.requires_pkce, createdAt: unixEpochToDate(data.created_at), @@ -73,7 +77,11 @@ function oauthConfigToJSON(data: EnterpriseOAuthConfigResource): EnterpriseOAuth name: data.name, client_id: data.clientId, provider_key: data.providerKey, + redirect_uri: data.redirectUri, discovery_url: data.discoveryUrl, + auth_url: data.authUrl, + token_url: data.tokenUrl, + user_info_url: data.userInfoUrl, logo_public_url: data.logoPublicUrl, requires_pkce: data.requiresPkce, created_at: data.createdAt?.getTime() ?? 0, diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts index 80806cc7989..54590049b85 100644 --- a/packages/localizations/src/en-US.ts +++ b/packages/localizations/src/en-US.ts @@ -241,18 +241,70 @@ export const enUS: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: 'Set the claims your identity provider includes in the ID token', - }, credentialsStep: { headerSubtitle: 'Add your application credentials', + clientId: { + label: 'Client ID', + placeholder: 'Paste client ID here...', + }, + clientSecret: { + label: 'Client secret', + placeholder: 'Paste client secret here...', + }, + paragraph: 'In your identity provider’s OIDC application, retrieve these values.', }, endpointsStep: { headerSubtitle: 'Add your identity provider’s endpoints', + discoveryUrl: { + description: + 'In your identity provider’s OIDC application, retrieve the discovery endpoint. Paste it below.', + label: 'Discovery endpoint', + placeholder: 'Paste URL here...', + }, + manual: { + authUrl: { + label: 'Authorization URL', + placeholder: 'Paste URL here...', + }, + description: 'In your identity provider’s OIDC application, retrieve these values.', + tokenUrl: { + label: 'Token URL', + placeholder: 'Paste URL here...', + }, + userInfoUrl: { + label: 'User Info URL', + placeholder: 'Paste URL here...', + }, + }, + modes: { + ariaLabel: 'OIDC endpoint configuration method', + discoveryUrl: 'Add via discovery endpoint', + manual: 'Configure manually', + }, }, mainHeaderTitle: 'Configure your identity provider', redirectUriStep: { headerSubtitle: 'Create a new OIDC application in your identity provider’s dashboard', + paragraph: + 'In your identity provider’s dashboard, create a new OIDC application that supports the authorization code grant type, and use the following redirect URI:', + claims: { + description: 'Ensure your ID token includes the following claims:', + table: { + columns: { + attribute: 'Clerk attribute', + claim: 'ID token claim', + }, + rows: { + email: { attribute: 'Primary email' }, + firstName: { attribute: 'First name' }, + lastName: { attribute: 'Last name' }, + subject: { attribute: 'External user ID' }, + }, + }, + }, + redirectUri: { + label: 'Authorized redirect URI', + }, }, }, samlCustom: { diff --git a/packages/shared/src/types/elementIds.ts b/packages/shared/src/types/elementIds.ts index b685d908db7..32b62ccb70e 100644 --- a/packages/shared/src/types/elementIds.ts +++ b/packages/shared/src/types/elementIds.ts @@ -31,6 +31,16 @@ export type FieldId = | 'idpMetadata' | 'idpMetadataUrl' | 'idpSsoUrl' + | 'discoveryUrl' + | 'authUrl' + | 'tokenUrl' + | 'userInfoUrl' + | 'clientId' + | 'clientSecret' + | 'redirectUri' + | 'oidcClientId' + | 'oidcClientSecret' + | 'oidcRedirectUri' | 'acsUrl' | 'spEntityId' | 'web3WalletName' diff --git a/packages/shared/src/types/enterpriseConnection.ts b/packages/shared/src/types/enterpriseConnection.ts index f3e17fc9367..ed5c59eaa4d 100644 --- a/packages/shared/src/types/enterpriseConnection.ts +++ b/packages/shared/src/types/enterpriseConnection.ts @@ -100,7 +100,11 @@ export interface EnterpriseOAuthConfigJSON { name: string; provider_key?: string; client_id: string; + redirect_uri?: string; discovery_url?: string; + auth_url?: string; + token_url?: string; + user_info_url?: string; logo_public_url?: string | null; requires_pkce?: boolean; created_at: number; @@ -112,7 +116,11 @@ export interface EnterpriseOAuthConfigResource { name: string; clientId: string; providerKey?: string; + redirectUri?: string; discoveryUrl?: string; + authUrl?: string; + tokenUrl?: string; + userInfoUrl?: string; logoPublicUrl?: string | null; requiresPkce?: boolean; createdAt: Date | null; diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts index 98a6d14f05e..d73ed179a04 100644 --- a/packages/shared/src/types/localization.ts +++ b/packages/shared/src/types/localization.ts @@ -1530,15 +1530,65 @@ export type __internal_LocalizationResource = { mainHeaderTitle: LocalizationValue; redirectUriStep: { headerSubtitle: LocalizationValue; - }; - claimsStep: { - headerSubtitle: LocalizationValue; + paragraph: LocalizationValue; + claims: { + description: LocalizationValue; + table: { + columns: { + attribute: LocalizationValue; + claim: LocalizationValue; + }; + rows: { + email: { attribute: LocalizationValue }; + firstName: { attribute: LocalizationValue }; + lastName: { attribute: LocalizationValue }; + subject: { attribute: LocalizationValue }; + }; + }; + }; + redirectUri: { + label: LocalizationValue; + }; }; endpointsStep: { headerSubtitle: LocalizationValue; + discoveryUrl: { + description: LocalizationValue; + label: LocalizationValue; + placeholder: LocalizationValue; + }; + manual: { + authUrl: { + label: LocalizationValue; + placeholder: LocalizationValue; + }; + description: LocalizationValue; + tokenUrl: { + label: LocalizationValue; + placeholder: LocalizationValue; + }; + userInfoUrl: { + label: LocalizationValue; + placeholder: LocalizationValue; + }; + }; + modes: { + ariaLabel: LocalizationValue; + discoveryUrl: LocalizationValue; + manual: LocalizationValue; + }; }; credentialsStep: { headerSubtitle: LocalizationValue; + clientId: { + label: LocalizationValue; + placeholder: LocalizationValue; + }; + clientSecret: { + label: LocalizationValue; + placeholder: LocalizationValue; + }; + paragraph: LocalizationValue; }; }; unsupportedProvider: { diff --git a/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts b/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts index ce024f41248..278a2d9fa0c 100644 --- a/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts +++ b/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts @@ -12,7 +12,6 @@ import { areAllOrganizationDomainsVerified, connectionBackingEmail, isEnterpriseConnectionConfigured, - isOidcProvider, organizationEnterpriseConnection, } from '../organizationEnterpriseConnection'; @@ -62,7 +61,7 @@ const fullyConfiguredSaml = makeSamlConnection({ const configuredOidc = makeOauthConfig({ clientId: 'client_abc' }); const makeOidcConnection = (overrides: Partial = {}): EnterpriseConnectionResource => - makeConnection({ provider: 'oidc_custom', samlConnection: null, oauthConfig: configuredOidc, ...overrides }); + makeConnection({ provider: 'oauth_custom_acme', samlConnection: null, oauthConfig: configuredOidc, ...overrides }); // Builds the entity with sensible defaults; each test overrides what it cares // about. @@ -75,18 +74,6 @@ const derive = (overrides: Partial { - describe('isOidcProvider', () => { - it('recognizes OIDC provider keys with the oidc_ prefix', () => { - expect(isOidcProvider('oidc_custom')).toBe(true); - expect(isOidcProvider('oidc_clerk_dev')).toBe(true); - }); - - it('rejects malformed OIDC provider keys', () => { - expect(isOidcProvider('oidc')).toBe(false); - expect(isOidcProvider('oidcfoo')).toBe(false); - }); - }); - describe('hasConnection', () => { it('undefined connection → false', () => { expect(derive({ connection: undefined }).hasConnection).toBe(false); @@ -106,8 +93,10 @@ describe('organizationEnterpriseConnection', () => { it('connection → its provider', () => { expect(derive({ connection: makeConnection({ provider: 'saml_custom' }) }).provider).toBe('saml_custom'); }); - it('carries a derived OIDC key verbatim', () => { - expect(derive({ connection: makeConnection({ provider: 'oidc_clerk_dev' }) }).provider).toBe('oidc_clerk_dev'); + it('carries a custom OIDC key verbatim', () => { + expect(derive({ connection: makeConnection({ provider: 'oauth_custom_clerk_dev' }) }).provider).toBe( + 'oauth_custom_clerk_dev', + ); }); }); diff --git a/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts b/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts index 743e38bf60f..eb6937f63ed 100644 --- a/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts +++ b/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts @@ -7,7 +7,8 @@ import type { import type { EnterpriseConnectionProviderType, OidcProviderType } from '../types'; -export const isOidcProvider = (provider: string): provider is OidcProviderType => provider.startsWith('oidc_'); +export const isOidcProvider = (provider: string): provider is OidcProviderType => + provider.startsWith('oidc_') || provider.startsWith('oauth_custom_'); /** * The email whose domain backs the connection: the user's primary address if @@ -56,7 +57,6 @@ export const isEnterpriseConnectionConfigured = ( if (!connection) { return false; } - // OIDC exposes only the client ID on the resource; the secret and manual endpoints are write-only. if (isOidcProvider(connection.provider)) { return Boolean(connection.oauthConfig?.clientId); } diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx index 88b1ffb7c5a..c0d83f54193 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx @@ -1,7 +1,45 @@ -import { describe, expect, it } from 'vitest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { Flow } from '@/customizables'; +import { bindCreateFixtures } from '@/test/create-fixtures'; +import { render, screen } from '@/test/utils'; +import { CardStateProvider } from '@/ui/elements/contexts'; import type { EnterpriseConnectionProviderType } from '../../../types'; -import { resolveConfigureSteps } from '../index'; + +// The dispatch reads `organizationEnterpriseConnection.provider`. The nested +// sub-flows also read `enterpriseConnection` (via `Step.Footer.Reset`), which is +// left undefined so that footer self-hides in this isolated render. +const contextState = vi.hoisted(() => ({ + provider: undefined as string | undefined, + enterpriseConnection: undefined as + | { + id: string; + oauthConfig: { + redirectUri?: string; + discoveryUrl?: string; + authUrl?: string; + tokenUrl?: string; + userInfoUrl?: string; + } | null; + } + | undefined, +})); +const updateConnection = vi.hoisted(() => vi.fn()); + +vi.mock('../../../ConfigureSSOContext', () => ({ + useConfigureSSO: () => ({ + enterpriseConnection: contextState.enterpriseConnection, + contentRef: { current: null }, + enterpriseConnectionMutations: { updateConnection }, + organizationEnterpriseConnection: { + provider: contextState.provider, + hasConnection: true, + }, + }), +})); + +import { ConfigureProviderStep, resolveConfigureSteps } from '../index'; import { OidcCustomConfigureSteps } from '../oidc'; import { SamlCustomConfigureSteps, @@ -10,8 +48,11 @@ import { SamlOktaConfigureSteps, } from '../saml'; +const { createFixtures } = bindCreateFixtures('ConfigureSSO'); + describe('resolveConfigureSteps', () => { - it('dispatches OIDC provider keys to the OIDC sub-flow', () => { + it('dispatches custom and legacy OIDC provider keys to the OIDC sub-flow', () => { + expect(resolveConfigureSteps('oauth_custom_clerk_dev')).toBe(OidcCustomConfigureSteps); expect(resolveConfigureSteps('oidc_clerk_dev')).toBe(OidcCustomConfigureSteps); expect(resolveConfigureSteps('oidc_ghe_acme')).toBe(OidcCustomConfigureSteps); expect(resolveConfigureSteps('oidc_gitlab_ent_acme')).toBe(OidcCustomConfigureSteps); @@ -29,3 +70,258 @@ describe('resolveConfigureSteps', () => { expect(resolveConfigureSteps('ldap_enterprise' as EnterpriseConnectionProviderType)).toBeUndefined(); }); }); + +describe('ConfigureProviderStep', () => { + beforeEach(() => { + contextState.provider = undefined; + contextState.enterpriseConnection = undefined; + updateConnection.mockReset(); + }); + + const renderStep = (wrapper: React.ComponentType<{ children?: React.ReactNode }>) => + render( + + + + + , + { wrapper }, + ); + + it('renders the OIDC configure steps for a custom OAuth provider key without throwing', async () => { + contextState.provider = 'oauth_custom_clerk_dev'; + contextState.enterpriseConnection = { + id: 'ent_123', + oauthConfig: { + redirectUri: 'https://instance.example/v1/oauth_callback', + }, + }; + const { wrapper } = await createFixtures(); + + const { userEvent } = renderStep(wrapper); + + expect(await screen.findAllByText(/create a new oidc application/i)).not.toHaveLength(0); + const redirectUri = screen.getByRole('textbox', { name: 'Authorized redirect URI' }); + expect(redirectUri).toHaveAttribute('readonly'); + expect(redirectUri).toHaveValue('https://instance.example/v1/oauth_callback'); + expect(screen.getByText('Ensure your ID token includes the following claims:')).toBeInTheDocument(); + expect(screen.getByRole('table')).toBeInTheDocument(); + expect(screen.getAllByRole('row')).toHaveLength(5); + expect(screen.getByText('sub')).toBeInTheDocument(); + expect(screen.getByText('email')).toBeInTheDocument(); + expect(screen.getByRole('columnheader', { name: 'ID token claim' })).toBeInTheDocument(); + expect(screen.getByText('given_name')).toBeInTheDocument(); + expect(screen.getByText('family_name')).toBeInTheDocument(); + + await userEvent.click(screen.getByRole('button', { name: 'Continue' })); + + const discoveryMode = await screen.findByRole('radio', { name: 'Add via discovery endpoint' }); + const manualMode = screen.getByRole('radio', { name: 'Configure manually' }); + expect(discoveryMode).toBeChecked(); + expect(screen.getAllByRole('textbox')).toHaveLength(1); + expect(screen.getByRole('button', { name: 'Continue' })).toBeDisabled(); + + await userEvent.click(manualMode); + + expect(screen.getAllByRole('textbox')).toHaveLength(3); + }); + + it('saves the discovery endpoint before advancing to credentials', async () => { + contextState.provider = 'oidc_clerk_dev'; + contextState.enterpriseConnection = { id: 'ent_123', oauthConfig: null }; + updateConnection.mockReset(); + updateConnection.mockResolvedValue({}); + const { wrapper } = await createFixtures(); + + const { userEvent } = renderStep(wrapper); + + await userEvent.click(await screen.findByRole('button', { name: 'Continue' })); + await userEvent.type( + screen.getByRole('textbox', { name: 'Discovery endpoint' }), + 'https://idp.example/.well-known/openid-configuration', + ); + await userEvent.click(screen.getByRole('button', { name: 'Continue' })); + + await vi.waitFor(() => { + expect(updateConnection).toHaveBeenCalledWith('ent_123', { + oidc: { discoveryUrl: 'https://idp.example/.well-known/openid-configuration' }, + }); + }); + }); + + it('saves manual endpoints before advancing to credentials', async () => { + contextState.provider = 'oidc_clerk_dev'; + contextState.enterpriseConnection = { id: 'ent_123', oauthConfig: null }; + updateConnection.mockReset(); + updateConnection.mockResolvedValue({}); + const { wrapper } = await createFixtures(); + + const { userEvent } = renderStep(wrapper); + + await userEvent.click(await screen.findByRole('button', { name: 'Continue' })); + const manualMode = await screen.findByRole('radio', { name: 'Configure manually' }); + await userEvent.click(manualMode); + + const authUrl = screen.getByRole('textbox', { name: 'Authorization URL' }); + const tokenUrl = screen.getByRole('textbox', { name: 'Token URL' }); + const userInfoUrl = screen.getByRole('textbox', { name: 'User Info URL' }); + await userEvent.type(authUrl, 'https://idp.example/authorize'); + await userEvent.type(tokenUrl, 'https://idp.example/token'); + await userEvent.type(userInfoUrl, 'https://idp.example/userinfo'); + await userEvent.click(screen.getByRole('button', { name: 'Continue' })); + + await vi.waitFor(() => { + expect(updateConnection).toHaveBeenCalledWith('ent_123', { + oidc: { + authUrl: 'https://idp.example/authorize', + tokenUrl: 'https://idp.example/token', + userInfoUrl: 'https://idp.example/userinfo', + }, + }); + }); + }); + + it('saves manual endpoints without a user info URL', async () => { + contextState.provider = 'oidc_clerk_dev'; + contextState.enterpriseConnection = { id: 'ent_123', oauthConfig: null }; + updateConnection.mockReset(); + updateConnection.mockResolvedValue({}); + const { wrapper } = await createFixtures(); + + const { userEvent } = renderStep(wrapper); + + await userEvent.click(await screen.findByRole('button', { name: 'Continue' })); + const manualMode = await screen.findByRole('radio', { name: 'Configure manually' }); + await userEvent.click(manualMode); + + const authUrl = screen.getByRole('textbox', { name: 'Authorization URL' }); + const tokenUrl = screen.getByRole('textbox', { name: 'Token URL' }); + await userEvent.type(authUrl, 'https://idp.example/authorize'); + await userEvent.type(tokenUrl, 'https://idp.example/token'); + await userEvent.click(screen.getByRole('button', { name: 'Continue' })); + + await vi.waitFor(() => { + expect(updateConnection).toHaveBeenCalledWith('ent_123', { + oidc: { + authUrl: 'https://idp.example/authorize', + tokenUrl: 'https://idp.example/token', + userInfoUrl: '', + }, + }); + }); + }); + + it('saves credentials before advancing', async () => { + contextState.provider = 'oidc_clerk_dev'; + contextState.enterpriseConnection = { id: 'ent_123', oauthConfig: null }; + updateConnection.mockReset(); + updateConnection.mockResolvedValue({}); + const { wrapper } = await createFixtures(); + + const { userEvent } = renderStep(wrapper); + + await userEvent.click(await screen.findByRole('button', { name: 'Continue' })); + await userEvent.type( + screen.getByRole('textbox', { name: 'Discovery endpoint' }), + 'https://idp.example/.well-known/openid-configuration', + ); + await userEvent.click(screen.getByRole('button', { name: 'Continue' })); + + const clientId = await screen.findByRole('textbox', { name: 'Client ID' }); + const clientSecret = screen.getByLabelText('Client secret'); + await userEvent.type(clientId, 'client_123'); + await userEvent.type(clientSecret, 'secret_456'); + + await userEvent.click(screen.getByRole('button', { name: 'Continue' })); + + await vi.waitFor(() => { + expect(updateConnection).toHaveBeenLastCalledWith('ent_123', { + oidc: { clientId: 'client_123', clientSecret: 'secret_456' }, + }); + }); + }); + + it('selects manual mode when an existing connection has manual endpoints without a discovery URL', async () => { + contextState.provider = 'oidc_clerk_dev'; + contextState.enterpriseConnection = { + id: 'ent_123', + oauthConfig: { + authUrl: 'https://idp.example/authorize', + tokenUrl: 'https://idp.example/token', + userInfoUrl: 'https://idp.example/userinfo', + }, + }; + const { wrapper } = await createFixtures(); + + const { userEvent } = renderStep(wrapper); + + await userEvent.click(await screen.findByRole('button', { name: 'Continue' })); + + const discoveryMode = await screen.findByRole('radio', { name: 'Add via discovery endpoint' }); + const manualMode = screen.getByRole('radio', { name: 'Configure manually' }); + expect(discoveryMode).not.toBeChecked(); + expect(manualMode).toBeChecked(); + expect(screen.getByRole('textbox', { name: 'Authorization URL' })).toHaveValue('https://idp.example/authorize'); + }); + + it('populates manual endpoints resolved from discovery', async () => { + contextState.provider = 'oidc_clerk_dev'; + contextState.enterpriseConnection = { + id: 'ent_123', + oauthConfig: { + discoveryUrl: 'https://idp.example/.well-known/openid-configuration', + authUrl: 'https://idp.example/authorize', + tokenUrl: 'https://idp.example/token', + userInfoUrl: 'https://idp.example/userinfo', + }, + }; + const { wrapper } = await createFixtures(); + + const { userEvent } = renderStep(wrapper); + + await userEvent.click(await screen.findByRole('button', { name: 'Continue' })); + const manualMode = await screen.findByRole('radio', { name: 'Configure manually' }); + await userEvent.click(manualMode); + + expect(screen.getByRole('textbox', { name: 'Authorization URL' })).toHaveValue('https://idp.example/authorize'); + expect(screen.getByRole('textbox', { name: 'Token URL' })).toHaveValue('https://idp.example/token'); + expect(screen.getByRole('textbox', { name: 'User Info URL' })).toHaveValue('https://idp.example/userinfo'); + }); + + it('retains manual mode when returning from credentials with a stale discovery URL', async () => { + contextState.provider = 'oidc_clerk_dev'; + contextState.enterpriseConnection = { + id: 'ent_123', + oauthConfig: { + discoveryUrl: 'https://idp.example/.well-known/openid-configuration', + authUrl: 'https://idp.example/authorize', + tokenUrl: 'https://idp.example/token', + userInfoUrl: 'https://idp.example/userinfo', + }, + }; + updateConnection.mockResolvedValue({}); + const { wrapper } = await createFixtures(); + + const { userEvent } = renderStep(wrapper); + + await userEvent.click(await screen.findByRole('button', { name: 'Continue' })); + const manualMode = await screen.findByRole('radio', { name: 'Configure manually' }); + await userEvent.click(manualMode); + await userEvent.click(screen.getByRole('button', { name: 'Continue' })); + + await screen.findByRole('textbox', { name: 'Client ID' }); + await userEvent.click(screen.getByRole('button', { name: 'Previous' })); + + expect(await screen.findByRole('radio', { name: 'Configure manually' })).toBeChecked(); + expect(screen.getByRole('textbox', { name: 'Authorization URL' })).toHaveValue('https://idp.example/authorize'); + }); + + it('degrades to the unsupported-provider state for a provider the SDK does not recognize', async () => { + contextState.provider = 'ldap_enterprise'; + const { wrapper } = await createFixtures(); + + renderStep(wrapper); + + expect(await screen.findByText(/unsupported provider/i)).toBeInTheDocument(); + }); +}); diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx index 1b965f20e19..c687f4c7d3b 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx @@ -62,10 +62,9 @@ export const ConfigureStep = (): JSX.Element => { ); }; -const ConfigureProviderStep = (): JSX.Element | null => { +export const ConfigureProviderStep = (): JSX.Element | null => { const { organizationEnterpriseConnection: c } = useConfigureSSO(); - // Type guard: the provider should be defined by the time we reach configure. if (!c.provider) { return null; } diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx index ce7866c38c0..b7c27de5168 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx @@ -1,17 +1,21 @@ -import { localizationKeys } from '@/customizables'; - -import { Step } from '../../../elements/Step'; -import { useWizard, Wizard, type WizardStepConfig } from '../../../elements/Wizard'; -import { InnerStepCounter } from '../../../elements/Wizard/InnerStepCounter'; - -const OIDC_STEPS: WizardStepConfig[] = [ - { id: 'redirect-uri' }, - { id: 'claims' }, - { id: 'endpoints' }, - { id: 'credentials' }, -]; +import { type JSX, useState } from 'react'; + +import { useConfigureSSO } from '../../../ConfigureSSOContext'; +import { Wizard, type WizardStepConfig } from '../../../elements/Wizard'; +import type { OidcIdpConfigurationMode } from '../shared/IdentityProviderConfigurationModes'; +import { OidcCredentialsStep } from './shared/OidcCredentialsStep'; +import { OidcEndpointsStep } from './shared/OidcEndpointsStep'; +import { OidcRedirectUriStep } from './shared/OidcRedirectUriStep'; + +const OIDC_STEPS: WizardStepConfig[] = [{ id: 'redirect-uri' }, { id: 'endpoints' }, { id: 'credentials' }]; + +export const OidcCustomConfigureSteps = (): JSX.Element => { + const { enterpriseConnection } = useConfigureSSO(); + const oauthConfig = enterpriseConnection?.oauthConfig; + const [endpointMode, setEndpointMode] = useState( + oauthConfig?.authUrl && !oauthConfig.discoveryUrl ? 'manual' : 'discoveryUrl', + ); -export const OidcCustomConfigureSteps = () => { return ( { - - - - - + @@ -35,119 +38,3 @@ export const OidcCustomConfigureSteps = () => { ); }; - -const OidcRedirectUriStep = () => { - const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); - - return ( - <> - - - - - - - - - goPrev()} - isDisabled={isFirstStep} - /> - goNext()} - isDisabled={isLastStep} - /> - - - ); -}; - -const OidcClaimsStep = () => { - const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); - - return ( - <> - - - - - - - - - goPrev()} - isDisabled={isFirstStep} - /> - goNext()} - isDisabled={isLastStep} - /> - - - ); -}; - -const OidcEndpointsStep = () => { - const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); - - return ( - <> - - - - - - - - - goPrev()} - isDisabled={isFirstStep} - /> - goNext()} - isDisabled={isLastStep} - /> - - - ); -}; - -const OidcCredentialsStep = () => { - const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); - - return ( - <> - - - - - - - - - goPrev()} - isDisabled={isFirstStep} - /> - goNext()} - isDisabled={isLastStep} - /> - - - ); -}; diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcCredentialsStep.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcCredentialsStep.tsx new file mode 100644 index 00000000000..ed736081cfe --- /dev/null +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcCredentialsStep.tsx @@ -0,0 +1,106 @@ +import React, { type JSX } from 'react'; + +import { localizationKeys, Text } from '@/customizables'; +import { useCardState } from '@/elements/contexts'; +import { Form } from '@/elements/Form'; +import { useFormControl } from '@/ui/utils/useFormControl'; +import { handleError } from '@/utils/errorHandler'; + +import { useConfigureSSO } from '../../../../ConfigureSSOContext'; +import { Step } from '../../../../elements/Step'; +import { useWizard } from '../../../../elements/Wizard'; +import { InnerStepCounter } from '../../../../elements/Wizard/InnerStepCounter'; +import { ActiveConnectionAlert } from '../../shared/ActiveConnectionAlert'; + +export const OidcCredentialsStep = (): JSX.Element => { + const card = useCardState(); + const { goNext, goPrev, isFirstStep } = useWizard(); + const { + enterpriseConnection, + enterpriseConnectionMutations: { updateConnection }, + } = useConfigureSSO(); + const clientIdField = useFormControl('oidcClientId', enterpriseConnection?.oauthConfig?.clientId ?? '', { + type: 'text', + label: localizationKeys('configureSSO.configureStep.oidcCustom.credentialsStep.clientId.label'), + placeholder: localizationKeys('configureSSO.configureStep.oidcCustom.credentialsStep.clientId.placeholder'), + isRequired: true, + }); + const clientSecretField = useFormControl('oidcClientSecret', '', { + type: 'password', + label: localizationKeys('configureSSO.configureStep.oidcCustom.credentialsStep.clientSecret.label'), + placeholder: localizationKeys('configureSSO.configureStep.oidcCustom.credentialsStep.clientSecret.placeholder'), + isRequired: true, + }); + const [isSubmitting, setIsSubmitting] = React.useState(false); + + const canSubmit = clientIdField.value.trim().length > 0 && clientSecretField.value.trim().length > 0 && !isSubmitting; + + const handleContinue = async (): Promise => { + if (!enterpriseConnection || !canSubmit) { + return; + } + + card.setError(undefined); + setIsSubmitting(true); + + try { + await updateConnection(enterpriseConnection.id, { + oidc: { + clientId: clientIdField.value.trim(), + clientSecret: clientSecretField.value.trim(), + }, + }); + void goNext(); + } catch (err) { + handleError(err as Error, [clientIdField, clientSecretField], card.setError); + setIsSubmitting(false); + } + }; + + return ( + <> + + + + + + + + + + + + + + + + + + + + + + + goPrev()} + isDisabled={isFirstStep || isSubmitting} + /> + + + + ); +}; diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsConfigurationForm.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsConfigurationForm.tsx new file mode 100644 index 00000000000..ff6016fcead --- /dev/null +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsConfigurationForm.tsx @@ -0,0 +1,66 @@ +import type { FieldId } from '@clerk/shared/types'; +import { type JSX } from 'react'; + +import { type LocalizationKey, Text } from '@/customizables'; +import { Form } from '@/elements/Form'; +import type { FormControlState } from '@/ui/utils/useFormControl'; + +type FormControl = FormControlState; + +type DiscoveryUrlForm = { + discoveryUrlField: FormControl; +}; + +type DiscoveryUrlLabels = { + description: LocalizationKey; +}; + +type ManualEndpointsForm = { + authUrlField: FormControl; + tokenUrlField: FormControl; + userInfoUrlField: FormControl; +}; + +type ManualEndpointsLabels = { + description: LocalizationKey; +}; + +export type OidcEndpointsConfigurationFormProps = + | { mode: 'discoveryUrl'; form: DiscoveryUrlForm; labels: DiscoveryUrlLabels } + | { mode: 'manual'; form: ManualEndpointsForm; labels: ManualEndpointsLabels }; + +export const OidcEndpointsConfigurationForm = (props: OidcEndpointsConfigurationFormProps): JSX.Element => { + if (props.mode === 'discoveryUrl') { + return ( + <> + + + + + + ); + } + + return ( + <> + + + + + + + + + + + + ); +}; diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsStep.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsStep.tsx new file mode 100644 index 00000000000..cfc98ba99e1 --- /dev/null +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsStep.tsx @@ -0,0 +1,165 @@ +import React, { type JSX } from 'react'; + +import { localizationKeys } from '@/customizables'; +import { useCardState } from '@/elements/contexts'; +import { useFormControl } from '@/ui/utils/useFormControl'; +import { handleError } from '@/utils/errorHandler'; + +import { useConfigureSSO } from '../../../../ConfigureSSOContext'; +import { Step } from '../../../../elements/Step'; +import { useWizard } from '../../../../elements/Wizard'; +import { InnerStepCounter } from '../../../../elements/Wizard/InnerStepCounter'; +import { ActiveConnectionAlert } from '../../shared/ActiveConnectionAlert'; +import { + IdentityProviderConfigurationModes, + type OidcIdpConfigurationMode, +} from '../../shared/IdentityProviderConfigurationModes'; +import { + OidcEndpointsConfigurationForm, + type OidcEndpointsConfigurationFormProps, +} from './OidcEndpointsConfigurationForm'; + +const OIDC_ENDPOINT_MODES = ['discoveryUrl', 'manual'] as const satisfies readonly OidcIdpConfigurationMode[]; + +interface OidcEndpointsStepProps { + mode: OidcIdpConfigurationMode; + onModeChange: (mode: OidcIdpConfigurationMode) => void; +} + +export const OidcEndpointsStep = ({ mode, onModeChange }: OidcEndpointsStepProps): JSX.Element => { + const card = useCardState(); + const { goNext, goPrev, isFirstStep } = useWizard(); + const { + enterpriseConnection, + enterpriseConnectionMutations: { updateConnection }, + } = useConfigureSSO(); + const oauthConfig = enterpriseConnection?.oauthConfig; + const [isSubmitting, setIsSubmitting] = React.useState(false); + + const discoveryUrlField = useFormControl('discoveryUrl', oauthConfig?.discoveryUrl ?? '', { + type: 'text', + label: localizationKeys('configureSSO.configureStep.oidcCustom.endpointsStep.discoveryUrl.label'), + placeholder: localizationKeys('configureSSO.configureStep.oidcCustom.endpointsStep.discoveryUrl.placeholder'), + isRequired: true, + }); + const authUrlField = useFormControl('authUrl', oauthConfig?.authUrl ?? '', { + type: 'text', + label: localizationKeys('configureSSO.configureStep.oidcCustom.endpointsStep.manual.authUrl.label'), + placeholder: localizationKeys('configureSSO.configureStep.oidcCustom.endpointsStep.manual.authUrl.placeholder'), + isRequired: true, + }); + const tokenUrlField = useFormControl('tokenUrl', oauthConfig?.tokenUrl ?? '', { + type: 'text', + label: localizationKeys('configureSSO.configureStep.oidcCustom.endpointsStep.manual.tokenUrl.label'), + placeholder: localizationKeys('configureSSO.configureStep.oidcCustom.endpointsStep.manual.tokenUrl.placeholder'), + isRequired: true, + }); + const userInfoUrlField = useFormControl('userInfoUrl', oauthConfig?.userInfoUrl ?? '', { + type: 'text', + label: localizationKeys('configureSSO.configureStep.oidcCustom.endpointsStep.manual.userInfoUrl.label'), + placeholder: localizationKeys('configureSSO.configureStep.oidcCustom.endpointsStep.manual.userInfoUrl.placeholder'), + }); + + const isValid = + mode === 'discoveryUrl' + ? discoveryUrlField.value.trim().length > 0 + : authUrlField.value.trim().length > 0 && tokenUrlField.value.trim().length > 0; + + const canSubmit = isValid && !isSubmitting; + + const formProps: OidcEndpointsConfigurationFormProps = + mode === 'discoveryUrl' + ? { + mode: 'discoveryUrl', + form: { discoveryUrlField }, + labels: { + description: localizationKeys( + 'configureSSO.configureStep.oidcCustom.endpointsStep.discoveryUrl.description', + ), + }, + } + : { + mode: 'manual', + form: { authUrlField, tokenUrlField, userInfoUrlField }, + labels: { + description: localizationKeys('configureSSO.configureStep.oidcCustom.endpointsStep.manual.description'), + }, + }; + + const handleContinue = async (): Promise => { + if (!enterpriseConnection || !canSubmit) { + return; + } + + card.setError(undefined); + setIsSubmitting(true); + + try { + await updateConnection( + enterpriseConnection.id, + mode === 'discoveryUrl' + ? { oidc: { discoveryUrl: discoveryUrlField.value.trim() } } + : { + oidc: { + authUrl: authUrlField.value.trim(), + tokenUrl: tokenUrlField.value.trim(), + userInfoUrl: userInfoUrlField.value.trim(), + }, + }, + ); + void goNext(); + } catch (err) { + handleError( + err as Error, + mode === 'discoveryUrl' ? [discoveryUrlField] : [authUrlField, tokenUrlField, userInfoUrlField], + card.setError, + ); + setIsSubmitting(false); + } + }; + + return ( + <> + + + + + + + + + + + + + + + + goPrev()} + isDisabled={isFirstStep || isSubmitting} + /> + + + + ); +}; diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcRedirectUriStep.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcRedirectUriStep.tsx new file mode 100644 index 00000000000..36abd73b105 --- /dev/null +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcRedirectUriStep.tsx @@ -0,0 +1,177 @@ +import { type JSX } from 'react'; + +import { + Badge, + Col, + descriptors, + Flex, + localizationKeys, + Table, + Tbody, + Td, + Text, + Th, + Thead, + Tr, +} from '@/customizables'; +import { ClipboardInput } from '@/elements/ClipboardInput'; +import { Form } from '@/elements/Form'; +import { Checkmark, Clipboard } from '@/icons'; +import { useFormControl } from '@/ui/utils/useFormControl'; + +import { useConfigureSSO } from '../../../../ConfigureSSOContext'; +import { Step } from '../../../../elements/Step'; +import { useWizard } from '../../../../elements/Wizard'; +import { InnerStepCounter } from '../../../../elements/Wizard/InnerStepCounter'; + +type OidcClaimRow = { + id: 'subject' | 'email' | 'firstName' | 'lastName'; + claim: 'sub' | 'email' | 'given_name' | 'family_name'; + isRequired: boolean; +}; + +const OIDC_CLAIM_ROWS: ReadonlyArray = [ + { id: 'subject', claim: 'sub', isRequired: true }, + { id: 'email', claim: 'email', isRequired: true }, + { id: 'firstName', claim: 'given_name', isRequired: false }, + { id: 'lastName', claim: 'family_name', isRequired: false }, +]; + +const OidcClaimsTable = (): JSX.Element => ( + ({ + 'tr > th:first-of-type': { paddingInlineStart: theme.space.$4 }, + })} + > + + + + + + + + {OIDC_CLAIM_ROWS.map(row => ( + + + + + ))} + +
+ ({ fontSize: theme.fontSizes.$xs })} + localizationKey={localizationKeys( + 'configureSSO.configureStep.oidcCustom.redirectUriStep.claims.table.columns.claim', + )} + /> + + ({ fontSize: theme.fontSizes.$xs })} + localizationKey={localizationKeys( + 'configureSSO.configureStep.oidcCustom.redirectUriStep.claims.table.columns.attribute', + )} + /> +
+ ({ gap: theme.space.$2 })} + > + + {row.claim} + + + + + +
+); + +export const OidcRedirectUriStep = (): JSX.Element => { + const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); + const { enterpriseConnection } = useConfigureSSO(); + const redirectUri = enterpriseConnection?.oauthConfig?.redirectUri ?? ''; + const redirectUriField = useFormControl('oidcRedirectUri', redirectUri, { + type: 'text', + label: localizationKeys('configureSSO.configureStep.oidcCustom.redirectUriStep.redirectUri.label'), + isRequired: false, + }); + + return ( + <> + + + + + + ({ gap: theme.space.$5 })}> + ({ gap: theme.space.$1x5 })}> + + + + + + + + + + ({ gap: theme.space.$3 })}> + + + + + + + + + goPrev()} + isDisabled={isFirstStep} + /> + goNext()} + isDisabled={isLastStep} + /> + + + ); +}; diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlCustomConfigureSteps.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlCustomConfigureSteps.tsx index 315ef2b0718..ded9cbeafa4 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlCustomConfigureSteps.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlCustomConfigureSteps.tsx @@ -24,16 +24,16 @@ import { useConfigureSSO } from '../../../ConfigureSSOContext'; import { Step } from '../../../elements/Step'; import { useWizard, Wizard, type WizardStepConfig } from '../../../elements/Wizard'; import { InnerStepCounter } from '../../../elements/Wizard/InnerStepCounter'; +import { + IdentityProviderConfigurationModes, + type SamlIdpConfigurationMode, +} from '../shared/IdentityProviderConfigurationModes'; import { applySamlSubmitError, buildSamlConfigurationPayload, IdentityProviderConfigurationForm, type IdentityProviderConfigurationFormProps, } from './shared/IdentityProviderConfigurationForm'; -import { - IdentityProviderConfigurationModes, - type IdpConfigurationMode, -} from './shared/IdentityProviderConfigurationModes'; const CUSTOM_STEPS: WizardStepConfig[] = [ { id: 'create-app' }, @@ -308,7 +308,7 @@ const SamlCustomAssignUsersStep = (): JSX.Element => { ); }; -const CUSTOM_SAML_IDP_MODES = ['metadataUrl', 'manual'] as const satisfies readonly IdpConfigurationMode[]; +const CUSTOM_SAML_IDP_MODES = ['metadataUrl', 'manual'] as const satisfies readonly SamlIdpConfigurationMode[]; const SamlCustomIdentityProviderMetadataStep = (): JSX.Element => { const card = useCardState(); @@ -327,7 +327,7 @@ const SamlCustomIdentityProviderMetadataStep = (): JSX.Element => { ); const existingCertPresent = Boolean(samlConnection?.idpCertificate); - const [mode, setMode] = React.useState(hasExistingConfig ? 'manual' : 'metadataUrl'); + const [mode, setMode] = React.useState(hasExistingConfig ? 'manual' : 'metadataUrl'); const [certFile, setCertFile] = React.useState(null); // Step-LOCAL submit state for the Continue button. `goNext` bubbles to the // parent (this is the terminal nested step) and the parent DEFERS the diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlGoogleConfigureSteps.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlGoogleConfigureSteps.tsx index 1431d6f3325..dff36e9feaf 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlGoogleConfigureSteps.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlGoogleConfigureSteps.tsx @@ -12,16 +12,16 @@ import { useConfigureSSO } from '../../../ConfigureSSOContext'; import { Step } from '../../../elements/Step'; import { useWizard, Wizard, type WizardStepConfig } from '../../../elements/Wizard'; import { InnerStepCounter } from '../../../elements/Wizard/InnerStepCounter'; +import { + IdentityProviderConfigurationModes, + type SamlIdpConfigurationMode, +} from '../shared/IdentityProviderConfigurationModes'; import { applySamlSubmitError, buildSamlConfigurationPayload, IdentityProviderConfigurationForm, type IdentityProviderConfigurationFormProps, } from './shared/IdentityProviderConfigurationForm'; -import { - IdentityProviderConfigurationModes, - type IdpConfigurationMode, -} from './shared/IdentityProviderConfigurationModes'; const GOOGLE_STEPS: WizardStepConfig[] = [ { id: 'create-app' }, @@ -143,7 +143,7 @@ const SamlGoogleCreateAppStep = (): JSX.Element => { ); }; -const GOOGLE_IDP_MODES = ['metadataFile', 'manual'] as const satisfies readonly IdpConfigurationMode[]; +const GOOGLE_IDP_MODES = ['metadataFile', 'manual'] as const satisfies readonly SamlIdpConfigurationMode[]; const SamlGoogleIdentityProviderMetadataStep = (): JSX.Element => { const card = useCardState(); @@ -160,7 +160,7 @@ const SamlGoogleIdentityProviderMetadataStep = (): JSX.Element => { const existingCertPresent = Boolean(samlConnection?.idpCertificate); const existingMetadataPresent = Boolean(samlConnection?.idpMetadata); - const [mode, setMode] = React.useState(hasExistingManualConfig ? 'manual' : 'metadataFile'); + const [mode, setMode] = React.useState(hasExistingManualConfig ? 'manual' : 'metadataFile'); const [metadataFile, setMetadataFile] = React.useState(null); const [certFile, setCertFile] = React.useState(null); // Step-LOCAL submit state for the Continue button. `goNext` bubbles to the diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlMicrosoftConfigureSteps.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlMicrosoftConfigureSteps.tsx index b9b27e58ce1..c7c937028dd 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlMicrosoftConfigureSteps.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlMicrosoftConfigureSteps.tsx @@ -33,16 +33,16 @@ import { useConfigureSSO } from '../../../ConfigureSSOContext'; import { Step } from '../../../elements/Step'; import { useWizard, Wizard, type WizardStepConfig } from '../../../elements/Wizard'; import { InnerStepCounter } from '../../../elements/Wizard/InnerStepCounter'; +import { + IdentityProviderConfigurationModes, + type SamlIdpConfigurationMode, +} from '../shared/IdentityProviderConfigurationModes'; import { applySamlSubmitError, buildSamlConfigurationPayload, IdentityProviderConfigurationForm, type IdentityProviderConfigurationFormProps, } from './shared/IdentityProviderConfigurationForm'; -import { - IdentityProviderConfigurationModes, - type IdpConfigurationMode, -} from './shared/IdentityProviderConfigurationModes'; const MICROSOFT_STEPS: WizardStepConfig[] = [ { id: 'create-app' }, @@ -636,7 +636,7 @@ const SamlMicrosoftAttributeMappingStep = (): JSX.Element => { ); }; -const MICROSOFT_SAML_IDP_MODES = ['metadataUrl', 'manual'] as const satisfies readonly IdpConfigurationMode[]; +const MICROSOFT_SAML_IDP_MODES = ['metadataUrl', 'manual'] as const satisfies readonly SamlIdpConfigurationMode[]; const SamlMicrosoftIdentityProviderMetadataStep = (): JSX.Element => { const card = useCardState(); @@ -655,7 +655,7 @@ const SamlMicrosoftIdentityProviderMetadataStep = (): JSX.Element => { ); const existingCertPresent = Boolean(samlConnection?.idpCertificate); - const [mode, setMode] = React.useState(hasExistingConfig ? 'manual' : 'metadataUrl'); + const [mode, setMode] = React.useState(hasExistingConfig ? 'manual' : 'metadataUrl'); const [certFile, setCertFile] = React.useState(null); const [isSubmitting, setIsSubmitting] = React.useState(false); diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlOktaConfigureSteps.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlOktaConfigureSteps.tsx index 812c357e1b1..ac4e0739ee4 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlOktaConfigureSteps.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/SamlOktaConfigureSteps.tsx @@ -25,16 +25,16 @@ import { useConfigureSSO } from '../../../ConfigureSSOContext'; import { Step } from '../../../elements/Step'; import { useWizard, Wizard, type WizardStepConfig } from '../../../elements/Wizard'; import { InnerStepCounter } from '../../../elements/Wizard/InnerStepCounter'; +import { + IdentityProviderConfigurationModes, + type SamlIdpConfigurationMode, +} from '../shared/IdentityProviderConfigurationModes'; import { applySamlSubmitError, buildSamlConfigurationPayload, IdentityProviderConfigurationForm, type IdentityProviderConfigurationFormProps, } from './shared/IdentityProviderConfigurationForm'; -import { - IdentityProviderConfigurationModes, - type IdpConfigurationMode, -} from './shared/IdentityProviderConfigurationModes'; const OKTA_STEPS: WizardStepConfig[] = [ { id: 'create-app' }, @@ -494,7 +494,7 @@ const SamlOktaAssignUsersStep = (): JSX.Element => { ); }; -const OKTA_IDP_MODES = ['metadataUrl', 'manual'] as const satisfies readonly IdpConfigurationMode[]; +const OKTA_IDP_MODES = ['metadataUrl', 'manual'] as const satisfies readonly SamlIdpConfigurationMode[]; const SamlOktaIdentityProviderMetadataStep = (): JSX.Element => { const card = useCardState(); @@ -513,7 +513,7 @@ const SamlOktaIdentityProviderMetadataStep = (): JSX.Element => { ); const existingCertPresent = Boolean(samlConnection?.idpCertificate); - const [mode, setMode] = React.useState(hasExistingConfig ? 'manual' : 'metadataUrl'); + const [mode, setMode] = React.useState(hasExistingConfig ? 'manual' : 'metadataUrl'); const [certFile, setCertFile] = React.useState(null); // Step-LOCAL submit state for the Continue button. `goNext` bubbles to the // parent (this is the terminal nested step) and the parent DEFERS the diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/shared/IdentityProviderConfigurationForm.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/shared/IdentityProviderConfigurationForm.tsx index ed8ac096250..14fad7e2586 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/shared/IdentityProviderConfigurationForm.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/shared/IdentityProviderConfigurationForm.tsx @@ -21,8 +21,8 @@ import { ArrowUpTray, Close } from '@/icons'; import type { FormControlState } from '@/ui/utils/useFormControl'; import { handleError } from '@/utils/errorHandler'; -import { ActiveConnectionAlert } from './ActiveConnectionAlert'; -import type { IdpConfigurationMode } from './IdentityProviderConfigurationModes'; +import { ActiveConnectionAlert } from '../../shared/ActiveConnectionAlert'; +import type { SamlIdpConfigurationMode } from '../../shared/IdentityProviderConfigurationModes'; type CardState = ReturnType; type FormControl = FormControlState; @@ -180,7 +180,7 @@ const ManualPanel = ({ form, labels }: ManualPanelProps): JSX.Element => ( ); type BuildSamlPayloadParams = { - mode: IdpConfigurationMode; + mode: SamlIdpConfigurationMode; metadataUrl?: { value: string }; metadataFile?: { file: File | null }; manual?: { diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/shared/IdentityProviderConfigurationModes.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/shared/IdentityProviderConfigurationModes.tsx deleted file mode 100644 index 1b75ea36aee..00000000000 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/shared/IdentityProviderConfigurationModes.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { type JSX } from 'react'; - -import { type LocalizationKey, useLocalizations } from '@/customizables'; -import { SegmentedControl } from '@/elements/SegmentedControl'; - -/** - * The possible modes for the identity provider configuration - * - * metadataUrl: Fetch IdP configuration via metadata URL - * metadataFile: Upload IdP configuration via metadata file - * manual: Configure manually each field, such as sign on URL, issuer, and signing certificate - */ -export type IdpConfigurationMode = 'metadataUrl' | 'metadataFile' | 'manual'; - -type ModeLocalizationKeys = Partial>; - -type IdentityProviderConfigurationModesProps = { - modes: readonly IdpConfigurationMode[]; - value: IdpConfigurationMode; - onChange: (mode: IdpConfigurationMode) => void; - labels: { - ariaLabel: LocalizationKey; - } & ModeLocalizationKeys; -}; - -export const IdentityProviderConfigurationModes = ({ - modes, - value, - onChange, - labels, -}: IdentityProviderConfigurationModesProps): JSX.Element => { - const { t } = useLocalizations(); - - return ( - onChange(next as IdpConfigurationMode)} - fullWidth - size='lg' - > - {modes.map(mode => { - const label = labels[mode]; - if (!label) { - return null; - } - - return ( - - ); - })} - - ); -}; diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/shared/ActiveConnectionAlert.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/shared/ActiveConnectionAlert.tsx similarity index 91% rename from packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/shared/ActiveConnectionAlert.tsx rename to packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/shared/ActiveConnectionAlert.tsx index 36fd518e72b..281cc069a5b 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/saml/shared/ActiveConnectionAlert.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/shared/ActiveConnectionAlert.tsx @@ -3,7 +3,7 @@ import React, { type JSX } from 'react'; import { localizationKeys } from '@/customizables'; import { Alert } from '@/elements/Alert'; -import { useConfigureSSO } from '../../../../ConfigureSSOContext'; +import { useConfigureSSO } from '../../../ConfigureSSOContext'; export const ActiveConnectionAlert = (): JSX.Element | null => { const { enterpriseConnection } = useConfigureSSO(); diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/shared/IdentityProviderConfigurationModes.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/shared/IdentityProviderConfigurationModes.tsx new file mode 100644 index 00000000000..f472cb0bf7d --- /dev/null +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/shared/IdentityProviderConfigurationModes.tsx @@ -0,0 +1,50 @@ +import { type JSX } from 'react'; + +import { type LocalizationKey, useLocalizations } from '@/customizables'; +import { SegmentedControl } from '@/elements/SegmentedControl'; + +export type SamlIdpConfigurationMode = 'metadataUrl' | 'metadataFile' | 'manual'; +export type OidcIdpConfigurationMode = 'discoveryUrl' | 'manual'; + +type IdentityProviderConfigurationModesProps = { + modes: readonly Mode[]; + value: Mode; + onChange: (mode: Mode) => void; + labels: { + ariaLabel: LocalizationKey; + } & Partial>; +}; + +export const IdentityProviderConfigurationModes = ({ + modes, + value, + onChange, + labels, +}: IdentityProviderConfigurationModesProps): JSX.Element => { + const { t } = useLocalizations(); + + return ( + onChange(next as Mode)} + fullWidth + size='lg' + > + {modes.map(mode => { + const label = labels[mode]; + if (!label) { + return null; + } + + return ( + + ); + })} + + ); +}; diff --git a/packages/ui/src/components/ConfigureSSO/types.ts b/packages/ui/src/components/ConfigureSSO/types.ts index 6f502b168d9..57056616d18 100644 --- a/packages/ui/src/components/ConfigureSSO/types.ts +++ b/packages/ui/src/components/ConfigureSSO/types.ts @@ -1,6 +1,6 @@ export type SamlProviderType = 'saml_okta' | 'saml_custom' | 'saml_google' | 'saml_microsoft'; -export type OidcProviderType = `oidc_${string}`; +export type OidcProviderType = `oidc_${string}` | `oauth_custom_${string}`; export type ProviderType = SamlProviderType | 'oidc_custom'; From 1c66c8897d0e535be2cbbf925b90c5d339f65a52 Mon Sep 17 00:00:00 2001 From: Nicolas Lopes Date: Tue, 28 Jul 2026 14:25:44 -0300 Subject: [PATCH 4/8] generate localizations --- AGENTS.md | 17 ++++++++ packages/localizations/src/ar-SA.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/be-BY.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/bg-BG.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/bn-IN.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/ca-ES.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/cs-CZ.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/da-DK.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/de-DE.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/el-GR.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/en-GB.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/en-US.ts | 26 ++++++++---- packages/localizations/src/es-CR.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/es-ES.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/es-MX.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/es-UY.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/fa-IR.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/fi-FI.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/fr-FR.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/he-IL.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/hi-IN.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/hr-HR.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/hu-HU.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/id-ID.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/is-IS.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/it-IT.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/ja-JP.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/kk-KZ.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/ko-KR.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/mn-MN.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/ms-MY.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/nb-NO.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/nl-BE.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/nl-NL.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/pl-PL.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/pt-BR.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/pt-PT.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/ro-RO.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/ru-RU.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/sk-SK.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/sr-RS.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/sv-SE.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/ta-IN.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/te-IN.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/th-TH.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/tr-TR.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/uk-UA.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/vi-VN.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/zh-CN.ts | 64 +++++++++++++++++++++++++++-- packages/localizations/src/zh-TW.ts | 64 +++++++++++++++++++++++++++-- 50 files changed, 2962 insertions(+), 153 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 65565c4662b..6961534141a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,3 +17,20 @@ Clerk's JavaScript SDK and library monorepo. - For the Mosaic design system (tokens, CVA utility, `MosaicProvider`, migration from existing system), see `references/mosaic-architecture.md`. - For dev setup, testing, JSDoc/Typedoc, publishing, changesets, and commit conventions, see `docs/CONTRIBUTING.md`. - For working in the repo day to day (setup ordering and footguns, the package map, dev-loop recipes, and the breaking-change checklist), the `clerk-monorepo` Claude Code skill in `.claude/skills/clerk-monorepo/` restates these rules in actionable form. + + +# Memory Context + +# claude-mem status + +This project has no memory yet. The current session will seed it; subsequent sessions will receive auto-injected context for relevant past work. + +Memory injection starts on your second session in a project. + +`/learn-codebase` is available if the user wants to front-load the entire repo into memory in a single pass (~5 minutes on a typical repo, optional). Otherwise memory builds passively as work happens. + +Live activity: http://localhost:37701 +How it works: `/how-it-works` + +This message disappears once the first observation lands. + diff --git a/packages/localizations/src/ar-SA.ts b/packages/localizations/src/ar-SA.ts index b79bfe15668..40994083186 100644 --- a/packages/localizations/src/ar-SA.ts +++ b/packages/localizations/src/ar-SA.ts @@ -244,18 +244,76 @@ export const arSA: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/be-BY.ts b/packages/localizations/src/be-BY.ts index 24bc493f3e3..83232a15181 100644 --- a/packages/localizations/src/be-BY.ts +++ b/packages/localizations/src/be-BY.ts @@ -244,18 +244,76 @@ export const beBY: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/bg-BG.ts b/packages/localizations/src/bg-BG.ts index 5f3905bf064..d3ac2d80177 100644 --- a/packages/localizations/src/bg-BG.ts +++ b/packages/localizations/src/bg-BG.ts @@ -245,18 +245,76 @@ export const bgBG: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/bn-IN.ts b/packages/localizations/src/bn-IN.ts index 6b2caba5587..e4b855441f3 100644 --- a/packages/localizations/src/bn-IN.ts +++ b/packages/localizations/src/bn-IN.ts @@ -250,18 +250,76 @@ export const bnIN: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/ca-ES.ts b/packages/localizations/src/ca-ES.ts index 8e416297a5f..5609cfa4b72 100644 --- a/packages/localizations/src/ca-ES.ts +++ b/packages/localizations/src/ca-ES.ts @@ -251,18 +251,76 @@ export const caES: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/cs-CZ.ts b/packages/localizations/src/cs-CZ.ts index b8ca0577e47..4518dcb268d 100644 --- a/packages/localizations/src/cs-CZ.ts +++ b/packages/localizations/src/cs-CZ.ts @@ -248,18 +248,76 @@ export const csCZ: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/da-DK.ts b/packages/localizations/src/da-DK.ts index 1ea5ddf36fc..a0c308472a5 100644 --- a/packages/localizations/src/da-DK.ts +++ b/packages/localizations/src/da-DK.ts @@ -244,18 +244,76 @@ export const daDK: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/de-DE.ts b/packages/localizations/src/de-DE.ts index 40da7012f8a..748ec81cd65 100644 --- a/packages/localizations/src/de-DE.ts +++ b/packages/localizations/src/de-DE.ts @@ -250,18 +250,76 @@ export const deDE: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/el-GR.ts b/packages/localizations/src/el-GR.ts index 8e0fa3a106e..3605d6956b7 100644 --- a/packages/localizations/src/el-GR.ts +++ b/packages/localizations/src/el-GR.ts @@ -244,18 +244,76 @@ export const elGR: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/en-GB.ts b/packages/localizations/src/en-GB.ts index 8caf6ac27bc..65ae7776b4e 100644 --- a/packages/localizations/src/en-GB.ts +++ b/packages/localizations/src/en-GB.ts @@ -244,18 +244,76 @@ export const enGB: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts index 54590049b85..7e8450b354b 100644 --- a/packages/localizations/src/en-US.ts +++ b/packages/localizations/src/en-US.ts @@ -242,7 +242,6 @@ export const enUS: LocalizationResource = { }, oidcCustom: { credentialsStep: { - headerSubtitle: 'Add your application credentials', clientId: { label: 'Client ID', placeholder: 'Paste client ID here...', @@ -251,16 +250,17 @@ export const enUS: LocalizationResource = { label: 'Client secret', placeholder: 'Paste client secret here...', }, + headerSubtitle: 'Add your application credentials', paragraph: 'In your identity provider’s OIDC application, retrieve these values.', }, endpointsStep: { - headerSubtitle: 'Add your identity provider’s endpoints', discoveryUrl: { description: 'In your identity provider’s OIDC application, retrieve the discovery endpoint. Paste it below.', label: 'Discovery endpoint', placeholder: 'Paste URL here...', }, + headerSubtitle: 'Add your identity provider’s endpoints', manual: { authUrl: { label: 'Authorization URL', @@ -284,9 +284,6 @@ export const enUS: LocalizationResource = { }, mainHeaderTitle: 'Configure your identity provider', redirectUriStep: { - headerSubtitle: 'Create a new OIDC application in your identity provider’s dashboard', - paragraph: - 'In your identity provider’s dashboard, create a new OIDC application that supports the authorization code grant type, and use the following redirect URI:', claims: { description: 'Ensure your ID token includes the following claims:', table: { @@ -295,13 +292,24 @@ export const enUS: LocalizationResource = { claim: 'ID token claim', }, rows: { - email: { attribute: 'Primary email' }, - firstName: { attribute: 'First name' }, - lastName: { attribute: 'Last name' }, - subject: { attribute: 'External user ID' }, + email: { + attribute: 'Primary email', + }, + firstName: { + attribute: 'First name', + }, + lastName: { + attribute: 'Last name', + }, + subject: { + attribute: 'External user ID', + }, }, }, }, + headerSubtitle: 'Create a new OIDC application in your identity provider’s dashboard', + paragraph: + 'In your identity provider’s dashboard, create a new OIDC application that supports the authorization code grant type, and use the following redirect URI:', redirectUri: { label: 'Authorized redirect URI', }, diff --git a/packages/localizations/src/es-CR.ts b/packages/localizations/src/es-CR.ts index a44615e1a4f..763951e89ce 100644 --- a/packages/localizations/src/es-CR.ts +++ b/packages/localizations/src/es-CR.ts @@ -244,18 +244,76 @@ export const esCR: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/es-ES.ts b/packages/localizations/src/es-ES.ts index c0c701c2bbc..50145eb44c7 100644 --- a/packages/localizations/src/es-ES.ts +++ b/packages/localizations/src/es-ES.ts @@ -250,18 +250,76 @@ export const esES: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/es-MX.ts b/packages/localizations/src/es-MX.ts index a943bf56a8c..1bc4a32c7fd 100644 --- a/packages/localizations/src/es-MX.ts +++ b/packages/localizations/src/es-MX.ts @@ -245,18 +245,76 @@ export const esMX: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/es-UY.ts b/packages/localizations/src/es-UY.ts index a6ee8e356b1..e4a4f3cff3e 100644 --- a/packages/localizations/src/es-UY.ts +++ b/packages/localizations/src/es-UY.ts @@ -244,18 +244,76 @@ export const esUY: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/fa-IR.ts b/packages/localizations/src/fa-IR.ts index 4711f65643f..418bf489df2 100644 --- a/packages/localizations/src/fa-IR.ts +++ b/packages/localizations/src/fa-IR.ts @@ -249,18 +249,76 @@ export const faIR: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/fi-FI.ts b/packages/localizations/src/fi-FI.ts index b73fcdc988c..6c5e925e4ee 100644 --- a/packages/localizations/src/fi-FI.ts +++ b/packages/localizations/src/fi-FI.ts @@ -250,18 +250,76 @@ export const fiFI: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/fr-FR.ts b/packages/localizations/src/fr-FR.ts index 564a5f6e462..84777acd790 100644 --- a/packages/localizations/src/fr-FR.ts +++ b/packages/localizations/src/fr-FR.ts @@ -252,18 +252,76 @@ export const frFR: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/he-IL.ts b/packages/localizations/src/he-IL.ts index b38a5ae2284..c53bed8d69e 100644 --- a/packages/localizations/src/he-IL.ts +++ b/packages/localizations/src/he-IL.ts @@ -244,18 +244,76 @@ export const heIL: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/hi-IN.ts b/packages/localizations/src/hi-IN.ts index b619a6aa509..0d429f2d76d 100644 --- a/packages/localizations/src/hi-IN.ts +++ b/packages/localizations/src/hi-IN.ts @@ -250,18 +250,76 @@ export const hiIN: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/hr-HR.ts b/packages/localizations/src/hr-HR.ts index 1a8c444aa0d..57d138a1021 100644 --- a/packages/localizations/src/hr-HR.ts +++ b/packages/localizations/src/hr-HR.ts @@ -251,18 +251,76 @@ export const hrHR: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/hu-HU.ts b/packages/localizations/src/hu-HU.ts index a3a074a606f..4fbdcd278bf 100644 --- a/packages/localizations/src/hu-HU.ts +++ b/packages/localizations/src/hu-HU.ts @@ -251,18 +251,76 @@ export const huHU: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/id-ID.ts b/packages/localizations/src/id-ID.ts index fd8c8def650..e865afeb3b5 100644 --- a/packages/localizations/src/id-ID.ts +++ b/packages/localizations/src/id-ID.ts @@ -244,18 +244,76 @@ export const idID: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/is-IS.ts b/packages/localizations/src/is-IS.ts index 1e9dd8302a5..f6a9725bbb5 100644 --- a/packages/localizations/src/is-IS.ts +++ b/packages/localizations/src/is-IS.ts @@ -250,18 +250,76 @@ export const isIS: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/it-IT.ts b/packages/localizations/src/it-IT.ts index 87aeab24e61..33bb54cb212 100644 --- a/packages/localizations/src/it-IT.ts +++ b/packages/localizations/src/it-IT.ts @@ -250,18 +250,76 @@ export const itIT: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/ja-JP.ts b/packages/localizations/src/ja-JP.ts index 262f21f2040..79040d358be 100644 --- a/packages/localizations/src/ja-JP.ts +++ b/packages/localizations/src/ja-JP.ts @@ -251,18 +251,76 @@ export const jaJP: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/kk-KZ.ts b/packages/localizations/src/kk-KZ.ts index 353fb82db80..0d1ac09634a 100644 --- a/packages/localizations/src/kk-KZ.ts +++ b/packages/localizations/src/kk-KZ.ts @@ -244,18 +244,76 @@ export const kkKZ: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/ko-KR.ts b/packages/localizations/src/ko-KR.ts index f730bc8828e..c1abc4a3deb 100644 --- a/packages/localizations/src/ko-KR.ts +++ b/packages/localizations/src/ko-KR.ts @@ -248,18 +248,76 @@ export const koKR: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/mn-MN.ts b/packages/localizations/src/mn-MN.ts index 52422d0fca7..16af9e40f59 100644 --- a/packages/localizations/src/mn-MN.ts +++ b/packages/localizations/src/mn-MN.ts @@ -244,18 +244,76 @@ export const mnMN: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/ms-MY.ts b/packages/localizations/src/ms-MY.ts index d228acb96cb..a5080bba09c 100644 --- a/packages/localizations/src/ms-MY.ts +++ b/packages/localizations/src/ms-MY.ts @@ -252,18 +252,76 @@ export const msMY: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/nb-NO.ts b/packages/localizations/src/nb-NO.ts index 1726160601d..f6ca9bd2a0d 100644 --- a/packages/localizations/src/nb-NO.ts +++ b/packages/localizations/src/nb-NO.ts @@ -251,18 +251,76 @@ export const nbNO: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/nl-BE.ts b/packages/localizations/src/nl-BE.ts index f2e621d8026..679be3735fe 100644 --- a/packages/localizations/src/nl-BE.ts +++ b/packages/localizations/src/nl-BE.ts @@ -244,18 +244,76 @@ export const nlBE: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/nl-NL.ts b/packages/localizations/src/nl-NL.ts index 565683154e2..7475561c530 100644 --- a/packages/localizations/src/nl-NL.ts +++ b/packages/localizations/src/nl-NL.ts @@ -244,18 +244,76 @@ export const nlNL: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/pl-PL.ts b/packages/localizations/src/pl-PL.ts index a86733c59a3..c752dae2933 100644 --- a/packages/localizations/src/pl-PL.ts +++ b/packages/localizations/src/pl-PL.ts @@ -244,18 +244,76 @@ export const plPL: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/pt-BR.ts b/packages/localizations/src/pt-BR.ts index 4d74f16e6a5..ee6e3fb2846 100644 --- a/packages/localizations/src/pt-BR.ts +++ b/packages/localizations/src/pt-BR.ts @@ -250,18 +250,76 @@ export const ptBR: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/pt-PT.ts b/packages/localizations/src/pt-PT.ts index 2bad5eb9060..d0398db77a2 100644 --- a/packages/localizations/src/pt-PT.ts +++ b/packages/localizations/src/pt-PT.ts @@ -252,18 +252,76 @@ export const ptPT: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/ro-RO.ts b/packages/localizations/src/ro-RO.ts index 33ff5bcafc4..f04ca27fc6c 100644 --- a/packages/localizations/src/ro-RO.ts +++ b/packages/localizations/src/ro-RO.ts @@ -250,18 +250,76 @@ export const roRO: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/ru-RU.ts b/packages/localizations/src/ru-RU.ts index 3168dc05ccd..97005a6fbb0 100644 --- a/packages/localizations/src/ru-RU.ts +++ b/packages/localizations/src/ru-RU.ts @@ -244,18 +244,76 @@ export const ruRU: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/sk-SK.ts b/packages/localizations/src/sk-SK.ts index 7f939328335..36814980eca 100644 --- a/packages/localizations/src/sk-SK.ts +++ b/packages/localizations/src/sk-SK.ts @@ -244,18 +244,76 @@ export const skSK: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/sr-RS.ts b/packages/localizations/src/sr-RS.ts index 706147b76ae..c1b209b00f7 100644 --- a/packages/localizations/src/sr-RS.ts +++ b/packages/localizations/src/sr-RS.ts @@ -244,18 +244,76 @@ export const srRS: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/sv-SE.ts b/packages/localizations/src/sv-SE.ts index baffd2302e6..a94c14b64d4 100644 --- a/packages/localizations/src/sv-SE.ts +++ b/packages/localizations/src/sv-SE.ts @@ -244,18 +244,76 @@ export const svSE: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/ta-IN.ts b/packages/localizations/src/ta-IN.ts index 7d7987e28eb..e7025ec6989 100644 --- a/packages/localizations/src/ta-IN.ts +++ b/packages/localizations/src/ta-IN.ts @@ -252,18 +252,76 @@ export const taIN: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/te-IN.ts b/packages/localizations/src/te-IN.ts index 2eac09a960c..b7761190f76 100644 --- a/packages/localizations/src/te-IN.ts +++ b/packages/localizations/src/te-IN.ts @@ -251,18 +251,76 @@ export const teIN: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/th-TH.ts b/packages/localizations/src/th-TH.ts index 04e6540168e..d65b08fc356 100644 --- a/packages/localizations/src/th-TH.ts +++ b/packages/localizations/src/th-TH.ts @@ -248,18 +248,76 @@ export const thTH: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/tr-TR.ts b/packages/localizations/src/tr-TR.ts index e3b09b99df6..ad2223c7909 100644 --- a/packages/localizations/src/tr-TR.ts +++ b/packages/localizations/src/tr-TR.ts @@ -244,18 +244,76 @@ export const trTR: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/uk-UA.ts b/packages/localizations/src/uk-UA.ts index 0fb0fae6328..f9fd91af731 100644 --- a/packages/localizations/src/uk-UA.ts +++ b/packages/localizations/src/uk-UA.ts @@ -244,18 +244,76 @@ export const ukUA: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/vi-VN.ts b/packages/localizations/src/vi-VN.ts index 2240838d115..c21e80d0184 100644 --- a/packages/localizations/src/vi-VN.ts +++ b/packages/localizations/src/vi-VN.ts @@ -250,18 +250,76 @@ export const viVN: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/zh-CN.ts b/packages/localizations/src/zh-CN.ts index aa575d37cfc..5d02a382dd5 100644 --- a/packages/localizations/src/zh-CN.ts +++ b/packages/localizations/src/zh-CN.ts @@ -244,18 +244,76 @@ export const zhCN: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { diff --git a/packages/localizations/src/zh-TW.ts b/packages/localizations/src/zh-TW.ts index 8f841f9c64b..713b1080c45 100644 --- a/packages/localizations/src/zh-TW.ts +++ b/packages/localizations/src/zh-TW.ts @@ -247,18 +247,76 @@ export const zhTW: LocalizationResource = { }, }, oidcCustom: { - claimsStep: { - headerSubtitle: undefined, - }, credentialsStep: { + clientId: { + label: undefined, + placeholder: undefined, + }, + clientSecret: { + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + paragraph: undefined, }, endpointsStep: { + discoveryUrl: { + description: undefined, + label: undefined, + placeholder: undefined, + }, headerSubtitle: undefined, + manual: { + authUrl: { + label: undefined, + placeholder: undefined, + }, + description: undefined, + tokenUrl: { + label: undefined, + placeholder: undefined, + }, + userInfoUrl: { + label: undefined, + placeholder: undefined, + }, + }, + modes: { + ariaLabel: undefined, + discoveryUrl: undefined, + manual: undefined, + }, }, mainHeaderTitle: undefined, redirectUriStep: { + claims: { + description: undefined, + table: { + columns: { + attribute: undefined, + claim: undefined, + }, + rows: { + email: { + attribute: undefined, + }, + firstName: { + attribute: undefined, + }, + lastName: { + attribute: undefined, + }, + subject: { + attribute: undefined, + }, + }, + }, + }, headerSubtitle: undefined, + paragraph: undefined, + redirectUri: { + label: undefined, + }, }, }, samlCustom: { From e937f477c5a2952e9fbc2fd3b9d80903314d4035 Mon Sep 17 00:00:00 2001 From: Nicolas Lopes Date: Tue, 28 Jul 2026 14:41:00 -0300 Subject: [PATCH 5/8] fix(ui): address OIDC configuration review feedback --- .changeset/cool-dragons-march.md | 6 + .changeset/spotty-items-dream.md | 2 - AGENTS.md | 17 --- packages/shared/src/types/elementIds.ts | 3 - .../organizationEnterpriseConnection.test.ts | 48 ++++++- .../organizationEnterpriseConnection.ts | 5 +- .../__tests__/ConfigureStep.test.tsx | 126 ++++++++++++++++-- .../steps/ConfigureStep/index.tsx | 13 +- .../oidc/OidcCustomConfigureSteps.tsx | 1 + .../oidc/shared/OidcCredentialsStep.tsx | 4 +- .../shared/OidcEndpointsConfigurationForm.tsx | 51 +++---- .../oidc/shared/OidcEndpointsStep.tsx | 5 +- .../oidc/shared/OidcRedirectUriStep.tsx | 2 +- 13 files changed, 207 insertions(+), 76 deletions(-) delete mode 100644 .changeset/spotty-items-dream.md diff --git a/.changeset/cool-dragons-march.md b/.changeset/cool-dragons-march.md index a845151cc84..1927703947f 100644 --- a/.changeset/cool-dragons-march.md +++ b/.changeset/cool-dragons-march.md @@ -1,2 +1,8 @@ --- +"@clerk/clerk-js": patch +"@clerk/localizations": patch +"@clerk/shared": patch +"@clerk/ui": patch --- + +Add support for configuring custom OpenID Connect enterprise connections through the Organization Profile. diff --git a/.changeset/spotty-items-dream.md b/.changeset/spotty-items-dream.md deleted file mode 100644 index a845151cc84..00000000000 --- a/.changeset/spotty-items-dream.md +++ /dev/null @@ -1,2 +0,0 @@ ---- ---- diff --git a/AGENTS.md b/AGENTS.md index 6961534141a..65565c4662b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,20 +17,3 @@ Clerk's JavaScript SDK and library monorepo. - For the Mosaic design system (tokens, CVA utility, `MosaicProvider`, migration from existing system), see `references/mosaic-architecture.md`. - For dev setup, testing, JSDoc/Typedoc, publishing, changesets, and commit conventions, see `docs/CONTRIBUTING.md`. - For working in the repo day to day (setup ordering and footguns, the package map, dev-loop recipes, and the breaking-change checklist), the `clerk-monorepo` Claude Code skill in `.claude/skills/clerk-monorepo/` restates these rules in actionable form. - - -# Memory Context - -# claude-mem status - -This project has no memory yet. The current session will seed it; subsequent sessions will receive auto-injected context for relevant past work. - -Memory injection starts on your second session in a project. - -`/learn-codebase` is available if the user wants to front-load the entire repo into memory in a single pass (~5 minutes on a typical repo, optional). Otherwise memory builds passively as work happens. - -Live activity: http://localhost:37701 -How it works: `/how-it-works` - -This message disappears once the first observation lands. - diff --git a/packages/shared/src/types/elementIds.ts b/packages/shared/src/types/elementIds.ts index 32b62ccb70e..6975892a769 100644 --- a/packages/shared/src/types/elementIds.ts +++ b/packages/shared/src/types/elementIds.ts @@ -38,9 +38,6 @@ export type FieldId = | 'clientId' | 'clientSecret' | 'redirectUri' - | 'oidcClientId' - | 'oidcClientSecret' - | 'oidcRedirectUri' | 'acsUrl' | 'spEntityId' | 'web3WalletName' diff --git a/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts b/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts index 278a2d9fa0c..3b424285b7c 100644 --- a/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts +++ b/packages/ui/src/components/ConfigureSSO/domain/__tests__/organizationEnterpriseConnection.test.ts @@ -58,7 +58,10 @@ const fullyConfiguredSaml = makeSamlConnection({ idpMetadataUrl: 'https://idp.example.com/metadata', }); -const configuredOidc = makeOauthConfig({ clientId: 'client_abc' }); +const configuredOidc = makeOauthConfig({ + clientId: 'client_abc', + discoveryUrl: 'https://idp.example.com/.well-known/openid-configuration', +}); const makeOidcConnection = (overrides: Partial = {}): EnterpriseConnectionResource => makeConnection({ provider: 'oauth_custom_acme', samlConnection: null, oauthConfig: configuredOidc, ...overrides }); @@ -141,9 +144,28 @@ describe('organizationEnterpriseConnection', () => { }).hasMinimumConfiguration, ).toBe(false); }); - it('oidc client id present → true', () => { + it('oidc client id and discovery URL present → true', () => { expect(derive({ connection: makeOidcConnection() }).hasMinimumConfiguration).toBe(true); }); + it('oidc client id without endpoints → false', () => { + expect( + derive({ connection: makeOidcConnection({ oauthConfig: makeOauthConfig({ clientId: 'client_abc' }) }) }) + .hasMinimumConfiguration, + ).toBe(false); + }); + it('oidc client id with manual authorization and token URLs → true', () => { + expect( + derive({ + connection: makeOidcConnection({ + oauthConfig: makeOauthConfig({ + clientId: 'client_abc', + authUrl: 'https://idp.example.com/authorize', + tokenUrl: 'https://idp.example.com/token', + }), + }), + }).hasMinimumConfiguration, + ).toBe(true); + }); it('oidc without oauth config → false', () => { expect(derive({ connection: makeOidcConnection({ oauthConfig: null }) }).hasMinimumConfiguration).toBe(false); }); @@ -294,9 +316,29 @@ describe('isEnterpriseConnectionConfigured', () => { it('oidc with empty client id → false', () => { expect(isEnterpriseConnectionConfigured(makeOidcConnection({ oauthConfig: makeOauthConfig() }))).toBe(false); }); - it('oidc with client id present → true', () => { + it('oidc with client id and discovery URL present → true', () => { expect(isEnterpriseConnectionConfigured(makeOidcConnection())).toBe(true); }); + it('oidc with client id but no endpoints → false', () => { + expect( + isEnterpriseConnectionConfigured( + makeOidcConnection({ oauthConfig: makeOauthConfig({ clientId: 'client_abc' }) }), + ), + ).toBe(false); + }); + it('oidc with client id and manual authorization and token URLs → true', () => { + expect( + isEnterpriseConnectionConfigured( + makeOidcConnection({ + oauthConfig: makeOauthConfig({ + clientId: 'client_abc', + authUrl: 'https://idp.example.com/authorize', + tokenUrl: 'https://idp.example.com/token', + }), + }), + ), + ).toBe(true); + }); it('branches on provider: an oidc connection is not satisfied by saml fields', () => { expect( isEnterpriseConnectionConfigured( diff --git a/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts b/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts index eb6937f63ed..fa4baeb775f 100644 --- a/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts +++ b/packages/ui/src/components/ConfigureSSO/domain/organizationEnterpriseConnection.ts @@ -58,7 +58,10 @@ export const isEnterpriseConnectionConfigured = ( return false; } if (isOidcProvider(connection.provider)) { - return Boolean(connection.oauthConfig?.clientId); + const oauthConfig = connection.oauthConfig; + return Boolean( + oauthConfig?.clientId && (oauthConfig.discoveryUrl || (oauthConfig.authUrl && oauthConfig.tokenUrl)), + ); } return Boolean(connection.samlConnection?.idpSsoUrl && connection.samlConnection?.idpEntityId); }; diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx index c0d83f54193..b27d2bd1d1c 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx @@ -1,9 +1,10 @@ +import { ClerkAPIResponseError } from '@clerk/shared/error'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { Flow } from '@/customizables'; import { bindCreateFixtures } from '@/test/create-fixtures'; import { render, screen } from '@/test/utils'; -import { CardStateProvider } from '@/ui/elements/contexts'; +import { CardStateProvider, useCardState } from '@/ui/elements/contexts'; import type { EnterpriseConnectionProviderType } from '../../../types'; @@ -12,6 +13,7 @@ import type { EnterpriseConnectionProviderType } from '../../../types'; // left undefined so that footer self-hides in this isolated render. const contextState = vi.hoisted(() => ({ provider: undefined as string | undefined, + isOIDCFlowEnabled: true, enterpriseConnection: undefined as | { id: string; @@ -27,6 +29,12 @@ const contextState = vi.hoisted(() => ({ })); const updateConnection = vi.hoisted(() => vi.fn()); +const CardErrorProbe = () => { + const { error } = useCardState(); + + return error ?
{error}
: null; +}; + vi.mock('../../../ConfigureSSOContext', () => ({ useConfigureSSO: () => ({ enterpriseConnection: contextState.enterpriseConnection, @@ -36,6 +44,7 @@ vi.mock('../../../ConfigureSSOContext', () => ({ provider: contextState.provider, hasConnection: true, }, + isOIDCFlowEnabled: contextState.isOIDCFlowEnabled, }), })); @@ -52,28 +61,34 @@ const { createFixtures } = bindCreateFixtures('ConfigureSSO'); describe('resolveConfigureSteps', () => { it('dispatches custom and legacy OIDC provider keys to the OIDC sub-flow', () => { - expect(resolveConfigureSteps('oauth_custom_clerk_dev')).toBe(OidcCustomConfigureSteps); - expect(resolveConfigureSteps('oidc_clerk_dev')).toBe(OidcCustomConfigureSteps); - expect(resolveConfigureSteps('oidc_ghe_acme')).toBe(OidcCustomConfigureSteps); - expect(resolveConfigureSteps('oidc_gitlab_ent_acme')).toBe(OidcCustomConfigureSteps); - expect(resolveConfigureSteps('oidc_custom')).toBe(OidcCustomConfigureSteps); + expect(resolveConfigureSteps('oauth_custom_clerk_dev', true)).toBe(OidcCustomConfigureSteps); + expect(resolveConfigureSteps('oidc_clerk_dev', true)).toBe(OidcCustomConfigureSteps); + expect(resolveConfigureSteps('oidc_ghe_acme', true)).toBe(OidcCustomConfigureSteps); + expect(resolveConfigureSteps('oidc_gitlab_ent_acme', true)).toBe(OidcCustomConfigureSteps); + expect(resolveConfigureSteps('oidc_custom', true)).toBe(OidcCustomConfigureSteps); + }); + + it('does not dispatch OIDC providers while the experimental flow is disabled', () => { + expect(resolveConfigureSteps('oauth_custom_clerk_dev', false)).toBeUndefined(); + expect(resolveConfigureSteps('oidc_clerk_dev', false)).toBeUndefined(); }); it('dispatches SAML providers by exact literal', () => { - expect(resolveConfigureSteps('saml_okta')).toBe(SamlOktaConfigureSteps); - expect(resolveConfigureSteps('saml_custom')).toBe(SamlCustomConfigureSteps); - expect(resolveConfigureSteps('saml_google')).toBe(SamlGoogleConfigureSteps); - expect(resolveConfigureSteps('saml_microsoft')).toBe(SamlMicrosoftConfigureSteps); + expect(resolveConfigureSteps('saml_okta', false)).toBe(SamlOktaConfigureSteps); + expect(resolveConfigureSteps('saml_custom', false)).toBe(SamlCustomConfigureSteps); + expect(resolveConfigureSteps('saml_google', false)).toBe(SamlGoogleConfigureSteps); + expect(resolveConfigureSteps('saml_microsoft', false)).toBe(SamlMicrosoftConfigureSteps); }); it('returns undefined for an unrecognized provider so the caller can degrade', () => { - expect(resolveConfigureSteps('ldap_enterprise' as EnterpriseConnectionProviderType)).toBeUndefined(); + expect(resolveConfigureSteps('ldap_enterprise' as EnterpriseConnectionProviderType, true)).toBeUndefined(); }); }); describe('ConfigureProviderStep', () => { beforeEach(() => { contextState.provider = undefined; + contextState.isOIDCFlowEnabled = true; contextState.enterpriseConnection = undefined; updateConnection.mockReset(); }); @@ -83,6 +98,7 @@ describe('ConfigureProviderStep', () => { + , { wrapper }, @@ -211,6 +227,36 @@ describe('ConfigureProviderStep', () => { }); }); + it('clears endpoint API errors when switching configuration modes', async () => { + contextState.provider = 'oidc_clerk_dev'; + contextState.enterpriseConnection = { id: 'ent_123', oauthConfig: null }; + updateConnection.mockRejectedValueOnce( + new ClerkAPIResponseError('Error', { + data: [ + { + code: 'form_param_invalid', + long_message: 'The endpoint configuration is invalid.', + message: 'The endpoint configuration is invalid.', + }, + ], + status: 422, + }), + ); + const { wrapper } = await createFixtures(); + + const { userEvent } = renderStep(wrapper); + + await userEvent.click(await screen.findByRole('button', { name: 'Continue' })); + await userEvent.type(screen.getByRole('textbox', { name: 'Discovery endpoint' }), 'https://idp.example/discovery'); + await userEvent.click(screen.getByRole('button', { name: 'Continue' })); + + expect(await screen.findByText('The endpoint configuration is invalid.')).toBeInTheDocument(); + + await userEvent.click(screen.getByRole('radio', { name: 'Configure manually' })); + + expect(screen.queryByText('The endpoint configuration is invalid.')).not.toBeInTheDocument(); + }); + it('saves credentials before advancing', async () => { contextState.provider = 'oidc_clerk_dev'; contextState.enterpriseConnection = { id: 'ent_123', oauthConfig: null }; @@ -241,6 +287,53 @@ describe('ConfigureProviderStep', () => { }); }); + it('displays credential API errors on their matching fields', async () => { + contextState.provider = 'oidc_clerk_dev'; + contextState.enterpriseConnection = { id: 'ent_123', oauthConfig: null }; + updateConnection.mockReset(); + updateConnection.mockResolvedValueOnce({}); + updateConnection.mockRejectedValueOnce( + new ClerkAPIResponseError('Error', { + data: [ + { + code: 'form_param_invalid', + long_message: 'Client ID is invalid.', + message: 'Client ID is invalid.', + meta: { param_name: 'client_id' }, + }, + { + code: 'form_param_invalid', + long_message: 'Client secret is invalid.', + message: 'Client secret is invalid.', + meta: { param_name: 'client_secret' }, + }, + ], + status: 422, + }), + ); + const { wrapper } = await createFixtures(); + + const { userEvent } = renderStep(wrapper); + + await userEvent.click(await screen.findByRole('button', { name: 'Continue' })); + await userEvent.type( + screen.getByRole('textbox', { name: 'Discovery endpoint' }), + 'https://idp.example/.well-known/openid-configuration', + ); + await userEvent.click(screen.getByRole('button', { name: 'Continue' })); + + const clientId = await screen.findByRole('textbox', { name: 'Client ID' }); + const clientSecret = screen.getByLabelText('Client secret'); + await userEvent.type(clientId, 'client_123'); + await userEvent.type(clientSecret, 'secret_456'); + await userEvent.click(screen.getByRole('button', { name: 'Continue' })); + + expect(await screen.findByText('Client ID is invalid.')).toBeInTheDocument(); + expect(await screen.findByText('Client secret is invalid.')).toBeInTheDocument(); + expect(clientId).toHaveAttribute('aria-describedby', 'error-clientId'); + expect(clientSecret).toHaveAttribute('aria-describedby', 'error-clientSecret'); + }); + it('selects manual mode when an existing connection has manual endpoints without a discovery URL', async () => { contextState.provider = 'oidc_clerk_dev'; contextState.enterpriseConnection = { @@ -324,4 +417,15 @@ describe('ConfigureProviderStep', () => { expect(await screen.findByText(/unsupported provider/i)).toBeInTheDocument(); }); + + it('degrades to the unsupported-provider state for an existing OIDC connection when the flag is off', async () => { + contextState.provider = 'oauth_custom_clerk_dev'; + contextState.isOIDCFlowEnabled = false; + const { wrapper } = await createFixtures(); + + renderStep(wrapper); + + expect(await screen.findByText(/unsupported provider/i)).toBeInTheDocument(); + expect(screen.queryByText(/create a new oidc application/i)).not.toBeInTheDocument(); + }); }); diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx index c687f4c7d3b..6abf3e61005 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/index.tsx @@ -28,8 +28,13 @@ const STEPS_BY_SAML_PROVIDER: Record export const resolveConfigureSteps = ( provider: EnterpriseConnectionProviderType, -): ConfigureStepsComponent | undefined => - isOidcProvider(provider) ? OidcCustomConfigureSteps : STEPS_BY_SAML_PROVIDER[provider]; + isOIDCFlowEnabled: boolean, +): ConfigureStepsComponent | undefined => { + if (isOidcProvider(provider)) { + return isOIDCFlowEnabled ? OidcCustomConfigureSteps : undefined; + } + return STEPS_BY_SAML_PROVIDER[provider]; +}; export const ConfigureStep = (): JSX.Element => { const { organizationEnterpriseConnection: c } = useConfigureSSO(); @@ -63,13 +68,13 @@ export const ConfigureStep = (): JSX.Element => { }; export const ConfigureProviderStep = (): JSX.Element | null => { - const { organizationEnterpriseConnection: c } = useConfigureSSO(); + const { organizationEnterpriseConnection: c, isOIDCFlowEnabled } = useConfigureSSO(); if (!c.provider) { return null; } - const ConfigureSteps = resolveConfigureSteps(c.provider); + const ConfigureSteps = resolveConfigureSteps(c.provider, isOIDCFlowEnabled); return ( diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx index b7c27de5168..f0951323f54 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx @@ -12,6 +12,7 @@ const OIDC_STEPS: WizardStepConfig[] = [{ id: 'redirect-uri' }, { id: 'endpoints export const OidcCustomConfigureSteps = (): JSX.Element => { const { enterpriseConnection } = useConfigureSSO(); const oauthConfig = enterpriseConnection?.oauthConfig; + // Keep mode outside the step so it persists across wizard navigation. const [endpointMode, setEndpointMode] = useState( oauthConfig?.authUrl && !oauthConfig.discoveryUrl ? 'manual' : 'discoveryUrl', ); diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcCredentialsStep.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcCredentialsStep.tsx index ed736081cfe..c8ecb821854 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcCredentialsStep.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcCredentialsStep.tsx @@ -19,13 +19,13 @@ export const OidcCredentialsStep = (): JSX.Element => { enterpriseConnection, enterpriseConnectionMutations: { updateConnection }, } = useConfigureSSO(); - const clientIdField = useFormControl('oidcClientId', enterpriseConnection?.oauthConfig?.clientId ?? '', { + const clientIdField = useFormControl('clientId', enterpriseConnection?.oauthConfig?.clientId ?? '', { type: 'text', label: localizationKeys('configureSSO.configureStep.oidcCustom.credentialsStep.clientId.label'), placeholder: localizationKeys('configureSSO.configureStep.oidcCustom.credentialsStep.clientId.placeholder'), isRequired: true, }); - const clientSecretField = useFormControl('oidcClientSecret', '', { + const clientSecretField = useFormControl('clientSecret', '', { type: 'password', label: localizationKeys('configureSSO.configureStep.oidcCustom.credentialsStep.clientSecret.label'), placeholder: localizationKeys('configureSSO.configureStep.oidcCustom.credentialsStep.clientSecret.placeholder'), diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsConfigurationForm.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsConfigurationForm.tsx index ff6016fcead..bb8b0fe11ea 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsConfigurationForm.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsConfigurationForm.tsx @@ -11,7 +11,7 @@ type DiscoveryUrlForm = { discoveryUrlField: FormControl; }; -type DiscoveryUrlLabels = { +type EndpointLabels = { description: LocalizationKey; }; @@ -21,30 +21,11 @@ type ManualEndpointsForm = { userInfoUrlField: FormControl; }; -type ManualEndpointsLabels = { - description: LocalizationKey; -}; - export type OidcEndpointsConfigurationFormProps = - | { mode: 'discoveryUrl'; form: DiscoveryUrlForm; labels: DiscoveryUrlLabels } - | { mode: 'manual'; form: ManualEndpointsForm; labels: ManualEndpointsLabels }; + | { mode: 'discoveryUrl'; form: DiscoveryUrlForm; labels: EndpointLabels } + | { mode: 'manual'; form: ManualEndpointsForm; labels: EndpointLabels }; export const OidcEndpointsConfigurationForm = (props: OidcEndpointsConfigurationFormProps): JSX.Element => { - if (props.mode === 'discoveryUrl') { - return ( - <> - - - - - - ); - } - return ( <> - - - - - - - - - + {props.mode === 'discoveryUrl' ? ( + + + + ) : ( + <> + + + + + + + + + + + )} ); }; diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsStep.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsStep.tsx index cfc98ba99e1..20c29103f3a 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsStep.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcEndpointsStep.tsx @@ -135,7 +135,10 @@ export const OidcEndpointsStep = ({ mode, onModeChange }: OidcEndpointsStepProps { + card.setError(undefined); + onModeChange(nextMode); + }} labels={{ ariaLabel: localizationKeys('configureSSO.configureStep.oidcCustom.endpointsStep.modes.ariaLabel'), discoveryUrl: localizationKeys('configureSSO.configureStep.oidcCustom.endpointsStep.modes.discoveryUrl'), diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcRedirectUriStep.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcRedirectUriStep.tsx index 36abd73b105..26230ed8131 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcRedirectUriStep.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcRedirectUriStep.tsx @@ -112,7 +112,7 @@ export const OidcRedirectUriStep = (): JSX.Element => { const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); const { enterpriseConnection } = useConfigureSSO(); const redirectUri = enterpriseConnection?.oauthConfig?.redirectUri ?? ''; - const redirectUriField = useFormControl('oidcRedirectUri', redirectUri, { + const redirectUriField = useFormControl('redirectUri', redirectUri, { type: 'text', label: localizationKeys('configureSSO.configureStep.oidcCustom.redirectUriStep.redirectUri.label'), isRequired: false, From 0ba29704fe1eb4b6872ed1b135ef812b8dd765ae Mon Sep 17 00:00:00 2001 From: Nicolas Lopes Date: Tue, 28 Jul 2026 15:19:44 -0300 Subject: [PATCH 6/8] fix(ui): preserve OIDC user info URL --- .../__tests__/ConfigureStep.test.tsx | 38 +++++++++++++++++++ .../oidc/OidcCustomConfigureSteps.tsx | 2 +- .../oidc/shared/OidcCredentialsStep.tsx | 18 ++++++++- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx index b27d2bd1d1c..b683d228e01 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx @@ -287,6 +287,44 @@ describe('ConfigureProviderStep', () => { }); }); + it('preserves manual endpoints while saving credentials', async () => { + contextState.provider = 'oidc_clerk_dev'; + contextState.enterpriseConnection = { + id: 'ent_123', + oauthConfig: { + authUrl: 'https://idp.example/authorize', + tokenUrl: 'https://idp.example/token', + userInfoUrl: 'https://idp.example/userinfo', + }, + }; + updateConnection.mockReset(); + updateConnection.mockResolvedValue({}); + const { wrapper } = await createFixtures(); + + const { userEvent } = renderStep(wrapper); + + await userEvent.click(await screen.findByRole('button', { name: 'Continue' })); + await userEvent.click(screen.getByRole('button', { name: 'Continue' })); + + const clientId = await screen.findByRole('textbox', { name: 'Client ID' }); + const clientSecret = screen.getByLabelText('Client secret'); + await userEvent.type(clientId, 'client_123'); + await userEvent.type(clientSecret, 'secret_456'); + await userEvent.click(screen.getByRole('button', { name: 'Continue' })); + + await vi.waitFor(() => { + expect(updateConnection).toHaveBeenLastCalledWith('ent_123', { + oidc: { + clientId: 'client_123', + clientSecret: 'secret_456', + authUrl: 'https://idp.example/authorize', + tokenUrl: 'https://idp.example/token', + userInfoUrl: 'https://idp.example/userinfo', + }, + }); + }); + }); + it('displays credential API errors on their matching fields', async () => { contextState.provider = 'oidc_clerk_dev'; contextState.enterpriseConnection = { id: 'ent_123', oauthConfig: null }; diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx index f0951323f54..1e07e27f6ad 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/OidcCustomConfigureSteps.tsx @@ -34,7 +34,7 @@ export const OidcCustomConfigureSteps = (): JSX.Element => { - +
); diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcCredentialsStep.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcCredentialsStep.tsx index c8ecb821854..27aa765ed7e 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcCredentialsStep.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/oidc/shared/OidcCredentialsStep.tsx @@ -11,15 +11,21 @@ import { Step } from '../../../../elements/Step'; import { useWizard } from '../../../../elements/Wizard'; import { InnerStepCounter } from '../../../../elements/Wizard/InnerStepCounter'; import { ActiveConnectionAlert } from '../../shared/ActiveConnectionAlert'; +import type { OidcIdpConfigurationMode } from '../../shared/IdentityProviderConfigurationModes'; -export const OidcCredentialsStep = (): JSX.Element => { +interface OidcCredentialsStepProps { + mode: OidcIdpConfigurationMode; +} + +export const OidcCredentialsStep = ({ mode }: OidcCredentialsStepProps): JSX.Element => { const card = useCardState(); const { goNext, goPrev, isFirstStep } = useWizard(); const { enterpriseConnection, enterpriseConnectionMutations: { updateConnection }, } = useConfigureSSO(); - const clientIdField = useFormControl('clientId', enterpriseConnection?.oauthConfig?.clientId ?? '', { + const oauthConfig = enterpriseConnection?.oauthConfig; + const clientIdField = useFormControl('clientId', oauthConfig?.clientId ?? '', { type: 'text', label: localizationKeys('configureSSO.configureStep.oidcCustom.credentialsStep.clientId.label'), placeholder: localizationKeys('configureSSO.configureStep.oidcCustom.credentialsStep.clientId.placeholder'), @@ -48,6 +54,14 @@ export const OidcCredentialsStep = (): JSX.Element => { oidc: { clientId: clientIdField.value.trim(), clientSecret: clientSecretField.value.trim(), + ...(mode === 'discoveryUrl' && oauthConfig?.discoveryUrl !== undefined + ? { discoveryUrl: oauthConfig.discoveryUrl } + : {}), + ...(mode === 'manual' && oauthConfig?.authUrl !== undefined ? { authUrl: oauthConfig.authUrl } : {}), + ...(mode === 'manual' && oauthConfig?.tokenUrl !== undefined ? { tokenUrl: oauthConfig.tokenUrl } : {}), + ...(mode === 'manual' && oauthConfig?.userInfoUrl !== undefined + ? { userInfoUrl: oauthConfig.userInfoUrl } + : {}), }, }); void goNext(); From c52dc1e3d3abd1cf397a75b8d0a66ccf1c52b419 Mon Sep 17 00:00:00 2001 From: Nicolas Lopes Date: Tue, 28 Jul 2026 15:35:52 -0300 Subject: [PATCH 7/8] test(ui): stabilize OIDC credential error coverage --- .../__tests__/ConfigureStep.test.tsx | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx index b683d228e01..13288278cd1 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx @@ -7,6 +7,7 @@ import { render, screen } from '@/test/utils'; import { CardStateProvider, useCardState } from '@/ui/elements/contexts'; import type { EnterpriseConnectionProviderType } from '../../../types'; +import { Wizard } from '../../../elements/Wizard'; // The dispatch reads `organizationEnterpriseConnection.provider`. The nested // sub-flows also read `enterpriseConnection` (via `Step.Footer.Reset`), which is @@ -50,6 +51,7 @@ vi.mock('../../../ConfigureSSOContext', () => ({ import { ConfigureProviderStep, resolveConfigureSteps } from '../index'; import { OidcCustomConfigureSteps } from '../oidc'; +import { OidcCredentialsStep } from '../oidc/shared/OidcCredentialsStep'; import { SamlCustomConfigureSteps, SamlGoogleConfigureSteps, @@ -104,6 +106,23 @@ describe('ConfigureProviderStep', () => { { wrapper }, ); + const renderCredentialsStep = (wrapper: React.ComponentType<{ children?: React.ReactNode }>) => + render( + + + + + + + + + , + { wrapper }, + ); + it('renders the OIDC configure steps for a custom OAuth provider key without throwing', async () => { contextState.provider = 'oauth_custom_clerk_dev'; contextState.enterpriseConnection = { @@ -329,8 +348,7 @@ describe('ConfigureProviderStep', () => { contextState.provider = 'oidc_clerk_dev'; contextState.enterpriseConnection = { id: 'ent_123', oauthConfig: null }; updateConnection.mockReset(); - updateConnection.mockResolvedValueOnce({}); - updateConnection.mockRejectedValueOnce( + updateConnection.mockRejectedValue( new ClerkAPIResponseError('Error', { data: [ { @@ -351,25 +369,21 @@ describe('ConfigureProviderStep', () => { ); const { wrapper } = await createFixtures(); - const { userEvent } = renderStep(wrapper); - - await userEvent.click(await screen.findByRole('button', { name: 'Continue' })); - await userEvent.type( - screen.getByRole('textbox', { name: 'Discovery endpoint' }), - 'https://idp.example/.well-known/openid-configuration', - ); - await userEvent.click(screen.getByRole('button', { name: 'Continue' })); + const { userEvent } = renderCredentialsStep(wrapper); - const clientId = await screen.findByRole('textbox', { name: 'Client ID' }); - const clientSecret = screen.getByLabelText('Client secret'); + const clientId = screen.getByRole('textbox'); + const clientSecret = document.querySelector('input[name="clientSecret"]'); + expect(clientSecret).not.toBeNull(); await userEvent.type(clientId, 'client_123'); - await userEvent.type(clientSecret, 'secret_456'); + await userEvent.type(clientSecret!, 'secret_456'); await userEvent.click(screen.getByRole('button', { name: 'Continue' })); - expect(await screen.findByText('Client ID is invalid.')).toBeInTheDocument(); - expect(await screen.findByText('Client secret is invalid.')).toBeInTheDocument(); - expect(clientId).toHaveAttribute('aria-describedby', 'error-clientId'); - expect(clientSecret).toHaveAttribute('aria-describedby', 'error-clientSecret'); + await vi.waitFor(() => { + expect(document.getElementById('error-clientId')).toHaveTextContent('Client ID is invalid.'); + expect(document.getElementById('error-clientSecret')).toHaveTextContent('Client secret is invalid.'); + expect(clientId).toHaveAttribute('aria-describedby', 'error-clientId'); + expect(clientSecret).toHaveAttribute('aria-describedby', 'error-clientSecret'); + }); }); it('selects manual mode when an existing connection has manual endpoints without a discovery URL', async () => { From 0ae71fba867c8628a9eb24c8777a63e2945fab7d Mon Sep 17 00:00:00 2001 From: Nicolas Lopes Date: Wed, 29 Jul 2026 11:22:36 -0300 Subject: [PATCH 8/8] chore(ui): sort imports in ConfigureStep test --- .../steps/ConfigureStep/__tests__/ConfigureStep.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx index 13288278cd1..f4511cc458e 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep/__tests__/ConfigureStep.test.tsx @@ -6,8 +6,8 @@ import { bindCreateFixtures } from '@/test/create-fixtures'; import { render, screen } from '@/test/utils'; import { CardStateProvider, useCardState } from '@/ui/elements/contexts'; -import type { EnterpriseConnectionProviderType } from '../../../types'; import { Wizard } from '../../../elements/Wizard'; +import type { EnterpriseConnectionProviderType } from '../../../types'; // The dispatch reads `organizationEnterpriseConnection.provider`. The nested // sub-flows also read `enterpriseConnection` (via `Step.Footer.Reset`), which is