Skip to content

feat(ui): add Configure manually path to ConfigureSSO submit-config sub-step#8553

Open
iagodahlem wants to merge 10 commits into
mainfrom
iago/orgs-1535-add-configure-manually-path
Open

feat(ui): add Configure manually path to ConfigureSSO submit-config sub-step#8553
iagodahlem wants to merge 10 commits into
mainfrom
iago/orgs-1535-add-configure-manually-path

Conversation

@iagodahlem
Copy link
Copy Markdown
Member

@iagodahlem iagodahlem commented May 14, 2026

Description

Adds the Configure manually path to the SAML config submission sub-step of <__experimental_ConfigureSSO />'s Configure step, and reshapes the sub-step so the per-mode bodies are isolated, the cert field routes errors inline, and Configure-again from the Confirmation step lands users on an editable, pre-populated form.

Segmented control + per-mode panels

The sub-step body now sits behind a two-mode SegmentedControl and the per-mode JSX is split into MetadataUrlPanel and ManualEntryPanel render components (internal to ConfigureStep.tsx). State stays lifted in SubmitSamlConfigSubStepuseFormControl hooks, cert file, mode, card state, mutation, Continue handler, and Step.Footer all live in the orchestrator. Panels receive their fields and cert state as props.

  1. Add via metadata (default for fresh setups) — single Metadata URL input. Continue posts { saml: { idpMetadataUrl } }.
  2. Configure manually — three fields:
    • Sign on URL — text input wired through a new idpSsoUrl FieldId.
    • Issuer — text input wired through a new idpEntityId FieldId.
    • Signing certificate — file picker behind a new idpCertificate FieldId. A hidden <input type="file" accept=".pem,.key,.crt,.cer,.cert"> is triggered by the visible Upload/Replace button. When a file is selected, the cert row swaps to a filename label plus a small remove button that clears the selection and resets the input value (so re-picking the same file refires the change). The accept list mirrors the Clerk Dashboard's existing SAML connection form.

Continue is gated to the selected mode's required fields. In manual mode, the handler reads the cert via File.text() and posts { saml: { idpSsoUrl, idpEntityId, idpCertificate } } through the same user.updateEnterpriseConnection call wrapped in useReverification.

Cert errors route inline

The cert field is a real useFormControl-backed field with its own FieldId. The cert section renders inside Field.Root / Field.LabelRow / Field.Label / Field.Feedback, matching the surrounding inputs. Backend errors keyed idp_certificate route inline below the cert UI via handleError([signOnUrlField, issuerField, certFileField], card.setError). Fresh interaction (file pick or remove) clears stale field-level feedback via clearFeedback(). The field's value stays empty — we only use the field for label rendering and error state, not value tracking.

Configure-again pre-fill

