feat(ui): SAML metadata URL submission in ConfigureSSO Configure step#8535
Open
iagodahlem wants to merge 13 commits into
Open
feat(ui): SAML metadata URL submission in ConfigureSSO Configure step#8535iagodahlem wants to merge 13 commits into
iagodahlem wants to merge 13 commits into
Conversation
Adds the Okta SAML metadata URL path to the Configure step. The user
pastes their IdP metadata URL and the wizard advances on a successful
PATCH to user.updateEnterpriseConnection with { saml: { idpMetadataUrl } }.
The mutation is wrapped in useReverification, matching the established
convention for sensitive user.* mutations in @clerk/ui. useCardState
drives the loading state; handleError routes backend errors inline under
the field when the API returns idp_metadata_url, or to the card-level
error surface otherwise. Locale keys added under configureSSO.configureStep
in en-US.
Manual entry, file upload, SP-side copy rows, and the Okta admin-console
walkthrough are deferred to follow-up PRs.
🦋 Changeset detectedLatest commit: 8584741 The changes in this PR will be included in the next version bump. This PR includes changesets to release 20 packages
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 |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Unblocks type-check for the SAML metadata URL input added to the ConfigureSSO Configure step.
…ider
Mirrors the existing createConnection pattern: ConfigureSSOCardContent
destructures updateEnterpriseConnection from
__internal_useUserEnterpriseConnections and passes it as a prop to
ConfigureSSOProvider, which wraps it once in useReverification and exposes
it as updateConnection on the context.
The id is taken implicitly from enterpriseConnection in context, so call
sites don't thread it through. ConfigureStep now just calls
updateConnection({ saml: { idpMetadataUrl } }) and gets both
reverification and query revalidation for free, since the hook owns the
revalidate call after a successful mutation.
Drops the infoText option on useFormControl (which renders the helper copy as a focus-triggered tooltip) and places the description as a static <Text> element above the input. Styling mirrors the muted-body treatment used in SelectProviderStep so the inline copy reads the same as the tooltip did. Also tightens the placeholder copy from the dummy metadata URL to a neutral 'Paste URL here...'.
Mirrors VerifyDomainStep's nested wizard pattern: the outer Step is now a pure shell wrapping an inner Wizard with four Wizard.Step children — create-app, configure-attributes, assign-users, submit-saml-config. Step.Header renders an InnerStepCounter so the body shows Step X/4 as the user moves through the sub-steps. The existing metadata URL form moves into SubmitSamlConfigSubStep unchanged — same useReverification, useCardState, handleError wiring, same field, same PATCH. The first three sub-steps are placeholders with Previous/Continue scaffolding; content lands in follow-up commits. goNext/goPrev bubble across the wizard boundary natively (the Wizard primitive supports nested parent navigation), so the form's Continue handler still advances to the outer Test step on a successful PATCH without any cross-boundary plumbing.
Adds flex:1 to SubmitSamlConfigSubStep's Step.Section (was missing, so the footer didn't sit flush with the card edge) and drops the align/justify props on the placeholder sub-steps. Pure layout polish.
The function previously ran deepCamelToSnake(params), producing a nested
body like { saml: { idp_metadata_url } }. The backend expects the SAML
and OIDC fields prefixed at the top level (saml_idp_metadata_url,
oidc_client_id, etc.), so IdP metadata submissions in
<__experimental_ConfigureSSO /> were silently rejected.
Replaces the helper with a manual flat-field mapper: top-level fields
stay top-level, SAML fields get a saml_ prefix, OIDC fields get an oidc_
prefix. attribute_mapping and custom_attributes pass through unchanged
since their inner keys are user-supplied and must not be transformed.
A small setIfDefined helper makes the omit-undefined / forward-null
semantics explicit, so users can clear a field by sending null without
the SDK silently dropping it.
Mirrors the fix Laura validated in the SAML POC PR.
Step.Body already fills the vertical space between header and footer,
but Step.Section as a flex item defaults to flex:0 — so sections inside
the body shrink to content height unless told to grow. Until now each
sub-step had to repeat sx={{ flex: 1 }} on its Step.Section.
Defaulting flex:1 on Step.Section doesn't work because Step.Header
reuses the same primitive internally and needs to stay content-height,
and a single sub-step may stack multiple Sections where only one should
fill.
Adds an opt-in fill boolean prop. <Step.Section fill> applies flex:1;
the default behavior stays unchanged. Updates the four Configure
sub-step bodies to use the new prop. Other consumers (VerifyDomain,
SelectProvider) keep the old sx={{ flex: 1 }} pattern and can adopt the
prop in follow-ups.
Replaces the placeholder body of the first inner sub-step with three
stacked content groups:
1. Create new Okta app — section heading + bulleted list of 5
Okta admin-console steps (Sign in to Okta, click Create App
Integration, select SAML 2.0, fill General Settings, click Next).
2. Configure service provider — section heading + 2 description
paragraphs + 2 read-only copy rows for the SP-side ACS URL and
Audience URI. Values pull from connection.samlConnection.acsUrl
and spEntityId in the provider context. Uses the existing
ClipboardInput primitive so each row gets a copy-to-clipboard
button.
3. Complete SAML integration — section heading + bulleted list of
2 follow-up Okta admin-console steps.
All three groups live in one Step.Section fill with a generous gap so
the body scrolls naturally if needed; Step.Header keeps the only
border-bottom separator.
Bold keywords inside instruction lines (Admin → Applications,
Create App Integration, SAML 2.0, etc.) are split into prefix / bold /
suffix localization keys per line. Clerk's localization helper only
supports {{token}} string interpolation, so this keeps the bold span
themable through the existing Text primitive while still letting
translators see each instruction line as discrete units.
Locale keys added under configureSSO.configureStep.createApp in en-US.
Layout tightening across the inner Configure wizard: - Move Step.Body inside each sub-step component so the wizard switches bodies cleanly between sub-steps instead of nesting Wizard.Step children under a single outer Step.Body. - Wrap the ACS URL and Audience URI copy rows in Form.ControlRow + Form.CommonInputWrapper + ClipboardInput so the rows reuse the standard form chrome (label rendering, error slot, spacing) and the ClipboardInput primitive's readOnly + copyIcon/copiedIcon API. Adds 'acsUrl' to the FieldId union to back the new useFormControl call sites. - Bring group headings down to textVariant='subtitle' so the body reads as supporting content under the existing Step.Header title. - Tighten vertical spacing: Step.Section gap drops from $6 to $5, inner-group heading-to-content gap from $3 to $1x5, list-item gap from $1 to $1x5. - Soften the bold span in instructional lines from $semibold + $colorForeground to $medium + $colorMutedForeground so the emphasis feels like keyword highlighting rather than full bold.
Replaces the placeholder body of the second inner sub-step with two stacked content groups: 1. SAML attribute mapping — section heading + a 3-row attribute table built from the Table primitives (Thead / Tbody / Tr / Th / Td) and rendered with monospace claim-name cells. Each row pairs the attribute label with a Badge: warning colorScheme for the required Email row, secondary colorScheme for the optional First/Last name rows. Claim names render in an inline code span using the same monospace + neutralAlpha100 background + small radius styling as the InstructionStepWithCode helper. 2. Verify the attribute mappings in Okta — description paragraph + a numbered ordered list of 9 Okta admin-console steps. Shape-A lines (1, 4, 7) use the existing InstructionStep helper (prefix / bold / suffix); Shape-B lines (2, 3, 5, 6, 8, 9) use the new InstructionStepWithCode helper (prefix / bold / middle / code / suffix) so the mail / firstName / lastName values render as inline code spans. Mirrors the layout conventions established in the sibling sub-step (Step.Body inside the sub-step, single Step.Section with gap $5, inner groups in Cols with gap $1x5, headings as textVariant subtitle, medium-weight muted bold span). Adds the matching locale type entries and English copy under configureSSO.configureStep.configureAttributes.
…table styling
Replaces sx={{ color: $colorMutedForeground }} with Text colorScheme='secondary'
across ConfigureAttributesSubStep — the prop already resolves to the same color
token, so the inline sx call drops out cleanly.
Tightens the attribute mapping table chrome: column headers shrink to
fontSize=$xs, the first column picks up an inline-start pad so the leading
cell breathes against the table edge, and the claim-name cells reduce to
fontFamily: monospace only (drops the background, border-radius, and
padding from the earlier 'code chip' treatment for a flatter look that
reads as data, not as inline code).
Inner Cols inside ConfigureAttributesSubStep step up from gap $1x5 to $3.
Numbered/bulleted list indents grow from paddingInlineStart $4 to $5.
…opt inline rich-text markup
Restructures localization keys under configureSSO.configureStep so future
SAML providers (Custom SAML) and OIDC can drop in alongside Okta without
duplicating shared copy:
- spFields and attributeMapping live at the top level since their labels,
table content, badges, and the "These are the defaults..." paragraph
read the same regardless of provider.
- samlOkta now owns provider-specific copy: title, subtitle, createApp
walkthrough, serviceProvider narrative, completeSamlIntegration steps,
configureAttributes pairs, metadataUrl. When Custom SAML lands, a
sibling samlCustom namespace mirrors this shape.
Replaces the InstructionStep and InstructionStepWithCode helpers (which
required 3 or 5 separate keys per sentence) with a single RichText
component that parses inline <strong>...</strong> and <code>...</code>
markup in a localized string. One key per sentence, translators see the
whole context, emphasis stays themable through Text spans.
ConfigureAttributesSubStep redesigned to match Figma 8032:14794:
- Claim names in the attribute mapping table are now user.email,
user.firstName, user.lastName (corrects user.profile.email).
- The verify-mappings list collapses from 9 separate numbered steps to 2,
with a nested bulleted sub-list of the name/expression pairs the user
enters in Okta.
- Table rows render from an ATTRIBUTE_ROWS constant so the row markup
isn't duplicated three times.
- Verify-mappings pairs render from an ATTRIBUTE_PAIRS constant for the
same reason.
Sweeps remaining sx={{ color: $colorMutedForeground }} call sites in the
Configure sub-steps over to Text colorScheme='secondary' to match the
pattern used elsewhere in the file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds the Okta SAML metadata URL submission path to the Configure step of
<__experimental_ConfigureSSO />.The user pastes their IdP metadata URL and the wizard advances on a successful
PATCH /me/enterprise_connections/{id}with{ saml: { idpMetadataUrl } }. The mutation is wrapped inuseReverification, matching the established convention for sensitiveuser.*mutations in@clerk/ui.useCardStatedrives the loading state;handleErrorroutes backend errors inline under the field when the API returnsidp_metadata_url, or to the card-level error surface otherwise.Locale keys added under
configureSSO.configureStepinen-US.Linear: ORGS-1456
Follow-ups (separate PRs)
How to test
Set up a sandbox where the ConfigureSSO wizard lands on the Configure step with an enterprise connection in context. Paste a valid Okta SAML metadata URL → Continue → connection is patched and the wizard advances. Backend errors keyed
idp_metadata_urlrender inline; others render at the card level.Base
Stacked on #8503. GitHub will auto-retarget this PR to
mainonce that merges.Checklist
pnpm testruns as expected.pnpm buildruns as expected.Type of change