Skip to content

ORGS-1766: Improve self-serve SSO domain verification UX#9183

Open
NicolasLopes7 wants to merge 1 commit into
mainfrom
nicolas/orgs-1766-domain-verification-ux
Open

ORGS-1766: Improve self-serve SSO domain verification UX#9183
NicolasLopes7 wants to merge 1 commit into
mainfrom
nicolas/orgs-1766-domain-verification-ux

Conversation

@NicolasLopes7

@NicolasLopes7 NicolasLopes7 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add a localized Check now action for pending DNS ownership verification
  • show expected 1-5 minute verification timing and prevent overlapping checks
  • retain the existing 10-second automatic ownership-verification poll

Testing

  • pnpm --filter @clerk/ui exec vitest run src/components/ConfigureSSO/tests/ConfigureSSO.test.tsx
  • NODE_OPTIONS='--localstorage-file=/private/tmp/clerk-ui-localstorage.json' pnpm --filter @clerk/ui test
  • pnpm --filter @clerk/ui type-check
  • package builds and targeted lint

Linear: ORGS-1766

Summary by CodeRabbit

  • New Features

    • Added a “Check now” action for rechecking unverified SSO domain ownership without reloading the page.
    • Added a pending-status hint and loading state while verification is in progress.
    • Extended localization support for the new domain verification messages across supported languages.
  • Tests

    • Added coverage confirming that “Check now” triggers domain ownership verification.

@vercel

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Jul 16, 2026 8:50pm
swingset Ready Ready Preview, Comment Jul 16, 2026 8:50pm

Request Review

@changeset-bot

changeset-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 9236b60

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The SSO organization domains flow now lets admins retry ownership verification for unverified TXT records. The UI adds loading and error handling, localization types and resources gain two keys, and a test covers the retry action.

Changes

SSO domain verification retry

Layer / File(s) Summary
Localization contract and resources
packages/shared/src/types/localization.ts, packages/localizations/src/*.ts
Adds checkNowButton and pendingHint to the TXT-record localization shape and locale resources, currently using undefined values.
Organization domain recheck UI
packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx, packages/ui/src/components/ConfigureSSO/__tests__/ConfigureSSO.test.tsx
Wires ownership verification through domain cards, adds the check-now button with loading state and error handling, and tests verification with the unverified domain ID.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: laurabeatris

Poem

I’m a rabbit with a record to check,
One quick button, no reload trek.
TXT winds whisper, states turn bright,
Pending hints guide the hop just right.
Thump-thump—verification takes flight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: improving the self-serve SSO domain verification experience.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@pkg-pr-new

pkg-pr-new Bot commented Jul 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9183

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9183

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9183

@clerk/expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/hono

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

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/react

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

@clerk/react-router

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/ui

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

@clerk/upgrade

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

@clerk/vue

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

commit: 9236b60

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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/OrganizationDomainsStep.tsx`:
- Around line 645-663: Add a dedicated element descriptor for the new themable
check-now action in the OrganizationDomainsStep domain card, and pass it to the
Button via the elementDescriptor prop. Reuse the project’s established
descriptor naming and localization/context conventions, keeping the existing
handleCheckNow behavior unchanged.
- Around line 100-108: Update handleAttemptOwnershipVerification in
packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx#L100-L108
to inspect the resolved bulk verification result and pass any returned domain
errors through card.setError, while preserving thrown-error handling. Add
coverage in
packages/ui/src/components/ConfigureSSO/__tests__/ConfigureSSO.test.tsx#L173-L183
by mocking a resolved response containing errors and asserting the user-visible
error state.
- Around line 579-582: Update handleCheckNow and the useOrganizationDomains
polling flow to share an in-flight guard or pause polling during manual
verification, ensuring onAttemptOwnershipVerification cannot run concurrently
from the button and scheduled poll. Preserve the existing loading-state behavior
and resume polling after the manual check completes.
🪄 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), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 9e7eed89-4e06-4d35-a498-737fe6ad65f4

📥 Commits

Reviewing files that changed from the base of the PR and between b37ba0d and 9236b60.

📒 Files selected for processing (52)
  • packages/localizations/src/ar-SA.ts
  • packages/localizations/src/be-BY.ts
  • packages/localizations/src/bg-BG.ts
  • packages/localizations/src/bn-IN.ts
  • packages/localizations/src/ca-ES.ts
  • packages/localizations/src/cs-CZ.ts
  • packages/localizations/src/da-DK.ts
  • packages/localizations/src/de-DE.ts
  • packages/localizations/src/el-GR.ts
  • packages/localizations/src/en-GB.ts
  • packages/localizations/src/en-US.ts
  • packages/localizations/src/es-CR.ts
  • packages/localizations/src/es-ES.ts
  • packages/localizations/src/es-MX.ts
  • packages/localizations/src/es-UY.ts
  • packages/localizations/src/fa-IR.ts
  • packages/localizations/src/fi-FI.ts
  • packages/localizations/src/fr-FR.ts
  • packages/localizations/src/he-IL.ts
  • packages/localizations/src/hi-IN.ts
  • packages/localizations/src/hr-HR.ts
  • packages/localizations/src/hu-HU.ts
  • packages/localizations/src/id-ID.ts
  • packages/localizations/src/is-IS.ts
  • packages/localizations/src/it-IT.ts
  • packages/localizations/src/ja-JP.ts
  • packages/localizations/src/kk-KZ.ts
  • packages/localizations/src/ko-KR.ts
  • packages/localizations/src/mn-MN.ts
  • packages/localizations/src/ms-MY.ts
  • packages/localizations/src/nb-NO.ts
  • packages/localizations/src/nl-BE.ts
  • packages/localizations/src/nl-NL.ts
  • packages/localizations/src/pl-PL.ts
  • packages/localizations/src/pt-BR.ts
  • packages/localizations/src/pt-PT.ts
  • packages/localizations/src/ro-RO.ts
  • packages/localizations/src/ru-RU.ts
  • packages/localizations/src/sk-SK.ts
  • packages/localizations/src/sr-RS.ts
  • packages/localizations/src/sv-SE.ts
  • packages/localizations/src/ta-IN.ts
  • packages/localizations/src/te-IN.ts
  • packages/localizations/src/th-TH.ts
  • packages/localizations/src/tr-TR.ts
  • packages/localizations/src/uk-UA.ts
  • packages/localizations/src/vi-VN.ts
  • packages/localizations/src/zh-CN.ts
  • packages/localizations/src/zh-TW.ts
  • packages/shared/src/types/localization.ts
  • packages/ui/src/components/ConfigureSSO/__tests__/ConfigureSSO.test.tsx
  • packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx

Comment on lines +100 to +108
const handleAttemptOwnershipVerification = async (domain: OrganizationDomainResource) => {
card.setError(undefined);

try {
await attemptOwnershipVerification([domain]);
} catch (err: any) {
const apiError = getFieldError(err) ?? getGlobalError(err);
card.setError(apiError);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Handle resolved per-domain verification failures.

The bulk API reports bad domains in its resolved errors array, but Line 104 ignores that result; only thrown failures reach the alert. Surface returned errors in card.error and cover that response shape.

  • packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx#L100-L108: inspect the returned bulk result and set a card error when it contains domain errors.
  • packages/ui/src/components/ConfigureSSO/__tests__/ConfigureSSO.test.tsx#L173-L183: mock a resolved response with errors and assert the user-visible error state.
📍 Affects 2 files
  • packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx#L100-L108 (this comment)
  • packages/ui/src/components/ConfigureSSO/__tests__/ConfigureSSO.test.tsx#L173-L183
🤖 Prompt for 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.

In `@packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx`
around lines 100 - 108, Update handleAttemptOwnershipVerification in
packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx#L100-L108
to inspect the resolved bulk verification result and pass any returned domain
errors through card.setError, while preserving thrown-error handling. Add
coverage in
packages/ui/src/components/ConfigureSSO/__tests__/ConfigureSSO.test.tsx#L173-L183
by mocking a resolved response containing errors and asserting the user-visible
error state.

Source: Coding guidelines

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@NicolasLopes7 is a returned error here theoretically possible? if so I assume we want to examine the return value, extract errors, and set them to the card error

Comment on lines +579 to +582
const handleCheckNow = () => {
setIsChecking(true);
void onAttemptOwnershipVerification().finally(() => setIsChecking(false));
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the target file and inspect the relevant range.
wc -l packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx
sed -n '520,720p' packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx

# Find the ownership-verification hook and polling references.
rg -n "onAttemptOwnershipVerification|isChecking|10-second|setIsChecking|poll|verification" packages/ui/src/components/ConfigureSSO -S

# Inspect nearby files that define the hook behavior, if present.
fd -a "OrganizationDomainsStep.tsx|*ConfigureSSO*|*ownership*|*verification*" packages/ui/src/components/ConfigureSSO packages/ui/src -t f

Repository: clerk/javascript

Length of output: 11136


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the parent logic around the handler passed to TxtRecord.
sed -n '150,240p' packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx
sed -n '360,540p' packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx

# Read the organization enterprise connection hook to understand whether it polls or refetches automatically.
sed -n '1,220p' packages/ui/src/components/ConfigureSSO/hooks/useOrganizationEnterpriseConnection.ts

# Read any helper/hook used to attempt ownership verification, if present.
rg -n "attemptOwnershipVerification|ownershipVerification|prepareOwnershipVerification|checkNow|verifyAgain" packages/ui/src/components/ConfigureSSO/hooks packages/ui/src/components/ConfigureSSO/domain -S

Repository: clerk/javascript

Length of output: 20125


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the rest of useOrganizationEnterpriseConnection, especially the domain mutation wiring.
sed -n '220,320p' packages/ui/src/components/ConfigureSSO/hooks/useOrganizationEnterpriseConnection.ts

# Locate any in-repo implementation of the internal domain hook or its revalidate behavior.
rg -n "__internal_useOrganizationDomains|attemptOwnershipVerification|prepareOwnershipVerification|revalidateDomains|onOwnershipVerified" packages -S

# Inspect the type or implementation surface for the domain aggregate if present in repo.
fd -a "organizationDomains*|useOrganizationDomains*|*OrganizationDomains*" packages -t f

Repository: clerk/javascript

Length of output: 11925


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the organization-domains hook implementation.
wc -l packages/shared/src/react/hooks/useOrganizationDomains.tsx
sed -n '1,260p' packages/shared/src/react/hooks/useOrganizationDomains.tsx

# Inspect the organization-domain resource methods for attempt/prep semantics.
sed -n '170,220p' packages/shared/src/types/organization.ts
sed -n '230,280p' packages/shared/src/types/organizationDomain.ts

Repository: clerk/javascript

Length of output: 13368


Serialize manual checks with the polling loop
handleCheckNow only disables this button; useOrganizationDomains keeps polling attemptOwnershipVerification() every 10s, so a click can overlap with the next scheduled attempt. Share an in-flight guard, or pause polling while a manual check is running, to avoid duplicate requests.

🤖 Prompt for 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.

In `@packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx`
around lines 579 - 582, Update handleCheckNow and the useOrganizationDomains
polling flow to share an in-flight guard or pause polling during manual
verification, ensuring onAttemptOwnershipVerification cannot run concurrently
from the button and scheduled poll. Preserve the existing loading-state behavior
and resume polling after the manual check completes.

Comment on lines +645 to +663
<Button
variant='bordered'
colorScheme='secondary'
size='xs'
isDisabled={isChecking}
isLoading={isChecking}
onClick={handleCheckNow}
sx={t => ({ alignSelf: 'flex-start', gap: t.space.$1x5 })}
>
<Icon
icon={RotateLeftRight}
size='sm'
colorScheme='neutral'
/>
<Text
as='span'
localizationKey={localizationKeys('configureSSO.organizationDomainsStep.domainCard.txtRecord.checkNowButton')}
/>
</Button>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add an element descriptor for the new action.

This new themable button cannot be targeted through Appearance customization. Add a dedicated descriptor and pass it via elementDescriptor. As per coding guidelines, “Use element descriptors for all themable elements.”

🤖 Prompt for 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.

In `@packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx`
around lines 645 - 663, Add a dedicated element descriptor for the new themable
check-now action in the OrganizationDomainsStep domain card, and pass it to the
Button via the elementDescriptor prop. Reuse the project’s established
descriptor naming and localization/context conventions, keeping the existing
handleCheckNow behavior unchanged.

Source: Coding guidelines

@github-actions

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-07-16T20:52:42.235Z

Summary

Metric Count
Packages analyzed 19
Packages with changes 1
🔴 Breaking changes 0
🟡 Non-breaking changes 1
🟢 Additions 0

🤖 This report was reviewed by claude-sonnet-4-6.


@clerk/shared

Current version: 4.25.5
Recommended bump: MINOR → 4.26.0

Subpath ./types

🟡 Non-breaking Changes (1)

Modified: __internal_LocalizationResource
// ... 1339 unchanged lines elided ...
          removeButtonTooltip__lastVerifiedDomainActive: LocalizationValue;
          txtRecord: {
            instructions: LocalizationValue;
+           pendingHint: LocalizationValue;
+           checkNowButton: LocalizationValue;
            typeLabel: LocalizationValue;
            hostLabel: LocalizationValue;
            valueLabel: LocalizationValue;
// ... 635 unchanged lines elided ...

Static analyzer: Breaking change in type alias __internal_LocalizationResource: Type changed: {locale:string;maintenanceMode:import("@clerk/shared").LocalizationValue;roles:{[r:string]:import("@clerk/shared").Loca…{locale:string;maintenanceMode:import("@clerk/shared").LocalizationValue;roles:{[r:string]:import("@clerk/shared").Loca…

🤖 AI review (reclassified as non-breaking) (72%): The before/after snippets are structurally identical at the visible portions; the only difference is '1902 lines elided' vs '1900 lines elided', indicating 2 new fields were added somewhere in the middle. __internal_LocalizationResource is consumed only as the source for DeepPartial<DeepLocalizationWithoutObjects<...>> (i.e., it is an output/read type for consumers), and adding new optional fields via DeepPartial wrapping to a type consumers only read is non-breaking. Even if the new fields are required in the raw type, DeepPartial makes them optional in LocalizationResource, so existing consumer objects still satisfy the interface.


Report generated by Break Check

Last ran on 9236b60.

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.

2 participants