When the user lands on the Configure step with an existing enterpriseConnection.samlConnection (typically via goToStep('configure') from the Confirmation step's Configure again button), the form populates:

  • signOnUrlField and issuerField initialize from samlConnection.idpSsoUrl / idpEntityId.
  • The segmented control defaults to Configure manually when prior config exists, otherwise Add via metadata.
  • The cert row defaults to a Replace file button when samlConnection.idpCertificate is present. Continue stays enabled without requiring a fresh upload; the manual PATCH conditionally includes idpCertificate only when a new file was selected so the backend retains the existing cert on submit.
  • The Metadata URL field is intentionally not pre-filled — metadata submission is a one-shot flow and matches the Dashboard's posture of always starting fresh.

Locale keys

Live under configureSSO.configureStep.samlOkta:

  • modes.* for the segmented control labels and aria-label.
  • submitSamlConfig.title for the "Fill in your Okta SAML application details" section heading.
  • manual.* for the per-mode description, field labels, placeholders, and the Upload file / Replace file / Remove file copy.

Also tightens the metadata-mode tab label from "Add via metadata URL" to "Add via metadata" to match Figma.

Linear: ORGS-1535

Follow-ups (separate PR)

  • Custom SAML provider variant (ORGS-1536) — generic SAML instructional copy across all 4 Configure sub-steps, switching by connection.provider. The Custom SAML manual path will reuse the segmented control, panel split, cert field, and Continue handler shipped here.
  • Field validations — client-side URL format checks. Today the PR matches the Dashboard's "trust user, backend rejects" posture; only required-empty is enforced (via the canSubmit gate, no inline message).
  • Tests — unit coverage for the Configure step (mode switching, cert state lifecycle, Continue payloads per mode, error routing, Configure-again pre-fill, initial-step deriving) ships alongside the broader ConfigureSSO test pass after the Custom SAML PR lands.

How to test

Fresh setup

In a sandbox with the ConfigureSSO wizard, walk through Select Provider → Verify Domain → land on Configure. Advance through sub-steps 1–3, then on the SAML config sub-step:

  • Add via metadata tab (default): paste a valid Okta SAML metadata URL → Continue → wizard advances to Test.
  • Configure manually tab: fill Sign on URL + Issuer, pick a .pem/.key/.crt/.cer/.cert cert file → Continue stays disabled until all three are present → click Continue → connection is patched with { saml: { idpSsoUrl, idpEntityId, idpCertificate } } → wizard advances to Test.

Click the × on the filename chip → cert state clears and the Upload file button returns. Picking the same file again refires the change.

Configure-again (editing)

From the Confirmation step's Configure again button (goToStep('configure')), land back on the SAML config sub-step:

  • Segmented control defaults to Configure manually.
  • Sign on URL + Issuer pre-populate from the existing connection.
  • Cert row shows Replace file; Continue is enabled without re-uploading. Submitting omits idpCertificate from the payload so the backend keeps the existing cert.
  • Pick a new cert file → row swaps to filename chip → Submit replaces the cert with the new one.

Errors

Backend errors keyed idp_sso_url, idp_entity_id, or idp_certificate render inline below the corresponding field; everything else surfaces at the card level.

Base

Branches from main — stacks on top of #8535 (merged).

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation

Wraps the SAML config submission body in a two-mode segmented control
inside <__experimental_ConfigureSSO />'s Configure step. Users pick
between Add via metadata URL (default) and Configure manually. The
metadata URL form keeps its existing behavior; the manual entry form
lands in a follow-up commit and is intentionally an empty body for now
with the Continue button disabled.

Mode is local component state in SubmitSamlConfigSubStep — internal
flag, not wizard navigation — so the segmented control swap stays
inside the sub-step.

Locale keys added under configureSSO.configureStep.samlOkta.modes in
en-US.
Two copy fixes against the Configure step's SAML submission sub-step:

- The metadata segmented-control tab now reads "Add via metadata"
  instead of "Add via metadata URL". Figma's tab label is the shorter
  variant; the description below the field still spells out "metadata
  URL".
- Add a section heading "Fill in your Okta SAML application details"
  above the segmented control, matching the per-sub-step subtitle
  pattern used in ConfigureAttributes and AssignUsers. Wired through a
  new configureSSO.configureStep.samlOkta.submitSamlConfig.title locale
  key.
Renders the Configure manually tab body in SubmitSamlConfigSubStep with
the per-mode description and three fields:

- Sign on URL — text input wired with useFormControl('idpSsoUrl')
- Issuer — text input wired with useFormControl('idpEntityId')
- Signing certificate — label plus a stub outline button with the
  Upload icon. The button is intentionally inert; the file picker and
  filename chip land in a follow-up commit.

Adds 'idpEntityId' and 'idpSsoUrl' to the FieldId union and a new
configureSSO.configureStep.samlOkta.manual locale block with the
description, per-field labels and placeholders, and the cert label
plus upload-file button copy.

The Continue button stays disabled in manual mode for now — its
payload handler ({ saml: { idpSsoUrl, idpEntityId, idpCertificate } })
ships in the next commit.
Replaces the stub Upload file button in SubmitSamlConfigSubStep with a
working file picker. A hidden file input captures the selected cert
(accepts .pem/.crt/.cer/.txt); when present, the cert row swaps to a
filename label plus a small remove button that clears state and resets
the input. Cert state lives in component-local React state — no
useFormControl, no FieldId — since the Continue handler that consumes
it ships in a follow-up.

Adds a configureSSO.configureStep.samlOkta.manual.signingCertificate.
removeFile locale key for the remove button's aria-label.
Enables Continue in Configure manually mode of SubmitSamlConfigSubStep
when Sign on URL, Issuer, and a cert file are all present. handleContinue
now branches on the mode: metadata URL keeps its existing single-field
payload; manual reads the selected cert via File.text() and posts
{ saml: { idpSsoUrl, idpEntityId, idpCertificate } } through the same
user.updateEnterpriseConnection mutation.

Backend rejections route through handleError into the relevant text
fields per mode (metadataUrlField for URL mode, signOnUrlField and
issuerField for manual). Cert-specific errors fall through to the card-
level error surface since the cert UI has no inline error slot.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 14, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment May 14, 2026 7:39pm

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 14, 2026

🦋 Changeset detected

Latest commit: 5fbd791

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
Name Type
@clerk/localizations Patch
@clerk/shared Patch
@clerk/ui Patch
@clerk/react Patch
@clerk/astro Patch
@clerk/backend Patch
@clerk/chrome-extension Patch
@clerk/clerk-js Patch
@clerk/expo-passkeys Patch
@clerk/expo Patch
@clerk/express Patch
@clerk/fastify Patch
@clerk/hono Patch
@clerk/msw Patch
@clerk/nextjs Patch
@clerk/nuxt Patch
@clerk/react-router Patch
@clerk/tanstack-react-start Patch
@clerk/testing Patch
@clerk/vue Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 14, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a two-mode segmented control to the SAML configuration submission flow in <__experimental_ConfigureSSO />. Users can choose Add via metadata URL (existing flow) or Configure manually (new manual entry fields). It adds new field identifiers (idpEntityId, idpSsoUrl, idpCertificate), extends localization types and en-US strings for the mode selector and manual form, implements mode state and cert-file handling, makes validation and submission mode-dependent, and includes UI and layout refinements for attribute mapping and user assignment.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • clerk/javascript#8535: Modifies the same SubmitSamlConfigSubStep to add IdP metadata URL submission with localization, which this PR extends by introducing the mode selector and manual configuration path branching.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main feature: adding a 'Configure manually' path to the SAML config submission sub-step, which is the primary objective of this PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description comprehensively covers the feature changes: adds Configure manually path with segmented control, describes two modes (metadata and manual), details new field IDs, certificate handling, error routing, pre-fill behavior, locale keys, and includes testing guidance.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 14, 2026

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@8553

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@8553

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@8553

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@8553

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@8553

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@8553

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@8553

@clerk/express

npm i https://pkg.pr.new/@clerk/express@8553

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@8553

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8553

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@8553

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@8553

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@8553

@clerk/react

npm i https://pkg.pr.new/@clerk/react@8553

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@8553

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@8553

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@8553

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@8553

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8553

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@8553

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@8553

commit: 5fbd791

Extracts the metadata URL and manual-entry bodies of
SubmitSamlConfigSubStep into MetadataUrlPanel and ManualEntryPanel
components. State stays lifted in the parent — useFormControl hooks,
certFile, mode, card, updateConnection, handleContinue, canSubmit, and
Step.Footer all live in SubmitSamlConfigSubStep. The panels are pure
render components that receive their fields and cert state as props.

Field state is preserved across mode switches as a consequence — the
lifted state outlives the panel that renders it. Acceptable trade-off
given the "no useEffects, single hook upstream + prop-injection" rule.

Also aligns the cert file input's accept list with the Clerk Dashboard's
SAML connection form: .pem, .key, .crt, .cer, .cert. Drops .txt, adds
.key and .cert.
Reorganizes SubmitSamlConfigSubStep so the orchestrator stays at the
top of the file with the per-mode panels declared below it, mirroring
the convention used elsewhere in the codebase. Also narrows certFile
in handleContinue via an early return guard instead of a non-null
assertion, and swaps the Step.Section sx callback for the gap
shorthand prop.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ui/src/components/ConfigureSSO/steps/ConfigureStep.tsx`:
- Around line 551-554: The handleContinue handler currently blocks all submits
when certFile is falsy; change the check so certFile is only required when the
flow is in manual/certificate-upload mode (e.g., gate certFile behind whatever
boolean indicates manual mode instead of unconditionally checking certFile),
keeping enterpriseConnection and canSubmit required for both flows; update any
UI state/props used to detect "metadataUrl" vs "manual" flow (referencing
handleContinue, certFile, enterpriseConnection, canSubmit, and
metadataUrl/manual-mode flag) and add a regression test that simulates the
metadata-mode submission (no certFile) to ensure Continue succeeds when
canSubmit is true.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 8da919c9-9e0a-4d43-b0bc-565b11adf210

📥 Commits

Reviewing files that changed from the base of the PR and between 426519d and 28616cd.

📒 Files selected for processing (1)
  • packages/ui/src/components/ConfigureSSO/steps/ConfigureStep.tsx

Comment thread packages/ui/src/components/ConfigureSSO/steps/ConfigureStep.tsx
…dback

Two changes for the Configure manually flow:

- Pre-fills the metadata URL, Sign on URL, and Issuer text inputs from
  the existing enterpriseConnection.samlConnection on mount and defaults
  to the manual segmented-control tab when prior config exists, so the
  Configure-again entry from Confirmation lands users on an editable
  form pre-populated with their current values. Fresh setups still
  default to the metadata-URL tab.
- Promotes the cert picker to a real useFormControl-backed field with
  a new idpCertificate FieldId, so the cert label and inline error
  feedback render through Field.Root / Field.Label / Field.Feedback in
  the same chrome as the surrounding text inputs. Backend errors keyed
  idp_certificate now route inline below the cert UI via handleError.
  When the existing connection already has a cert on file, the picker
  shows a Replace file affordance and Continue stays enabled without
  requiring a fresh upload; the manual PATCH omits idpCertificate from
  the payload when no new file was selected.
Wraps the cert field section in a Box and groups Field.Label, the file
input, and the upload/filename row inside a Col gap-2 so the label-to-
control spacing stays consistent with the surrounding inputs.
Field.Feedback sits outside the Col so the error row keeps its default
spacing below the control. Also swaps the filename Text from an inline
fontSize sx to the buttonSmall variant and adds vertical padding to
the filename chip so it shares the upload button's baseline height.
…gain

Reverts the metadata URL field to always initialize as an empty string,
matching the Clerk Dashboard's SAML connection form behavior. The
metadata URL flow is a one-shot operation; pre-filling it implies the
user is editing the URL rather than re-submitting fresh metadata, which
is the opposite of how the metadata mode works on every other surface.
Sign on URL, Issuer, and the cert state are still pre-filled / preserved
for the manual mode's edit flow.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant