@burdenoff/microfe-auth 2026.925.1 → 2026.1009.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/README.md +14 -0
  2. package/dist/auth/AuthRoot.d.ts +0 -1
  3. package/dist/auth/AuthRoot.js.map +1 -1
  4. package/dist/auth/AuthRoutes.d.ts +1 -1
  5. package/dist/auth/AuthRoutes.js.map +1 -1
  6. package/dist/auth/components/AuthIcons.d.ts +12 -13
  7. package/dist/auth/components/AuthIcons.js.map +1 -1
  8. package/dist/auth/components/AuthLayout.d.ts +1 -2
  9. package/dist/auth/components/AuthLayout.js.map +1 -1
  10. package/dist/auth/components/CaptchaV2.d.ts +1 -1
  11. package/dist/auth/components/CaptchaV2.js +2 -2
  12. package/dist/auth/components/CaptchaV2.js.map +1 -1
  13. package/dist/auth/components/ConfirmActionDialog.d.ts +1 -1
  14. package/dist/auth/components/ConfirmActionDialog.js.map +1 -1
  15. package/dist/auth/components/profile/UserProfileMenu.d.ts +1 -1
  16. package/dist/auth/components/profile/UserProfileMenu.js.map +1 -1
  17. package/dist/auth/components/workspace/WorkspaceSelector.d.ts +1 -2
  18. package/dist/auth/components/workspace/WorkspaceSelector.js.map +1 -1
  19. package/dist/auth/constants/permissions.js.map +1 -1
  20. package/dist/auth/hooks/useAccountOperations.d.ts +0 -1
  21. package/dist/auth/hooks/useAccountOperations.js.map +1 -1
  22. package/dist/auth/hooks/useActiveContextBootstrapMirror.js.map +1 -1
  23. package/dist/auth/hooks/useApiKeyOperations.d.ts +1 -2
  24. package/dist/auth/hooks/useAppOperations.d.ts +1 -2
  25. package/dist/auth/hooks/useAuthOperations.d.ts +0 -1
  26. package/dist/auth/hooks/useAuthOperations.js.map +1 -1
  27. package/dist/auth/hooks/useAuthPermissions.js.map +1 -1
  28. package/dist/auth/hooks/useCaptchaV3.js +1 -1
  29. package/dist/auth/hooks/useCaptchaV3.js.map +1 -1
  30. package/dist/auth/hooks/useContextSwitcherData.d.ts +1 -1
  31. package/dist/auth/hooks/useContextSwitcherData.js +346 -259
  32. package/dist/auth/hooks/useContextSwitcherData.js.map +1 -1
  33. package/dist/auth/hooks/useDelegationOperations.d.ts +0 -1
  34. package/dist/auth/hooks/useMfaOperations.d.ts +0 -1
  35. package/dist/auth/hooks/useMfaOperations.js.map +1 -1
  36. package/dist/auth/hooks/useMyWorkspaces.d.ts +0 -1
  37. package/dist/auth/hooks/useMyWorkspaces.js.map +1 -1
  38. package/dist/auth/hooks/useOAuthOperations.d.ts +0 -1
  39. package/dist/auth/hooks/useOAuthOperations.js +2 -2
  40. package/dist/auth/hooks/useOAuthOperations.js.map +1 -1
  41. package/dist/auth/hooks/usePasswordOperations.d.ts +0 -1
  42. package/dist/auth/hooks/usePasswordOperations.js.map +1 -1
  43. package/dist/auth/hooks/useSessionOperations.d.ts +0 -1
  44. package/dist/auth/hooks/useSessionOperations.js.map +1 -1
  45. package/dist/auth/hooks/useSignupCaptcha.js +1 -1
  46. package/dist/auth/hooks/useSignupCaptcha.js.map +1 -1
  47. package/dist/auth/hooks/useSsoOperations.d.ts +0 -1
  48. package/dist/auth/hooks/useSsoOperations.js.map +1 -1
  49. package/dist/auth/hooks/useTokenRefresh.js.map +1 -1
  50. package/dist/auth/hooks/useUserOperations.d.ts +0 -1
  51. package/dist/auth/hooks/useUserOperations.js.map +1 -1
  52. package/dist/auth/hooks/useWorkspaceOperations.d.ts +0 -1
  53. package/dist/auth/hooks/useWorkspaceOperations.js.map +1 -1
  54. package/dist/auth/hooks/useWorkspaceToken.js.map +1 -1
  55. package/dist/auth/pages/AuditLogPage.d.ts +1 -1
  56. package/dist/auth/pages/AuditLogPage.js.map +1 -1
  57. package/dist/auth/pages/EmailVerifyPage.d.ts +1 -1
  58. package/dist/auth/pages/EmailVerifyPage.js.map +1 -1
  59. package/dist/auth/pages/LoginPage.d.ts +1 -1
  60. package/dist/auth/pages/LoginPage.js.map +1 -1
  61. package/dist/auth/pages/MagicLinkPage.d.ts +1 -1
  62. package/dist/auth/pages/MagicLinkPage.js.map +1 -1
  63. package/dist/auth/pages/MfaSetupPage.d.ts +1 -1
  64. package/dist/auth/pages/MfaSetupPage.js +88 -88
  65. package/dist/auth/pages/MfaSetupPage.js.map +1 -1
  66. package/dist/auth/pages/MfaVerifyPage.d.ts +1 -1
  67. package/dist/auth/pages/MfaVerifyPage.js.map +1 -1
  68. package/dist/auth/pages/OAuthCallbackPage.d.ts +1 -1
  69. package/dist/auth/pages/OAuthCallbackPage.js.map +1 -1
  70. package/dist/auth/pages/PasswordResetPage.d.ts +1 -1
  71. package/dist/auth/pages/PasswordResetPage.js.map +1 -1
  72. package/dist/auth/pages/ReactivatePage.d.ts +1 -1
  73. package/dist/auth/pages/ReactivatePage.js.map +1 -1
  74. package/dist/auth/pages/RegisterPage.d.ts +1 -1
  75. package/dist/auth/pages/RegisterPage.js.map +1 -1
  76. package/dist/auth/pages/SSOClearPage.d.ts +1 -1
  77. package/dist/auth/pages/SSOClearPage.js.map +1 -1
  78. package/dist/auth/pages/SSODepositPage.d.ts +1 -1
  79. package/dist/auth/pages/SSODepositPage.js.map +1 -1
  80. package/dist/auth/pages/SSORelayCallbackPage.d.ts +1 -1
  81. package/dist/auth/pages/SSORelayCallbackPage.js.map +1 -1
  82. package/dist/auth/pages/SSORelayPage.d.ts +1 -1
  83. package/dist/auth/pages/SSORelayPage.js.map +1 -1
  84. package/dist/auth/pages/SecurityPage.d.ts +1 -1
  85. package/dist/auth/pages/SecurityPage.js.map +1 -1
  86. package/dist/auth/pages/SessionBridgePage.d.ts +1 -1
  87. package/dist/auth/pages/SessionBridgePage.js.map +1 -1
  88. package/dist/auth/pages/SessionsPage.d.ts +1 -1
  89. package/dist/auth/pages/SessionsPage.js.map +1 -1
  90. package/dist/auth/pages/SsoCallbackPage.d.ts +1 -1
  91. package/dist/auth/pages/SsoCallbackPage.js.map +1 -1
  92. package/dist/auth/pages/SsoConfigPage.d.ts +1 -1
  93. package/dist/auth/pages/SsoConfigPage.js.map +1 -1
  94. package/dist/auth/pages/SsoLoginPage.d.ts +1 -1
  95. package/dist/auth/pages/SsoLoginPage.js.map +1 -1
  96. package/dist/auth/pages/UserDetailsPage.d.ts +1 -1
  97. package/dist/auth/pages/UserDetailsPage.js.map +1 -1
  98. package/dist/auth/pages/UserProfilePage.d.ts +1 -1
  99. package/dist/auth/pages/UserProfilePage.js.map +1 -1
  100. package/dist/auth/pages/UsersPage.d.ts +1 -1
  101. package/dist/auth/pages/UsersPage.js.map +1 -1
  102. package/dist/auth/providers/AuthProvider.d.ts +0 -1
  103. package/dist/auth/providers/AuthProvider.js.map +1 -1
  104. package/dist/auth/providers/CaptchaProvider.d.ts +1 -2
  105. package/dist/auth/providers/CaptchaProvider.js +2 -2
  106. package/dist/auth/providers/CaptchaProvider.js.map +1 -1
  107. package/dist/auth/store/authStore.d.ts +0 -1
  108. package/dist/auth/store/authStore.js.map +1 -1
  109. package/dist/auth/types/index.d.ts +0 -1
  110. package/dist/auth/utils/captchaConfig.js.map +1 -1
  111. package/dist/auth/utils/formatters.js.map +1 -1
  112. package/dist/auth/utils/gatewayBaseUrls.js.map +1 -1
  113. package/dist/auth/utils/legalUrls.js.map +1 -1
  114. package/dist/auth/utils/redirect.js.map +1 -1
  115. package/dist/auth/utils/ssoOrigins.js.map +1 -1
  116. package/dist/auth/utils/validation.d.ts +0 -1
  117. package/dist/auth/utils/validation.js.map +1 -1
  118. package/dist/dev/main.d.ts +0 -1
  119. package/dist/generated/global-operations.js.map +1 -1
  120. package/dist/generated/wspace-operations.js.map +1 -1
  121. package/dist/index.d.ts +0 -1
  122. package/dist/shared/hooks/useTr.js.map +1 -1
  123. package/dist/shared/types/index.d.ts +0 -1
  124. package/dist/translations/en.js.map +1 -1
  125. package/package.json +27 -20
  126. package/dist/_virtual/_rolldown/runtime.js +0 -13
  127. package/dist/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js +0 -70
  128. package/dist/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js.map +0 -1
  129. package/dist/node_modules/object-assign/index.js +0 -41
  130. package/dist/node_modules/object-assign/index.js.map +0 -1
  131. package/dist/node_modules/prop-types/checkPropTypes.js +0 -46
  132. package/dist/node_modules/prop-types/checkPropTypes.js.map +0 -1
  133. package/dist/node_modules/prop-types/factoryWithThrowingShims.js +0 -49
  134. package/dist/node_modules/prop-types/factoryWithThrowingShims.js.map +0 -1
  135. package/dist/node_modules/prop-types/factoryWithTypeCheckers.js +0 -272
  136. package/dist/node_modules/prop-types/factoryWithTypeCheckers.js.map +0 -1
  137. package/dist/node_modules/prop-types/index.js +0 -16
  138. package/dist/node_modules/prop-types/index.js.map +0 -1
  139. package/dist/node_modules/prop-types/lib/ReactPropTypesSecret.js +0 -10
  140. package/dist/node_modules/prop-types/lib/ReactPropTypesSecret.js.map +0 -1
  141. package/dist/node_modules/prop-types/lib/has.js +0 -10
  142. package/dist/node_modules/prop-types/lib/has.js.map +0 -1
  143. package/dist/node_modules/qrcode.react/lib/esm/index.js +0 -959
  144. package/dist/node_modules/qrcode.react/lib/esm/index.js.map +0 -1
  145. package/dist/node_modules/react-async-script/lib/esm/async-script-loader.js +0 -114
  146. package/dist/node_modules/react-async-script/lib/esm/async-script-loader.js.map +0 -1
  147. package/dist/node_modules/react-google-recaptcha/lib/esm/index.js +0 -8
  148. package/dist/node_modules/react-google-recaptcha/lib/esm/index.js.map +0 -1
  149. package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha-wrapper.js +0 -20
  150. package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha-wrapper.js.map +0 -1
  151. package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha.js +0 -148
  152. package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha.js.map +0 -1
  153. package/dist/node_modules/react-google-recaptcha-v3/dist/react-google-recaptcha-v3.esm.js +0 -445
  154. package/dist/node_modules/react-google-recaptcha-v3/dist/react-google-recaptcha-v3.esm.js.map +0 -1
  155. package/dist/node_modules/react-is/cjs/react-is.development.js +0 -84
  156. package/dist/node_modules/react-is/cjs/react-is.development.js.map +0 -1
  157. package/dist/node_modules/react-is/cjs/react-is.production.min.js +0 -64
  158. package/dist/node_modules/react-is/cjs/react-is.production.min.js.map +0 -1
  159. package/dist/node_modules/react-is/index.js +0 -12
  160. package/dist/node_modules/react-is/index.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"SsoConfigPage.js","names":[],"sources":["../../../src/auth/pages/SsoConfigPage.tsx"],"sourcesContent":["import { useState, useEffect, useRef } from \"react\";\nimport { useNavigate, useSearchParams } from \"react-router\";\nimport { useAuthPermissions } from \"../hooks/useAuthPermissions\";\nimport { useTr } from \"../../shared/hooks/useTr\";\nimport { useFeatureFlagDetails } from \"@burdenoff/fe-libs/shared/feature-flags\";\n// TODO(ux-sweep): wrap \"Advanced SAML / OIDC overrides\" (signing/encryption/\n// nameID-format/attribute-mapping) fields in <OptionalFields> once the\n// SsoConfigPage tabbed form is refactored away from raw tabs. The page is\n// 1700+ lines with no obvious mid-form advanced section to wrap today.\nimport {\n EmphasisPanel,\n IllustratedEmptyState,\n PagePurpose,\n NextSteps,\n} from \"@burdenoff/fe-libs/ui\";\nimport { Button } from \"@burdenoff/fe-libs/button\";\nimport { ConfirmActionDialog } from \"../components/ConfirmActionDialog\";\nimport {\n useSsoOperations,\n type SSOConfigInput,\n} from \"../hooks/useSsoOperations\";\nimport { SpinnerIcon, AlertIcon } from \"../components/AuthIcons\";\nimport {\n nativeCopyText,\n nativeImpact,\n nativeNotify,\n} from \"../../utils/nativeBridge\";\n\nconst copyTextWithNative = async (text: string): Promise<void> => {\n void nativeImpact(\"light\");\n const ok = await nativeCopyText(text);\n void nativeNotify(ok ? \"success\" : \"error\");\n};\n\n// =============================================================================\n// SAML Metadata Parser\n// =============================================================================\n\ninterface ParsedSAMLMetadata {\n entityId: string;\n ssoUrl: string;\n sloUrl?: string;\n certificate: string;\n}\n\nfunction parseSAMLMetadata(xmlString: string): ParsedSAMLMetadata | null {\n try {\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlString, \"text/xml\");\n\n // Check for parse errors\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n console.error(\"XML parse error:\", parseError.textContent);\n return null;\n }\n\n // Extract EntityID\n const entityDescriptor = doc.querySelector(\"EntityDescriptor\");\n const entityId = entityDescriptor?.getAttribute(\"entityID\") || \"\";\n\n // Find IDPSSODescriptor\n const idpDescriptor = doc.querySelector(\"IDPSSODescriptor\");\n if (!idpDescriptor) {\n console.error(\"No IDPSSODescriptor found\");\n return null;\n }\n\n // Extract SSO URL (HTTP-Redirect or HTTP-POST binding)\n const ssoServices = idpDescriptor.querySelectorAll(\"SingleSignOnService\");\n let ssoUrl = \"\";\n for (const service of ssoServices) {\n const binding = service.getAttribute(\"Binding\") || \"\";\n if (binding.includes(\"HTTP-Redirect\") || binding.includes(\"HTTP-POST\")) {\n ssoUrl = service.getAttribute(\"Location\") || \"\";\n break;\n }\n }\n\n // Extract SLO URL\n const sloServices = idpDescriptor.querySelectorAll(\"SingleLogoutService\");\n let sloUrl = \"\";\n for (const service of sloServices) {\n const binding = service.getAttribute(\"Binding\") || \"\";\n if (binding.includes(\"HTTP-Redirect\") || binding.includes(\"HTTP-POST\")) {\n sloUrl = service.getAttribute(\"Location\") || \"\";\n break;\n }\n }\n\n // Extract Certificate\n const certElement = doc.querySelector(\"X509Certificate\");\n let certificate = certElement?.textContent?.trim() || \"\";\n if (certificate && !certificate.includes(\"-----BEGIN\")) {\n certificate = `-----BEGIN CERTIFICATE-----\\n${certificate}\\n-----END CERTIFICATE-----`;\n }\n\n if (!entityId || !ssoUrl || !certificate) {\n console.error(\"Missing required SAML metadata fields\");\n return null;\n }\n\n return { entityId, ssoUrl, sloUrl, certificate };\n } catch (error) {\n console.error(\"Failed to parse SAML metadata:\", error);\n return null;\n }\n}\n\n// =============================================================================\n// OIDC Client Types\n// =============================================================================\n\ninterface OIDCClient {\n client_id: string;\n client_secret?: string;\n redirect_uris: string[];\n grant_types: string[];\n response_types: string[];\n token_endpoint_auth_method: string;\n client_name?: string;\n registration_access_token?: string;\n}\n\ninterface SsoConfigPageProps {\n /** When true, skips the enterprise-plan gate so admins always see the full UI */\n bypassEnterprisePlanGate?: boolean;\n}\n\n/**\n * SSO Configuration page for managing SAML/OIDC enterprise SSO.\n * Admin only - allows configuring Identity Provider settings.\n * In admin-app context, bypassEnterprisePlanGate=true and tenant/org/workspace\n * scoping is read from URL search params (?tenant=&org=&workspace=).\n */\nexport function SsoConfigPage({\n bypassEnterprisePlanGate = false,\n}: SsoConfigPageProps) {\n const tr = useTr();\n const navigate = useNavigate();\n const [searchParams] = useSearchParams();\n const { canManageSsoConfig, isLoading: permissionsLoading } =\n useAuthPermissions();\n // Enterprise SSO gate: only visible to workspaces on an enterprise plan.\n // When the flag is absent the section is hidden (default-deny).\n // bypassEnterprisePlanGate=true skips this check entirely (admin-app usage).\n const enterpriseSsoFlag = useFeatureFlagDetails(\n \"workspace.auth.enterprise-sso\",\n );\n const isEnterpriseSsoEnabled =\n bypassEnterprisePlanGate || enterpriseSsoFlag?.value === true;\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n // In admin context, read scope from URL params; otherwise use platform default\n const urlTenantId = searchParams.get(\"tenant\");\n const urlOrgId = searchParams.get(\"org\");\n const urlWorkspaceId = searchParams.get(\"workspace\");\n const effectiveTenantId = urlTenantId ?? \"burdenoff.com\";\n\n const {\n ssoConfig,\n oidcConfig,\n isLoading,\n isSaving,\n isDeleting,\n saveSsoConfig,\n deleteSsoConfig,\n } = useSsoOperations(effectiveTenantId);\n\n const [activeTab, setActiveTab] = useState<\n \"saml\" | \"oidc\" | \"clients\" | \"test\"\n >(\"saml\");\n const [isEditing, setIsEditing] = useState(false);\n const [showDeleteDialog, setShowDeleteDialog] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [success, setSuccess] = useState<string | null>(null);\n\n // SAML Metadata import state\n const [metadataUrl, setMetadataUrl] = useState(\"\");\n const [isImporting, setIsImporting] = useState(false);\n\n // OIDC Client registration state\n const [showClientForm, setShowClientForm] = useState(false);\n const [newClient, setNewClient] = useState({\n client_name: \"\",\n redirect_uris: \"\",\n grant_types: [\"authorization_code\", \"refresh_token\"],\n token_endpoint_auth_method: \"none\",\n });\n const [isCreatingClient, setIsCreatingClient] = useState(false);\n const [createdClient, setCreatedClient] = useState<OIDCClient | null>(null);\n\n // Form state for SAML configuration\n const [formData, setFormData] = useState<SSOConfigInput>({\n entityId: \"\",\n ssoUrl: \"\",\n sloUrl: \"\",\n certificate: \"\",\n enabled: false,\n });\n\n // Handle SAML metadata file upload\n const handleMetadataFileUpload = async (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => {\n const file = event.target.files?.[0];\n if (!file) return;\n\n setError(null);\n setIsImporting(true);\n\n try {\n const text = await file.text();\n const parsed = parseSAMLMetadata(text);\n\n if (parsed) {\n setFormData({\n ...formData,\n entityId: parsed.entityId,\n ssoUrl: parsed.ssoUrl,\n sloUrl: parsed.sloUrl || \"\",\n certificate: parsed.certificate,\n });\n setSuccess(\n tr(\n \"auth.sso.importSuccess\",\n \"SAML metadata imported successfully! Review and save the configuration.\",\n ),\n );\n setIsEditing(true);\n } else {\n setError(\n tr(\n \"auth.sso.parseError\",\n \"Failed to parse SAML metadata. Make sure the file contains valid IdP metadata XML.\",\n ),\n );\n }\n } catch {\n setError(tr(\"auth.sso.readError\", \"Failed to read metadata file\"));\n } finally {\n setIsImporting(false);\n if (fileInputRef.current) {\n fileInputRef.current.value = \"\";\n }\n }\n };\n\n // Handle SAML metadata URL fetch\n const handleMetadataUrlFetch = async () => {\n if (!metadataUrl) {\n setError(tr(\"auth.sso.enterUrl\", \"Please enter a metadata URL\"));\n return;\n }\n\n setError(null);\n setIsImporting(true);\n\n try {\n const response = await fetch(metadataUrl);\n if (!response.ok) {\n throw new Error(`Failed to fetch: ${response.statusText}`);\n }\n\n const text = await response.text();\n const parsed = parseSAMLMetadata(text);\n\n if (parsed) {\n setFormData({\n ...formData,\n entityId: parsed.entityId,\n ssoUrl: parsed.ssoUrl,\n sloUrl: parsed.sloUrl || \"\",\n certificate: parsed.certificate,\n });\n setSuccess(\n tr(\n \"auth.sso.importSuccessFromUrl\",\n \"SAML metadata imported successfully! Review and save the configuration.\",\n ),\n );\n setIsEditing(true);\n setMetadataUrl(\"\");\n } else {\n setError(\n tr(\n \"auth.sso.parseUrlError\",\n \"Failed to parse SAML metadata from URL.\",\n ),\n );\n }\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"auth.sso.fetchError\", \"Failed to fetch metadata from URL\"),\n );\n } finally {\n setIsImporting(false);\n }\n };\n\n // Register new OIDC client\n const handleRegisterClient = async () => {\n if (!newClient.client_name || !newClient.redirect_uris) {\n setError(\n tr(\n \"auth.sso.clientRequired\",\n \"Client name and redirect URI are required\",\n ),\n );\n return;\n }\n\n setIsCreatingClient(true);\n setError(null);\n\n try {\n const registrationEndpoint = oidcConfig?.registrationEndpoint;\n\n if (!registrationEndpoint) {\n throw new Error(\n tr(\n \"auth.sso.oidcNotConfigured\",\n \"OIDC dynamic client registration is not configured for this environment.\",\n ),\n );\n }\n\n const response = await fetch(registrationEndpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n client_name: newClient.client_name,\n redirect_uris: newClient.redirect_uris\n .split(\",\")\n .map((uri) => uri.trim()),\n grant_types: newClient.grant_types,\n response_types: [\"code\"],\n token_endpoint_auth_method: newClient.token_endpoint_auth_method,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json();\n throw new Error(\n errorData.error_description ||\n errorData.error ||\n \"Registration failed\",\n );\n }\n\n const client = await response.json();\n setCreatedClient(client);\n setSuccess(\n tr(\n \"auth.sso.clientRegistered\",\n \"OIDC client registered successfully! Save the client credentials.\",\n ),\n );\n setShowClientForm(false);\n setNewClient({\n client_name: \"\",\n redirect_uris: \"\",\n grant_types: [\"authorization_code\", \"refresh_token\"],\n token_endpoint_auth_method: \"none\",\n });\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"auth.sso.registerFailed\", \"Failed to register client\"),\n );\n } finally {\n setIsCreatingClient(false);\n }\n };\n\n // Sync form with loaded config\n useEffect(() => {\n if (ssoConfig) {\n setFormData({\n entityId: ssoConfig.entityId || \"\",\n ssoUrl: ssoConfig.ssoUrl || \"\",\n sloUrl: ssoConfig.sloUrl || \"\",\n certificate: ssoConfig.certificate || \"\",\n enabled: ssoConfig.enabled || false,\n });\n }\n }, [ssoConfig]);\n\n const handleSave = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setSuccess(null);\n\n try {\n await saveSsoConfig(formData);\n setSuccess(\n tr(\"auth.sso.saveSuccess\", \"SSO configuration saved successfully!\"),\n );\n setIsEditing(false);\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"auth.sso.saveFailed\", \"Failed to save configuration\"),\n );\n }\n };\n\n const handleDelete = async () => {\n setError(null);\n setSuccess(null);\n void nativeImpact(\"medium\");\n\n try {\n await deleteSsoConfig();\n void nativeNotify(\"success\");\n setSuccess(\n tr(\"auth.sso.deleteSuccess\", \"SSO configuration deleted successfully.\"),\n );\n setShowDeleteDialog(false);\n setFormData({\n entityId: \"\",\n ssoUrl: \"\",\n sloUrl: \"\",\n certificate: \"\",\n enabled: false,\n });\n } catch (err) {\n void nativeNotify(\"error\");\n setError(\n err instanceof Error\n ? err.message\n : tr(\"auth.sso.deleteFailed\", \"Failed to delete configuration\"),\n );\n }\n };\n\n const handleToggleEnabled = async () => {\n setError(null);\n try {\n await saveSsoConfig({ ...formData, enabled: !formData.enabled });\n setSuccess(\n formData.enabled\n ? tr(\"auth.sso.ssoDisabled\", \"SSO disabled\")\n : tr(\"auth.sso.ssoEnabled\", \"SSO enabled\"),\n );\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"auth.sso.statusUpdateFailed\", \"Failed to update status\"),\n );\n }\n };\n\n if (permissionsLoading) {\n return (\n <div className=\"max-w-5xl mx-auto p-6\">\n <div className=\"text-center py-16\">\n <SpinnerIcon className=\"size-8 mx-auto text-text-secondary animate-spin\" />\n <p className=\"mt-4 text-text-secondary\">\n {tr(\"auth.sso.loadingPermissions\", \"Loading permissions...\")}\n </p>\n </div>\n </div>\n );\n }\n\n if (!canManageSsoConfig) {\n return (\n <div className=\"max-w-5xl mx-auto p-6\">\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title={tr(\"auth.sso.adminRequired\", \"Admin Access Required\")}\n description={tr(\n \"auth.sso.adminRequiredDesc\",\n \"You need administrator privileges to configure SSO settings.\",\n )}\n />\n </div>\n );\n }\n\n // Enterprise SSO is a plan-gated feature. Only show the full configuration\n // to workspaces on an enterprise plan (flag: workspace.auth.enterprise-sso).\n if (!isEnterpriseSsoEnabled) {\n return (\n <div className=\"max-w-5xl mx-auto p-6\">\n <IllustratedEmptyState\n illustration=\"onboarding\"\n title={tr(\n \"auth.sso.enterprisePlanRequired\",\n \"Enterprise Plan Required\",\n )}\n description={\n <>\n {tr(\n \"auth.sso.enterprisePlanRequiredDesc\",\n \"Single Sign-On (SAML / OIDC) configuration is available on the Enterprise plan.\",\n )}{\" \"}\n {tr(\n \"auth.sso.contactSales\",\n \"Contact sales to upgrade your workspace to the Enterprise plan.\",\n )}\n </>\n }\n />\n </div>\n );\n }\n\n return (\n <div className=\"max-w-5xl mx-auto p-6\">\n <ConfirmActionDialog\n open={showDeleteDialog}\n onOpenChange={setShowDeleteDialog}\n title={tr(\"auth.sso.deleteConfirmTitle\", \"Delete SSO configuration?\")}\n description={tr(\n \"auth.sso.deleteConfirmDesc\",\n \"Users will immediately lose the ability to sign in with this SSO setup until a new configuration is saved.\",\n )}\n confirmText={tr(\"auth.sso.deleteConfirmButton\", \"Delete configuration\")}\n variant=\"danger\"\n isPending={isDeleting}\n onConfirm={handleDelete}\n />\n {/* Header */}\n <div className=\"flex items-center justify-between mb-8\">\n <div className=\"flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/security\")}\n aria-label={tr(\"auth.sso.backToSecurity\", \"Back to Security\")}\n className=\"p-2 rounded-lg hover:bg-bg-sunken transition-colors\"\n >\n <svg\n className=\"size-5 text-text-secondary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M10 19l-7-7m0 0l7-7m-7 7h18\"\n />\n </svg>\n </button>\n <div>\n <h1 className=\"text-2xl font-semibold text-text-primary\">\n {tr(\"auth.sso.title\", \"Single Sign-On (SSO)\")}\n </h1>\n <p className=\"text-text-secondary mt-1\">\n {tr(\n \"auth.sso.description\",\n \"Configure enterprise SSO with SAML 2.0 or OIDC\",\n )}\n </p>\n </div>\n </div>\n\n {ssoConfig && (\n <div className=\"flex items-center gap-3\">\n <span\n className={`px-3 py-1 rounded-full text-sm font-medium ${\n formData.enabled\n ? \"bg-status-success-bg-subtle text-status-success-text\"\n : \"bg-bg-sunken text-text-secondary\"\n }`}\n >\n {formData.enabled\n ? tr(\"auth.sso.enabled\", \"Enabled\")\n : tr(\"auth.sso.disabled\", \"Disabled\")}\n </span>\n <button\n type=\"button\"\n onClick={handleToggleEnabled}\n disabled={isSaving}\n className=\"px-4 py-2 rounded-lg border border-border-default text-text-primary hover:bg-bg-sunken transition-colors text-sm font-medium\"\n >\n {formData.enabled\n ? tr(\"auth.sso.disable\", \"Disable\")\n : tr(\"auth.sso.enable\", \"Enable\")}\n </button>\n </div>\n )}\n </div>\n\n <PagePurpose className=\"mb-6\">\n {tr(\n \"auth.sso.purpose\",\n \"Connect your organization's identity provider so your team signs in with their existing corporate credentials. Configure SAML 2.0 or OIDC here, then register the client apps that should accept these logins.\",\n )}\n </PagePurpose>\n\n {/* Emphasis: connection status — the one highlighted zone */}\n <EmphasisPanel className=\"mb-8\">\n <div className=\"flex items-center justify-between gap-4\">\n <div>\n <p className=\"text-sm font-medium text-text-secondary\">\n {tr(\"auth.sso.statusLabel\", \"SSO connection\")}\n </p>\n <p className=\"mt-1 text-lg font-semibold text-text-primary\">\n {!ssoConfig\n ? tr(\"auth.sso.statusNotConfigured\", \"Not configured yet\")\n : formData.enabled\n ? tr(\n \"auth.sso.statusActive\",\n \"Active — users can sign in via SSO\",\n )\n : tr(\n \"auth.sso.statusConfiguredDisabled\",\n \"Configured but disabled\",\n )}\n </p>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {tr(\n \"auth.sso.statusHint\",\n \"Save a SAML or OIDC configuration below, then enable it to go live.\",\n )}\n </p>\n </div>\n </div>\n </EmphasisPanel>\n\n {/* Admin context banner — shown when scoping SSO config to a specific tenant/org/workspace */}\n {bypassEnterprisePlanGate &&\n (urlTenantId ?? urlOrgId ?? urlWorkspaceId) && (\n <div className=\"mb-6 p-4 rounded-xl bg-status-info-bg-subtle border border-status-info-border\">\n <p className=\"text-sm font-medium text-status-info-text mb-1\">\n {tr(\"auth.sso.adminContext\", \"Configuring SSO for\")}\n </p>\n <div className=\"flex flex-wrap gap-4 text-xs text-status-info-text\">\n {urlTenantId && (\n <span>\n <span className=\"font-medium\">\n {tr(\"auth.sso.tenant\", \"Tenant:\")}\n </span>{\" \"}\n <code className=\"font-mono\">{urlTenantId}</code>\n </span>\n )}\n {urlOrgId && (\n <span>\n <span className=\"font-medium\">\n {tr(\"auth.sso.organization\", \"Organization:\")}\n </span>{\" \"}\n <code className=\"font-mono\">{urlOrgId}</code>\n </span>\n )}\n {urlWorkspaceId && (\n <span>\n <span className=\"font-medium\">\n {tr(\"auth.sso.workspace\", \"Workspace:\")}\n </span>{\" \"}\n <code className=\"font-mono\">{urlWorkspaceId}</code>\n </span>\n )}\n </div>\n </div>\n )}\n\n {/* Alerts */}\n {error && (\n <div className=\"mb-6 flex items-start gap-3 p-4 rounded-xl bg-status-error-bg-subtle border border-status-error-border\">\n <AlertIcon className=\"size-5 text-status-error-text flex-shrink-0 mt-0.5\" />\n <div className=\"flex-1\">\n <p className=\"text-sm text-status-error-text\">{error}</p>\n <button\n type=\"button\"\n onClick={() => setError(null)}\n className=\"mt-2 text-sm text-status-error-text hover:underline\"\n >\n {tr(\"auth.sso.dismiss\", \"Dismiss\")}\n </button>\n </div>\n </div>\n )}\n\n {success && (\n <div className=\"mb-6 flex items-start gap-3 p-4 rounded-xl bg-status-success-bg-subtle border border-status-success-border\">\n <svg\n className=\"size-5 text-status-success-text flex-shrink-0 mt-0.5\"\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\"\n clipRule=\"evenodd\"\n />\n </svg>\n <div className=\"flex-1\">\n <p className=\"text-sm text-status-success-text\">{success}</p>\n <button\n type=\"button\"\n onClick={() => setSuccess(null)}\n className=\"mt-2 text-sm text-status-success-text hover:underline\"\n >\n {tr(\"auth.sso.dismiss\", \"Dismiss\")}\n </button>\n </div>\n </div>\n )}\n\n {/* Tabs */}\n <div className=\"mb-6 border-b border-border-subtle\">\n <nav className=\"flex gap-6\">\n {[\n {\n id: \"saml\",\n label: tr(\"auth.sso.samlTab\", \"SAML 2.0\"),\n icon: \"🔐\",\n },\n {\n id: \"oidc\",\n label: tr(\"auth.sso.oidcTab\", \"OIDC Provider\"),\n icon: \"🌐\",\n },\n {\n id: \"clients\",\n label: tr(\"auth.sso.clientsTab\", \"OIDC Clients\"),\n icon: \"🔑\",\n },\n {\n id: \"test\",\n label: tr(\"auth.sso.testTab\", \"Test SSO\"),\n icon: \"🧪\",\n },\n ].map((tab) => (\n <button\n type=\"button\"\n key={tab.id}\n onClick={() => setActiveTab(tab.id as typeof activeTab)}\n className={`pb-3 text-sm font-medium transition-colors relative ${\n activeTab === tab.id\n ? \"text-text-link\"\n : \"text-text-secondary hover:text-text-primary\"\n }`}\n >\n <span className=\"flex items-center gap-2\">\n <span>{tab.icon}</span>\n {tab.label}\n </span>\n {activeTab === tab.id && (\n <span className=\"absolute bottom-0 left-0 right-0 h-0.5 bg-action-primary-bg\" />\n )}\n </button>\n ))}\n </nav>\n </div>\n\n {/* Loading */}\n {isLoading && (\n <div className=\"flex items-center justify-center py-12\">\n <SpinnerIcon className=\"size-8 text-text-link animate-spin\" />\n <span className=\"ml-3 text-text-secondary\">\n {tr(\"auth.sso.loadingConfig\", \"Loading configuration...\")}\n </span>\n </div>\n )}\n\n {/* SAML Configuration Tab */}\n {!isLoading && activeTab === \"saml\" && (\n <div className=\"space-y-6\">\n {/* Info Card */}\n <div className=\"p-4 rounded-xl bg-status-info-bg-subtle border border-status-info-border\">\n <h3 className=\"font-medium text-status-info-text mb-2\">\n {tr(\"auth.sso.samlConfigTitle\", \"SAML 2.0 Configuration\")}\n </h3>\n <p className=\"text-sm text-status-info-text\">\n {tr(\n \"auth.sso.samlConfigDesc\",\n \"Configure your Identity Provider (IdP) to enable enterprise SSO. You'll need to get the following information from your IdP (Okta, Azure AD, OneLogin, etc.):\",\n )}\n </p>\n <ul className=\"mt-2 text-sm text-status-info-text list-disc list-inside\">\n <li>{tr(\"auth.sso.entityIdItem\", \"Entity ID (Issuer URL)\")}</li>\n <li>{tr(\"auth.sso.ssoUrlItem\", \"SSO URL (Login URL)\")}</li>\n <li>{tr(\"auth.sso.certificateItem\", \"X.509 Certificate\")}</li>\n </ul>\n </div>\n\n {/* Metadata Import Card */}\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.importMetadata\", \"Import IdP Metadata\")}\n </h3>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n \"auth.sso.importMetadataDesc\",\n \"Automatically configure SSO by importing your IdP's metadata XML file or URL.\",\n )}\n </p>\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n {/* File Upload */}\n <div className=\"space-y-3\">\n <label className=\"block text-sm font-medium text-text-primary\">\n {tr(\"auth.sso.uploadFile\", \"Upload Metadata File\")}\n </label>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".xml,application/xml,text/xml\"\n onChange={handleMetadataFileUpload}\n className=\"hidden\"\n id=\"metadata-file\"\n aria-label={tr(\"auth.sso.uploadFile\", \"Upload Metadata File\")}\n />\n <label\n htmlFor=\"metadata-file\"\n className=\"flex items-center justify-center gap-2 w-full px-4 py-3 border-2 border-dashed border-border-default rounded-xl cursor-pointer hover:border-action-primary-bg transition-colors\"\n >\n {isImporting ? (\n <SpinnerIcon className=\"size-5 animate-spin text-text-link\" />\n ) : (\n <svg\n className=\"size-5 text-text-tertiary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12\"\n />\n </svg>\n )}\n <span className=\"text-sm text-text-secondary\">\n {isImporting\n ? tr(\"auth.sso.importing\", \"Importing...\")\n : tr(\"auth.sso.chooseFile\", \"Choose XML file\")}\n </span>\n </label>\n </div>\n\n {/* URL Fetch */}\n <div className=\"space-y-3\">\n <label className=\"block text-sm font-medium text-text-primary\">\n {tr(\"auth.sso.fetchFromUrl\", \"Fetch from URL\")}\n </label>\n <div className=\"flex gap-2\">\n <input\n id=\"sso-metadata-url\"\n type=\"url\"\n value={metadataUrl}\n onChange={(e) => setMetadataUrl(e.target.value)}\n placeholder=\"https://idp.example.com/metadata.xml\"\n aria-label={tr(\"auth.sso.fetchFromUrl\", \"Fetch from URL\")}\n className=\"flex-1 px-4 py-2.5 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all text-sm\"\n />\n <button\n type=\"button\"\n onClick={handleMetadataUrlFetch}\n disabled={isImporting || !metadataUrl}\n className=\"px-4 py-2.5 rounded-xl bg-action-primary-bg text-white font-medium hover:bg-action-primary-bg-hover disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center gap-2\"\n >\n {isImporting ? (\n <SpinnerIcon className=\"size-4 animate-spin\" />\n ) : (\n <svg\n className=\"size-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\"\n />\n </svg>\n )}\n {tr(\"auth.sso.fetch\", \"Fetch\")}\n </button>\n </div>\n </div>\n </div>\n </div>\n\n {/* SP Metadata Card */}\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.spMetadata\", \"Service Provider (SP) Metadata\")}\n </h3>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n \"auth.sso.spMetadataDesc\",\n \"Provide these values to your Identity Provider when setting up the SAML integration:\",\n )}\n </p>\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr(\"auth.sso.spEntityId\", \"SP Entity ID / Audience URI\")}\n </label>\n <div className=\"flex items-center gap-2\">\n <code className=\"flex-1 px-3 py-2 rounded-lg bg-bg-sunken text-sm text-text-primary font-mono\">\n {window.location.origin}/auth/saml/metadata\n </code>\n <button\n type=\"button\"\n onClick={() =>\n void copyTextWithNative(\n `${window.location.origin}/auth/saml/metadata`,\n )\n }\n className=\"px-3 py-2 rounded-lg border border-border-default text-text-secondary hover:bg-bg-sunken\"\n >\n {tr(\"auth.sso.copy\", \"Copy\")}\n </button>\n </div>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr(\n \"auth.sso.acsUrl\",\n \"Assertion Consumer Service (ACS) URL\",\n )}\n </label>\n <div className=\"flex items-center gap-2\">\n <code className=\"flex-1 px-3 py-2 rounded-lg bg-bg-sunken text-sm text-text-primary font-mono\">\n {window.location.origin}/auth/sso/callback\n </code>\n <button\n type=\"button\"\n onClick={() =>\n void copyTextWithNative(\n `${window.location.origin}/auth/sso/callback`,\n )\n }\n className=\"px-3 py-2 rounded-lg border border-border-default text-text-secondary hover:bg-bg-sunken\"\n >\n {tr(\"auth.sso.copy\", \"Copy\")}\n </button>\n </div>\n </div>\n </div>\n </div>\n\n {/* IdP Configuration Form */}\n <form\n onSubmit={handleSave}\n className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\"\n >\n <div className=\"flex items-center justify-between mb-6\">\n <h3 className=\"text-lg font-medium text-text-primary\">\n {tr(\"auth.sso.idpSettings\", \"Identity Provider (IdP) Settings\")}\n </h3>\n {!isEditing && ssoConfig && (\n <button\n type=\"button\"\n onClick={() => setIsEditing(true)}\n className=\"px-4 py-2 rounded-lg border border-status-info-border text-text-link hover:bg-status-info-bg-subtle text-sm font-medium transition-colors\"\n >\n {tr(\"auth.sso.editConfig\", \"Edit Configuration\")}\n </button>\n )}\n </div>\n\n <div className=\"space-y-5\">\n <div>\n <label\n htmlFor=\"sso-entity-id\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.sso.idpEntityId\", \"IdP Entity ID / Issuer URL\")}{\" \"}\n <span className=\"text-status-error-text\" aria-hidden=\"true\">\n *\n </span>\n </label>\n <input\n id=\"sso-entity-id\"\n type=\"url\"\n aria-label={tr(\"auth.sso.idpEntityId\", \"IdP Entity ID\")}\n value={formData.entityId}\n onChange={(e) =>\n setFormData({ ...formData, entityId: e.target.value })\n }\n disabled={!isEditing && !!ssoConfig}\n placeholder={tr(\n \"auth.sso.idpEntityIdPlaceholder\",\n \"https://your-idp.example.com/saml/metadata\",\n )}\n required\n aria-required=\"true\"\n aria-describedby=\"sso-entity-id-hint\"\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg disabled:opacity-60 disabled:cursor-not-allowed transition-all\"\n />\n <p\n id=\"sso-entity-id-hint\"\n className=\"mt-1 text-xs text-text-secondary\"\n >\n {tr(\n \"auth.sso.idpEntityIdHelper\",\n \"The unique identifier of your Identity Provider\",\n )}\n </p>\n </div>\n\n <div>\n <label\n htmlFor=\"sso-sso-url\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.sso.ssoUrl\", \"SSO URL (Login URL)\")}{\" \"}\n <span className=\"text-status-error-text\" aria-hidden=\"true\">\n *\n </span>\n </label>\n <input\n id=\"sso-sso-url\"\n type=\"url\"\n aria-label={tr(\"auth.sso.ssoUrl\", \"SSO URL\")}\n value={formData.ssoUrl}\n onChange={(e) =>\n setFormData({ ...formData, ssoUrl: e.target.value })\n }\n disabled={!isEditing && !!ssoConfig}\n placeholder={tr(\n \"auth.sso.ssoUrlPlaceholder\",\n \"https://your-idp.example.com/saml/sso\",\n )}\n required\n aria-required=\"true\"\n aria-describedby=\"sso-sso-url-hint\"\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg disabled:opacity-60 disabled:cursor-not-allowed transition-all\"\n />\n <p\n id=\"sso-sso-url-hint\"\n className=\"mt-1 text-xs text-text-secondary\"\n >\n {tr(\n \"auth.sso.ssoUrlHelper\",\n \"The URL where users are redirected to authenticate\",\n )}\n </p>\n </div>\n\n <div>\n <label\n htmlFor=\"sso-certificate\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.sso.certificate\", \"X.509 Certificate\")}{\" \"}\n <span className=\"text-status-error-text\" aria-hidden=\"true\">\n *\n </span>\n </label>\n <textarea\n id=\"sso-certificate\"\n aria-label={tr(\"auth.sso.certificate\", \"X.509 Certificate\")}\n value={formData.certificate}\n onChange={(e) =>\n setFormData({ ...formData, certificate: e.target.value })\n }\n disabled={!isEditing && !!ssoConfig}\n placeholder={tr(\n \"auth.sso.certificatePlaceholder\",\n \"-----BEGIN CERTIFICATE-----\\nMIIDpDCCAoygAwIBAgIGAX...\\n-----END CERTIFICATE-----\",\n )}\n required\n aria-required=\"true\"\n aria-describedby=\"sso-certificate-hint\"\n rows={6}\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg disabled:opacity-60 disabled:cursor-not-allowed transition-all font-mono text-sm\"\n />\n <p\n id=\"sso-certificate-hint\"\n className=\"mt-1 text-xs text-text-secondary\"\n >\n {tr(\n \"auth.sso.certificateHelper\",\n \"The public X.509 certificate from your IdP for signature verification\",\n )}\n </p>\n </div>\n </div>\n\n {(isEditing || !ssoConfig) && (\n <div className=\"mt-6 flex items-center gap-3\">\n <Button\n type=\"submit\"\n disabled={isSaving}\n variant=\"default\"\n size=\"lg\"\n className=\"font-semibold\"\n >\n {isSaving ? (\n <>\n <SpinnerIcon className=\"size-4 animate-spin\" />\n {tr(\"auth.sso.saving\", \"Saving...\")}\n </>\n ) : (\n tr(\"auth.sso.saveConfig\", \"Save Configuration\")\n )}\n </Button>\n {isEditing && (\n <button\n type=\"button\"\n onClick={() => {\n setIsEditing(false);\n if (ssoConfig) {\n setFormData({\n entityId: ssoConfig.entityId || \"\",\n ssoUrl: ssoConfig.ssoUrl || \"\",\n sloUrl: ssoConfig.sloUrl || \"\",\n certificate: ssoConfig.certificate || \"\",\n enabled: ssoConfig.enabled || false,\n });\n }\n }}\n className=\"px-6 py-3 rounded-xl border border-border-default text-text-primary font-medium hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.sso.cancel\", \"Cancel\")}\n </button>\n )}\n </div>\n )}\n </form>\n\n {/* Danger Zone */}\n {ssoConfig && (\n <div className=\"p-6 rounded-xl border border-status-error-border bg-status-error-bg-subtle\">\n <h3 className=\"text-lg font-medium text-status-error-text mb-2\">\n {tr(\"auth.sso.dangerZone\", \"Danger Zone\")}\n </h3>\n <p className=\"text-sm text-status-error-text mb-4\">\n {tr(\n \"auth.sso.dangerZoneDesc\",\n \"Deleting the SSO configuration will prevent users from signing in with their enterprise credentials. This action cannot be undone.\",\n )}\n </p>\n <button\n type=\"button\"\n onClick={() => setShowDeleteDialog(true)}\n disabled={isDeleting}\n className=\"px-4 py-2 rounded-lg bg-status-error-bg text-white font-medium hover:bg-status-error-bg-hover disabled:opacity-50 transition-colors flex items-center gap-2\"\n >\n {isDeleting ? (\n <>\n <SpinnerIcon className=\"size-4 animate-spin\" />\n {tr(\"auth.sso.deleting\", \"Deleting...\")}\n </>\n ) : (\n tr(\"auth.sso.deleteConfig\", \"Delete SSO Configuration\")\n )}\n </button>\n </div>\n )}\n </div>\n )}\n\n {/* OIDC Provider Tab */}\n {!isLoading && activeTab === \"oidc\" && (\n <div className=\"space-y-6\">\n <div className=\"p-4 rounded-xl bg-accent-purple-subtle border border-accent-purple-subtle\">\n <h3 className=\"font-medium text-accent-purple mb-2\">\n {tr(\"auth.sso.oidcProviderInfo\", \"OIDC Provider Information\")}\n </h3>\n <p className=\"text-sm text-accent-purple\">\n {tr(\n \"auth.sso.oidcProviderInfoDesc\",\n \"Your auth service acts as an OpenID Connect Provider. This allows other applications to authenticate users through your system using standard OAuth 2.0/OIDC flows.\",\n )}\n </p>\n </div>\n\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.discoveryEndpoint\", \"Discovery Endpoint\")}\n </h3>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n \"auth.sso.discoveryEndpointDesc\",\n \"Applications can auto-configure by fetching the OpenID Connect Discovery document:\",\n )}\n </p>\n <div className=\"flex items-center gap-2\">\n <code className=\"flex-1 px-3 py-2 rounded-lg bg-bg-sunken text-sm text-text-primary font-mono break-all\">\n {oidcConfig?.issuer\n ? `${oidcConfig.issuer}/.well-known/openid-configuration`\n : \"Discovery endpoint unavailable until OIDC is configured\"}\n </code>\n <button\n type=\"button\"\n onClick={() => {\n const url = oidcConfig?.issuer\n ? `${oidcConfig.issuer}/.well-known/openid-configuration`\n : \"\";\n if (!url) {\n return;\n }\n void copyTextWithNative(url);\n }}\n disabled={!oidcConfig?.issuer}\n className=\"px-3 py-2 rounded-lg border border-border-default text-text-secondary hover:bg-bg-sunken flex-shrink-0\"\n >\n {tr(\"auth.sso.copy\", \"Copy\")}\n </button>\n </div>\n </div>\n\n {oidcConfig && (\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.oidcEndpoints\", \"OIDC Endpoints\")}\n </h3>\n <div className=\"space-y-4\">\n {[\n {\n label: tr(\"auth.sso.issuer\", \"Issuer\"),\n value: oidcConfig.issuer,\n },\n {\n label: tr(\n \"auth.sso.authorizationEndpoint\",\n \"Authorization Endpoint\",\n ),\n value: oidcConfig.authorizationEndpoint,\n },\n {\n label: tr(\"auth.sso.tokenEndpoint\", \"Token Endpoint\"),\n value: oidcConfig.tokenEndpoint,\n },\n {\n label: tr(\"auth.sso.userinfoEndpoint\", \"UserInfo Endpoint\"),\n value: oidcConfig.userinfoEndpoint,\n },\n {\n label: tr(\"auth.sso.jwksUri\", \"JWKS URI\"),\n value: oidcConfig.jwksUri,\n },\n ].map((item) => (\n <div key={item.label} className=\"flex items-start gap-4\">\n <span className=\"w-48 text-sm font-medium text-text-primary flex-shrink-0\">\n {item.label}\n </span>\n <code className=\"text-sm text-text-secondary font-mono break-all\">\n {item.value}\n </code>\n </div>\n ))}\n </div>\n </div>\n )}\n\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.supportedFeatures\", \"Supported Features\")}\n </h3>\n <div className=\"grid grid-cols-2 gap-4\">\n {[\n {\n name: tr(\n \"auth.sso.featAuthCodePkce\",\n \"Authorization Code + PKCE\",\n ),\n status: true,\n },\n {\n name: tr(\"auth.sso.featClientCreds\", \"Client Credentials\"),\n status: true,\n },\n {\n name: tr(\"auth.sso.featDeviceAuth\", \"Device Authorization\"),\n status: true,\n },\n {\n name: tr(\"auth.sso.featRefreshTokens\", \"Refresh Tokens\"),\n status: true,\n },\n {\n name: tr(\n \"auth.sso.featTokenIntrospection\",\n \"Token Introspection\",\n ),\n status: true,\n },\n {\n name: tr(\"auth.sso.featTokenRevocation\", \"Token Revocation\"),\n status: true,\n },\n ].map((feature) => (\n <div key={feature.name} className=\"flex items-center gap-2\">\n <span\n className={`size-2 rounded-full ${feature.status ? \"bg-status-success-text\" : \"bg-bg-sunken\"}`}\n />\n <span className=\"text-sm text-text-primary\">\n {feature.name}\n </span>\n </div>\n ))}\n </div>\n </div>\n </div>\n )}\n\n {/* OIDC Clients Tab */}\n {!isLoading && activeTab === \"clients\" && (\n <div className=\"space-y-6\">\n <div className=\"p-4 rounded-xl bg-status-warning-bg-subtle border border-status-warning-border\">\n <h3 className=\"font-medium text-status-warning-text mb-2\">\n {tr(\"auth.sso.clientManagement\", \"OIDC Client Management\")}\n </h3>\n <p className=\"text-sm text-status-warning-text\">\n {tr(\n \"auth.sso.clientManagementDesc\",\n \"Register applications that can authenticate users through your OIDC provider. Each client gets unique credentials to use in the OAuth 2.0 / OIDC flow.\",\n )}\n </p>\n </div>\n\n {/* Newly Created Client Display */}\n {createdClient && (\n <div className=\"p-6 rounded-xl border-2 border-status-success-border bg-status-success-bg-subtle\">\n <div className=\"flex items-start justify-between mb-4\">\n <div>\n <h3 className=\"text-lg font-medium text-status-success-text\">\n {tr(\n \"auth.sso.clientCreatedTitle\",\n \"Client Created Successfully!\",\n )}\n </h3>\n <p className=\"text-sm text-status-success-text mt-1\">\n {tr(\n \"auth.sso.clientCreatedDesc\",\n \"Save these credentials securely. The client secret will not be shown again.\",\n )}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => setCreatedClient(null)}\n aria-label={tr(\n \"auth.sso.dismissClientCredentials\",\n \"Dismiss\",\n )}\n className=\"text-status-success-text hover:text-status-success-text\"\n >\n <svg\n className=\"size-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n <div className=\"space-y-3\">\n <div>\n <label className=\"block text-xs font-medium text-status-success-text mb-1\">\n {tr(\"auth.sso.clientId\", \"Client ID\")}\n </label>\n <div className=\"flex gap-2\">\n <code className=\"flex-1 px-3 py-2 rounded-lg bg-bg-surface text-sm font-mono border border-status-success-border\">\n {createdClient.client_id}\n </code>\n <button\n type=\"button\"\n onClick={() =>\n void copyTextWithNative(createdClient.client_id)\n }\n className=\"px-3 py-2 rounded-lg bg-status-success-bg text-white text-sm hover:bg-status-success-bg\"\n >\n {tr(\"auth.sso.copy\", \"Copy\")}\n </button>\n </div>\n </div>\n {createdClient.client_secret && (\n <div>\n <label className=\"block text-xs font-medium text-status-success-text mb-1\">\n {tr(\"auth.sso.clientSecret\", \"Client Secret (save now!)\")}\n </label>\n <div className=\"flex gap-2\">\n <code className=\"flex-1 px-3 py-2 rounded-lg bg-bg-surface text-sm font-mono border border-status-success-border\">\n {createdClient.client_secret}\n </code>\n <button\n type=\"button\"\n onClick={() =>\n void copyTextWithNative(\n createdClient.client_secret || \"\",\n )\n }\n className=\"px-3 py-2 rounded-lg bg-status-success-bg text-white text-sm hover:bg-status-success-bg\"\n >\n {tr(\"auth.sso.copy\", \"Copy\")}\n </button>\n </div>\n </div>\n )}\n <div>\n <label className=\"block text-xs font-medium text-status-success-text mb-1\">\n {tr(\"auth.sso.redirectUris\", \"Redirect URIs\")}\n </label>\n <code className=\"block px-3 py-2 rounded-lg bg-bg-surface text-sm font-mono border border-status-success-border\">\n {createdClient.redirect_uris.join(\", \")}\n </code>\n </div>\n </div>\n </div>\n )}\n\n {/* Register New Client */}\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <div className=\"flex items-center justify-between mb-6\">\n <h3 className=\"text-lg font-medium text-text-primary\">\n {tr(\"auth.sso.registerClient\", \"Register New Client\")}\n </h3>\n {!showClientForm && (\n <button\n type=\"button\"\n onClick={() => setShowClientForm(true)}\n className=\"px-4 py-2 rounded-lg bg-action-primary-bg text-white font-medium hover:bg-action-primary-bg-hover transition-colors flex items-center gap-2\"\n >\n <svg\n className=\"size-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 4v16m8-8H4\"\n />\n </svg>\n {tr(\"auth.sso.newClient\", \"New Client\")}\n </button>\n )}\n </div>\n\n {showClientForm ? (\n <div className=\"space-y-5\">\n <div>\n <label\n htmlFor=\"oidc-client-name\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.sso.clientName\", \"Client Name\")}{\" \"}\n <span className=\"text-status-error-text\" aria-hidden=\"true\">\n *\n </span>\n </label>\n <input\n id=\"oidc-client-name\"\n type=\"text\"\n aria-label={tr(\"auth.sso.oidcClientName\", \"Client Name\")}\n value={newClient.client_name}\n onChange={(e) =>\n setNewClient({\n ...newClient,\n client_name: e.target.value,\n })\n }\n placeholder={tr(\n \"auth.sso.clientNamePlaceholder\",\n \"My Application\",\n )}\n aria-required=\"true\"\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n </div>\n\n <div>\n <label\n htmlFor=\"oidc-redirect-uris\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.sso.redirectUris\", \"Redirect URIs\")}{\" \"}\n <span className=\"text-status-error-text\" aria-hidden=\"true\">\n *\n </span>\n </label>\n <input\n id=\"oidc-redirect-uris\"\n type=\"text\"\n aria-label={tr(\n \"auth.sso.oidcRedirectUris\",\n \"Redirect URIs\",\n )}\n value={newClient.redirect_uris}\n onChange={(e) =>\n setNewClient({\n ...newClient,\n redirect_uris: e.target.value,\n })\n }\n placeholder={tr(\n \"auth.sso.redirectUrisPlaceholder\",\n \"http://localhost:3000/callback, https://app.example.com/callback\",\n )}\n aria-required=\"true\"\n aria-describedby=\"oidc-redirect-uris-hint\"\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n <p\n id=\"oidc-redirect-uris-hint\"\n className=\"mt-1 text-xs text-text-secondary\"\n >\n {tr(\n \"auth.sso.redirectUrisHelper\",\n \"Separate multiple URIs with commas\",\n )}\n </p>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n {tr(\"auth.sso.grantTypes\", \"Grant Types\")}\n </label>\n <div className=\"flex flex-wrap gap-3\">\n {[\n \"authorization_code\",\n \"refresh_token\",\n \"client_credentials\",\n ].map((grant) => (\n <label\n key={grant}\n className=\"flex items-center gap-2 cursor-pointer\"\n >\n <input\n type=\"checkbox\"\n aria-label={grant}\n checked={newClient.grant_types.includes(grant)}\n onChange={(e) => {\n if (e.target.checked) {\n setNewClient({\n ...newClient,\n grant_types: [...newClient.grant_types, grant],\n });\n } else {\n setNewClient({\n ...newClient,\n grant_types: newClient.grant_types.filter(\n (g) => g !== grant,\n ),\n });\n }\n }}\n className=\"size-4 rounded border-border-default text-text-link focus:ring-action-primary-bg\"\n />\n <span className=\"text-sm text-text-primary\">\n {grant.replace(/_/g, \" \")}\n </span>\n </label>\n ))}\n </div>\n </div>\n\n <div>\n <label\n htmlFor=\"oidc-token-auth-method\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\n \"auth.sso.tokenEndpointAuth\",\n \"Token Endpoint Auth Method\",\n )}\n </label>\n <select\n id=\"oidc-token-auth-method\"\n value={newClient.token_endpoint_auth_method}\n onChange={(e) =>\n setNewClient({\n ...newClient,\n token_endpoint_auth_method: e.target.value,\n })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n >\n <option value=\"none\">\n {tr(\n \"auth.sso.tokenAuthNone\",\n \"None (Public Client - SPAs, Mobile Apps)\",\n )}\n </option>\n <option value=\"client_secret_basic\">\n {tr(\"auth.sso.tokenAuthBasic\", \"Client Secret Basic\")}\n </option>\n <option value=\"client_secret_post\">\n {tr(\"auth.sso.tokenAuthPost\", \"Client Secret Post\")}\n </option>\n </select>\n </div>\n\n <div className=\"flex items-center gap-3 pt-2\">\n <Button\n type=\"button\"\n onClick={handleRegisterClient}\n disabled={isCreatingClient}\n variant=\"default\"\n size=\"lg\"\n className=\"font-semibold\"\n >\n {isCreatingClient ? (\n <>\n <SpinnerIcon className=\"size-4 animate-spin\" />\n {tr(\"auth.sso.registering\", \"Registering...\")}\n </>\n ) : (\n tr(\"auth.sso.registerClientButton\", \"Register Client\")\n )}\n </Button>\n <button\n type=\"button\"\n onClick={() => {\n setShowClientForm(false);\n setNewClient({\n client_name: \"\",\n redirect_uris: \"\",\n grant_types: [\"authorization_code\", \"refresh_token\"],\n token_endpoint_auth_method: \"none\",\n });\n }}\n className=\"px-6 py-3 rounded-xl border border-border-default text-text-primary font-medium hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.sso.cancel\", \"Cancel\")}\n </button>\n </div>\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title={tr(\"auth.sso.emptyClientsTitle\", \"No client apps yet\")}\n description={tr(\n \"auth.sso.emptyClients\",\n 'Click \"New Client\" to register an OAuth 2.0 / OIDC client application.',\n )}\n />\n )}\n </div>\n\n {/* Default Clients Info */}\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.preconfiguredClients\", \"Pre-configured Clients\")}\n </h3>\n <div className=\"space-y-4\">\n <div className=\"p-4 rounded-lg bg-bg-canvas/50 border border-border-default\">\n <div className=\"flex items-center justify-between mb-2\">\n <span className=\"font-medium text-text-primary\">\n tenant-frontend\n </span>\n <span className=\"px-2 py-1 rounded-full text-xs bg-status-success-bg-subtle text-status-success-text\">\n {tr(\"auth.sso.active\", \"Active\")}\n </span>\n </div>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"auth.sso.preconfigClientDesc\",\n \"Default frontend client for tenant authentication\",\n )}\n </p>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n <span className=\"px-2 py-0.5 rounded bg-bg-sunken text-xs text-text-primary\">\n authorization_code\n </span>\n <span className=\"px-2 py-0.5 rounded bg-bg-sunken text-xs text-text-primary\">\n refresh_token\n </span>\n <span className=\"px-2 py-0.5 rounded bg-bg-sunken text-xs text-text-primary\">\n {tr(\"auth.sso.pkceRequired\", \"PKCE required\")}\n </span>\n </div>\n </div>\n </div>\n </div>\n </div>\n )}\n\n {/* Test SSO Tab */}\n {!isLoading && activeTab === \"test\" && (\n <div className=\"space-y-6\">\n <div className=\"p-4 rounded-xl bg-status-warning-bg-subtle border border-status-warning-border\">\n <h3 className=\"font-medium text-status-warning-text mb-2\">\n {tr(\"auth.sso.testLoginTitle\", \"Test SSO Login\")}\n </h3>\n <p className=\"text-sm text-status-warning-text\">\n {tr(\n \"auth.sso.testLoginDesc\",\n \"Use this section to test your SSO configuration before rolling it out to users. Make sure your IdP is properly configured with the SP metadata above.\",\n )}\n </p>\n </div>\n\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.spInitiatedTest\", \"SP-Initiated Login Test\")}\n </h3>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n \"auth.sso.spInitiatedTestDesc\",\n \"Click the button below to initiate an SSO login flow. You will be redirected to your IdP to authenticate.\",\n )}\n </p>\n\n {ssoConfig && ssoConfig.enabled ? (\n <a\n href={`${window.location.origin}/auth/sso/login`}\n className=\"inline-flex items-center gap-2 px-6 py-3 rounded-xl bg-status-success-bg text-white font-medium shadow-sm hover:opacity-90 transition-all duration-200\"\n >\n <svg\n className=\"size-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1\"\n />\n </svg>\n {tr(\"auth.sso.testSsoLoginButton\", \"Test SSO Login\")}\n </a>\n ) : (\n <div className=\"p-4 rounded-xl bg-bg-sunken/50 text-text-secondary text-sm\">\n {!ssoConfig\n ? tr(\n \"auth.sso.notConfigured\",\n \"SSO is not configured. Please configure your IdP settings first.\",\n )\n : tr(\n \"auth.sso.disabledTest\",\n \"SSO is disabled. Enable it to test the login flow.\",\n )}\n </div>\n )}\n </div>\n\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.testResults\", \"Test Results\")}\n </h3>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"auth.sso.testResultsDesc\",\n \"After testing, results will appear here. Check the browser console for detailed logs.\",\n )}\n </p>\n </div>\n </div>\n )}\n\n <NextSteps\n className=\"mt-8\"\n storageKey=\"auth-sso-config\"\n steps={[\n {\n id: \"save-config\",\n label: tr(\"auth.sso.nextSave\", \"Save your IdP configuration\"),\n description: tr(\n \"auth.sso.nextSaveDesc\",\n \"Enter your SAML or OIDC details, then save so the connection exists.\",\n ),\n done: Boolean(ssoConfig),\n },\n {\n id: \"enable-sso\",\n label: tr(\"auth.sso.nextEnable\", \"Enable SSO for sign-in\"),\n description: tr(\n \"auth.sso.nextEnableDesc\",\n \"Flip the connection on once you've confirmed the settings.\",\n ),\n done: Boolean(ssoConfig && formData.enabled),\n onClick: () => {\n if (ssoConfig && !formData.enabled) void handleToggleEnabled();\n },\n },\n {\n id: \"test-login\",\n label: tr(\"auth.sso.nextTest\", \"Test the login flow\"),\n description: tr(\n \"auth.sso.nextTestDesc\",\n \"Run a test sign-in before rolling SSO out to your whole team.\",\n ),\n href:\n ssoConfig && ssoConfig.enabled\n ? `${window.location.origin}/auth/sso/login`\n : undefined,\n },\n ]}\n />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SsoConfigPage.js","names":[],"sources":["../../../src/auth/pages/SsoConfigPage.tsx"],"sourcesContent":["import { useState, useEffect, useRef } from \"react\";\nimport { useNavigate, useSearchParams } from \"react-router\";\nimport { useAuthPermissions } from \"../hooks/useAuthPermissions\";\nimport { useTr } from \"../../shared/hooks/useTr\";\nimport { useFeatureFlagDetails } from \"@burdenoff/fe-libs/shared/feature-flags\";\n// TODO(ux-sweep): wrap \"Advanced SAML / OIDC overrides\" (signing/encryption/\n// nameID-format/attribute-mapping) fields in <OptionalFields> once the\n// SsoConfigPage tabbed form is refactored away from raw tabs. The page is\n// 1700+ lines with no obvious mid-form advanced section to wrap today.\nimport {\n EmphasisPanel,\n IllustratedEmptyState,\n PagePurpose,\n NextSteps,\n} from \"@burdenoff/fe-libs/ui\";\nimport { Button } from \"@burdenoff/fe-libs/button\";\nimport { ConfirmActionDialog } from \"../components/ConfirmActionDialog\";\nimport {\n useSsoOperations,\n type SSOConfigInput,\n} from \"../hooks/useSsoOperations\";\nimport { SpinnerIcon, AlertIcon } from \"../components/AuthIcons\";\nimport {\n nativeCopyText,\n nativeImpact,\n nativeNotify,\n} from \"../../utils/nativeBridge\";\n\nconst copyTextWithNative = async (text: string): Promise<void> => {\n void nativeImpact(\"light\");\n const ok = await nativeCopyText(text);\n void nativeNotify(ok ? \"success\" : \"error\");\n};\n\n// =============================================================================\n// SAML Metadata Parser\n// =============================================================================\n\ninterface ParsedSAMLMetadata {\n entityId: string;\n ssoUrl: string;\n sloUrl?: string;\n certificate: string;\n}\n\nfunction parseSAMLMetadata(xmlString: string): ParsedSAMLMetadata | null {\n try {\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlString, \"text/xml\");\n\n // Check for parse errors\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n console.error(\"XML parse error:\", parseError.textContent);\n return null;\n }\n\n // Extract EntityID\n const entityDescriptor = doc.querySelector(\"EntityDescriptor\");\n const entityId = entityDescriptor?.getAttribute(\"entityID\") || \"\";\n\n // Find IDPSSODescriptor\n const idpDescriptor = doc.querySelector(\"IDPSSODescriptor\");\n if (!idpDescriptor) {\n console.error(\"No IDPSSODescriptor found\");\n return null;\n }\n\n // Extract SSO URL (HTTP-Redirect or HTTP-POST binding)\n const ssoServices = idpDescriptor.querySelectorAll(\"SingleSignOnService\");\n let ssoUrl = \"\";\n for (const service of ssoServices) {\n const binding = service.getAttribute(\"Binding\") || \"\";\n if (binding.includes(\"HTTP-Redirect\") || binding.includes(\"HTTP-POST\")) {\n ssoUrl = service.getAttribute(\"Location\") || \"\";\n break;\n }\n }\n\n // Extract SLO URL\n const sloServices = idpDescriptor.querySelectorAll(\"SingleLogoutService\");\n let sloUrl = \"\";\n for (const service of sloServices) {\n const binding = service.getAttribute(\"Binding\") || \"\";\n if (binding.includes(\"HTTP-Redirect\") || binding.includes(\"HTTP-POST\")) {\n sloUrl = service.getAttribute(\"Location\") || \"\";\n break;\n }\n }\n\n // Extract Certificate\n const certElement = doc.querySelector(\"X509Certificate\");\n let certificate = certElement?.textContent?.trim() || \"\";\n if (certificate && !certificate.includes(\"-----BEGIN\")) {\n certificate = `-----BEGIN CERTIFICATE-----\\n${certificate}\\n-----END CERTIFICATE-----`;\n }\n\n if (!entityId || !ssoUrl || !certificate) {\n console.error(\"Missing required SAML metadata fields\");\n return null;\n }\n\n return { entityId, ssoUrl, sloUrl, certificate };\n } catch (error) {\n console.error(\"Failed to parse SAML metadata:\", error);\n return null;\n }\n}\n\n// =============================================================================\n// OIDC Client Types\n// =============================================================================\n\ninterface OIDCClient {\n client_id: string;\n client_secret?: string;\n redirect_uris: string[];\n grant_types: string[];\n response_types: string[];\n token_endpoint_auth_method: string;\n client_name?: string;\n registration_access_token?: string;\n}\n\ninterface SsoConfigPageProps {\n /** When true, skips the enterprise-plan gate so admins always see the full UI */\n bypassEnterprisePlanGate?: boolean;\n}\n\n/**\n * SSO Configuration page for managing SAML/OIDC enterprise SSO.\n * Admin only - allows configuring Identity Provider settings.\n * In admin-app context, bypassEnterprisePlanGate=true and tenant/org/workspace\n * scoping is read from URL search params (?tenant=&org=&workspace=).\n */\nexport function SsoConfigPage({\n bypassEnterprisePlanGate = false,\n}: SsoConfigPageProps) {\n const tr = useTr();\n const navigate = useNavigate();\n const [searchParams] = useSearchParams();\n const { canManageSsoConfig, isLoading: permissionsLoading } =\n useAuthPermissions();\n // Enterprise SSO gate: only visible to workspaces on an enterprise plan.\n // When the flag is absent the section is hidden (default-deny).\n // bypassEnterprisePlanGate=true skips this check entirely (admin-app usage).\n const enterpriseSsoFlag = useFeatureFlagDetails(\n \"workspace.auth.enterprise-sso\",\n );\n const isEnterpriseSsoEnabled =\n bypassEnterprisePlanGate || enterpriseSsoFlag?.value === true;\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n // In admin context, read scope from URL params; otherwise use platform default\n const urlTenantId = searchParams.get(\"tenant\");\n const urlOrgId = searchParams.get(\"org\");\n const urlWorkspaceId = searchParams.get(\"workspace\");\n const effectiveTenantId = urlTenantId ?? \"burdenoff.com\";\n\n const {\n ssoConfig,\n oidcConfig,\n isLoading,\n isSaving,\n isDeleting,\n saveSsoConfig,\n deleteSsoConfig,\n } = useSsoOperations(effectiveTenantId);\n\n const [activeTab, setActiveTab] = useState<\n \"saml\" | \"oidc\" | \"clients\" | \"test\"\n >(\"saml\");\n const [isEditing, setIsEditing] = useState(false);\n const [showDeleteDialog, setShowDeleteDialog] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [success, setSuccess] = useState<string | null>(null);\n\n // SAML Metadata import state\n const [metadataUrl, setMetadataUrl] = useState(\"\");\n const [isImporting, setIsImporting] = useState(false);\n\n // OIDC Client registration state\n const [showClientForm, setShowClientForm] = useState(false);\n const [newClient, setNewClient] = useState({\n client_name: \"\",\n redirect_uris: \"\",\n grant_types: [\"authorization_code\", \"refresh_token\"],\n token_endpoint_auth_method: \"none\",\n });\n const [isCreatingClient, setIsCreatingClient] = useState(false);\n const [createdClient, setCreatedClient] = useState<OIDCClient | null>(null);\n\n // Form state for SAML configuration\n const [formData, setFormData] = useState<SSOConfigInput>({\n entityId: \"\",\n ssoUrl: \"\",\n sloUrl: \"\",\n certificate: \"\",\n enabled: false,\n });\n\n // Handle SAML metadata file upload\n const handleMetadataFileUpload = async (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => {\n const file = event.target.files?.[0];\n if (!file) return;\n\n setError(null);\n setIsImporting(true);\n\n try {\n const text = await file.text();\n const parsed = parseSAMLMetadata(text);\n\n if (parsed) {\n setFormData({\n ...formData,\n entityId: parsed.entityId,\n ssoUrl: parsed.ssoUrl,\n sloUrl: parsed.sloUrl || \"\",\n certificate: parsed.certificate,\n });\n setSuccess(\n tr(\n \"auth.sso.importSuccess\",\n \"SAML metadata imported successfully! Review and save the configuration.\",\n ),\n );\n setIsEditing(true);\n } else {\n setError(\n tr(\n \"auth.sso.parseError\",\n \"Failed to parse SAML metadata. Make sure the file contains valid IdP metadata XML.\",\n ),\n );\n }\n } catch {\n setError(tr(\"auth.sso.readError\", \"Failed to read metadata file\"));\n } finally {\n setIsImporting(false);\n if (fileInputRef.current) {\n fileInputRef.current.value = \"\";\n }\n }\n };\n\n // Handle SAML metadata URL fetch\n const handleMetadataUrlFetch = async () => {\n if (!metadataUrl) {\n setError(tr(\"auth.sso.enterUrl\", \"Please enter a metadata URL\"));\n return;\n }\n\n setError(null);\n setIsImporting(true);\n\n try {\n const response = await fetch(metadataUrl);\n if (!response.ok) {\n throw new Error(`Failed to fetch: ${response.statusText}`);\n }\n\n const text = await response.text();\n const parsed = parseSAMLMetadata(text);\n\n if (parsed) {\n setFormData({\n ...formData,\n entityId: parsed.entityId,\n ssoUrl: parsed.ssoUrl,\n sloUrl: parsed.sloUrl || \"\",\n certificate: parsed.certificate,\n });\n setSuccess(\n tr(\n \"auth.sso.importSuccessFromUrl\",\n \"SAML metadata imported successfully! Review and save the configuration.\",\n ),\n );\n setIsEditing(true);\n setMetadataUrl(\"\");\n } else {\n setError(\n tr(\n \"auth.sso.parseUrlError\",\n \"Failed to parse SAML metadata from URL.\",\n ),\n );\n }\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"auth.sso.fetchError\", \"Failed to fetch metadata from URL\"),\n );\n } finally {\n setIsImporting(false);\n }\n };\n\n // Register new OIDC client\n const handleRegisterClient = async () => {\n if (!newClient.client_name || !newClient.redirect_uris) {\n setError(\n tr(\n \"auth.sso.clientRequired\",\n \"Client name and redirect URI are required\",\n ),\n );\n return;\n }\n\n setIsCreatingClient(true);\n setError(null);\n\n try {\n const registrationEndpoint = oidcConfig?.registrationEndpoint;\n\n if (!registrationEndpoint) {\n throw new Error(\n tr(\n \"auth.sso.oidcNotConfigured\",\n \"OIDC dynamic client registration is not configured for this environment.\",\n ),\n );\n }\n\n const response = await fetch(registrationEndpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n client_name: newClient.client_name,\n redirect_uris: newClient.redirect_uris\n .split(\",\")\n .map((uri) => uri.trim()),\n grant_types: newClient.grant_types,\n response_types: [\"code\"],\n token_endpoint_auth_method: newClient.token_endpoint_auth_method,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json();\n throw new Error(\n errorData.error_description ||\n errorData.error ||\n \"Registration failed\",\n );\n }\n\n const client = await response.json();\n setCreatedClient(client);\n setSuccess(\n tr(\n \"auth.sso.clientRegistered\",\n \"OIDC client registered successfully! Save the client credentials.\",\n ),\n );\n setShowClientForm(false);\n setNewClient({\n client_name: \"\",\n redirect_uris: \"\",\n grant_types: [\"authorization_code\", \"refresh_token\"],\n token_endpoint_auth_method: \"none\",\n });\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"auth.sso.registerFailed\", \"Failed to register client\"),\n );\n } finally {\n setIsCreatingClient(false);\n }\n };\n\n // Sync form with loaded config\n useEffect(() => {\n if (ssoConfig) {\n setFormData({\n entityId: ssoConfig.entityId || \"\",\n ssoUrl: ssoConfig.ssoUrl || \"\",\n sloUrl: ssoConfig.sloUrl || \"\",\n certificate: ssoConfig.certificate || \"\",\n enabled: ssoConfig.enabled || false,\n });\n }\n }, [ssoConfig]);\n\n const handleSave = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setSuccess(null);\n\n try {\n await saveSsoConfig(formData);\n setSuccess(\n tr(\"auth.sso.saveSuccess\", \"SSO configuration saved successfully!\"),\n );\n setIsEditing(false);\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"auth.sso.saveFailed\", \"Failed to save configuration\"),\n );\n }\n };\n\n const handleDelete = async () => {\n setError(null);\n setSuccess(null);\n void nativeImpact(\"medium\");\n\n try {\n await deleteSsoConfig();\n void nativeNotify(\"success\");\n setSuccess(\n tr(\"auth.sso.deleteSuccess\", \"SSO configuration deleted successfully.\"),\n );\n setShowDeleteDialog(false);\n setFormData({\n entityId: \"\",\n ssoUrl: \"\",\n sloUrl: \"\",\n certificate: \"\",\n enabled: false,\n });\n } catch (err) {\n void nativeNotify(\"error\");\n setError(\n err instanceof Error\n ? err.message\n : tr(\"auth.sso.deleteFailed\", \"Failed to delete configuration\"),\n );\n }\n };\n\n const handleToggleEnabled = async () => {\n setError(null);\n try {\n await saveSsoConfig({ ...formData, enabled: !formData.enabled });\n setSuccess(\n formData.enabled\n ? tr(\"auth.sso.ssoDisabled\", \"SSO disabled\")\n : tr(\"auth.sso.ssoEnabled\", \"SSO enabled\"),\n );\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"auth.sso.statusUpdateFailed\", \"Failed to update status\"),\n );\n }\n };\n\n if (permissionsLoading) {\n return (\n <div className=\"max-w-5xl mx-auto p-6\">\n <div className=\"text-center py-16\">\n <SpinnerIcon className=\"size-8 mx-auto text-text-secondary animate-spin\" />\n <p className=\"mt-4 text-text-secondary\">\n {tr(\"auth.sso.loadingPermissions\", \"Loading permissions...\")}\n </p>\n </div>\n </div>\n );\n }\n\n if (!canManageSsoConfig) {\n return (\n <div className=\"max-w-5xl mx-auto p-6\">\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title={tr(\"auth.sso.adminRequired\", \"Admin Access Required\")}\n description={tr(\n \"auth.sso.adminRequiredDesc\",\n \"You need administrator privileges to configure SSO settings.\",\n )}\n />\n </div>\n );\n }\n\n // Enterprise SSO is a plan-gated feature. Only show the full configuration\n // to workspaces on an enterprise plan (flag: workspace.auth.enterprise-sso).\n if (!isEnterpriseSsoEnabled) {\n return (\n <div className=\"max-w-5xl mx-auto p-6\">\n <IllustratedEmptyState\n illustration=\"onboarding\"\n title={tr(\n \"auth.sso.enterprisePlanRequired\",\n \"Enterprise Plan Required\",\n )}\n description={\n <>\n {tr(\n \"auth.sso.enterprisePlanRequiredDesc\",\n \"Single Sign-On (SAML / OIDC) configuration is available on the Enterprise plan.\",\n )}{\" \"}\n {tr(\n \"auth.sso.contactSales\",\n \"Contact sales to upgrade your workspace to the Enterprise plan.\",\n )}\n </>\n }\n />\n </div>\n );\n }\n\n return (\n <div className=\"max-w-5xl mx-auto p-6\">\n <ConfirmActionDialog\n open={showDeleteDialog}\n onOpenChange={setShowDeleteDialog}\n title={tr(\"auth.sso.deleteConfirmTitle\", \"Delete SSO configuration?\")}\n description={tr(\n \"auth.sso.deleteConfirmDesc\",\n \"Users will immediately lose the ability to sign in with this SSO setup until a new configuration is saved.\",\n )}\n confirmText={tr(\"auth.sso.deleteConfirmButton\", \"Delete configuration\")}\n variant=\"danger\"\n isPending={isDeleting}\n onConfirm={handleDelete}\n />\n {/* Header */}\n <div className=\"flex items-center justify-between mb-8\">\n <div className=\"flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/security\")}\n aria-label={tr(\"auth.sso.backToSecurity\", \"Back to Security\")}\n className=\"p-2 rounded-lg hover:bg-bg-sunken transition-colors\"\n >\n <svg\n className=\"size-5 text-text-secondary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M10 19l-7-7m0 0l7-7m-7 7h18\"\n />\n </svg>\n </button>\n <div>\n <h1 className=\"text-2xl font-semibold text-text-primary\">\n {tr(\"auth.sso.title\", \"Single Sign-On (SSO)\")}\n </h1>\n <p className=\"text-text-secondary mt-1\">\n {tr(\n \"auth.sso.description\",\n \"Configure enterprise SSO with SAML 2.0 or OIDC\",\n )}\n </p>\n </div>\n </div>\n\n {ssoConfig && (\n <div className=\"flex items-center gap-3\">\n <span\n className={`px-3 py-1 rounded-full text-sm font-medium ${\n formData.enabled\n ? \"bg-status-success-bg-subtle text-status-success-text\"\n : \"bg-bg-sunken text-text-secondary\"\n }`}\n >\n {formData.enabled\n ? tr(\"auth.sso.enabled\", \"Enabled\")\n : tr(\"auth.sso.disabled\", \"Disabled\")}\n </span>\n <button\n type=\"button\"\n onClick={handleToggleEnabled}\n disabled={isSaving}\n className=\"px-4 py-2 rounded-lg border border-border-default text-text-primary hover:bg-bg-sunken transition-colors text-sm font-medium\"\n >\n {formData.enabled\n ? tr(\"auth.sso.disable\", \"Disable\")\n : tr(\"auth.sso.enable\", \"Enable\")}\n </button>\n </div>\n )}\n </div>\n\n <PagePurpose className=\"mb-6\">\n {tr(\n \"auth.sso.purpose\",\n \"Connect your organization's identity provider so your team signs in with their existing corporate credentials. Configure SAML 2.0 or OIDC here, then register the client apps that should accept these logins.\",\n )}\n </PagePurpose>\n\n {/* Emphasis: connection status — the one highlighted zone */}\n <EmphasisPanel className=\"mb-8\">\n <div className=\"flex items-center justify-between gap-4\">\n <div>\n <p className=\"text-sm font-medium text-text-secondary\">\n {tr(\"auth.sso.statusLabel\", \"SSO connection\")}\n </p>\n <p className=\"mt-1 text-lg font-semibold text-text-primary\">\n {!ssoConfig\n ? tr(\"auth.sso.statusNotConfigured\", \"Not configured yet\")\n : formData.enabled\n ? tr(\n \"auth.sso.statusActive\",\n \"Active — users can sign in via SSO\",\n )\n : tr(\n \"auth.sso.statusConfiguredDisabled\",\n \"Configured but disabled\",\n )}\n </p>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {tr(\n \"auth.sso.statusHint\",\n \"Save a SAML or OIDC configuration below, then enable it to go live.\",\n )}\n </p>\n </div>\n </div>\n </EmphasisPanel>\n\n {/* Admin context banner — shown when scoping SSO config to a specific tenant/org/workspace */}\n {bypassEnterprisePlanGate &&\n (urlTenantId ?? urlOrgId ?? urlWorkspaceId) && (\n <div className=\"mb-6 p-4 rounded-xl bg-status-info-bg-subtle border border-status-info-border\">\n <p className=\"text-sm font-medium text-status-info-text mb-1\">\n {tr(\"auth.sso.adminContext\", \"Configuring SSO for\")}\n </p>\n <div className=\"flex flex-wrap gap-4 text-xs text-status-info-text\">\n {urlTenantId && (\n <span>\n <span className=\"font-medium\">\n {tr(\"auth.sso.tenant\", \"Tenant:\")}\n </span>{\" \"}\n <code className=\"font-mono\">{urlTenantId}</code>\n </span>\n )}\n {urlOrgId && (\n <span>\n <span className=\"font-medium\">\n {tr(\"auth.sso.organization\", \"Organization:\")}\n </span>{\" \"}\n <code className=\"font-mono\">{urlOrgId}</code>\n </span>\n )}\n {urlWorkspaceId && (\n <span>\n <span className=\"font-medium\">\n {tr(\"auth.sso.workspace\", \"Workspace:\")}\n </span>{\" \"}\n <code className=\"font-mono\">{urlWorkspaceId}</code>\n </span>\n )}\n </div>\n </div>\n )}\n\n {/* Alerts */}\n {error && (\n <div className=\"mb-6 flex items-start gap-3 p-4 rounded-xl bg-status-error-bg-subtle border border-status-error-border\">\n <AlertIcon className=\"size-5 text-status-error-text flex-shrink-0 mt-0.5\" />\n <div className=\"flex-1\">\n <p className=\"text-sm text-status-error-text\">{error}</p>\n <button\n type=\"button\"\n onClick={() => setError(null)}\n className=\"mt-2 text-sm text-status-error-text hover:underline\"\n >\n {tr(\"auth.sso.dismiss\", \"Dismiss\")}\n </button>\n </div>\n </div>\n )}\n\n {success && (\n <div className=\"mb-6 flex items-start gap-3 p-4 rounded-xl bg-status-success-bg-subtle border border-status-success-border\">\n <svg\n className=\"size-5 text-status-success-text flex-shrink-0 mt-0.5\"\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\"\n clipRule=\"evenodd\"\n />\n </svg>\n <div className=\"flex-1\">\n <p className=\"text-sm text-status-success-text\">{success}</p>\n <button\n type=\"button\"\n onClick={() => setSuccess(null)}\n className=\"mt-2 text-sm text-status-success-text hover:underline\"\n >\n {tr(\"auth.sso.dismiss\", \"Dismiss\")}\n </button>\n </div>\n </div>\n )}\n\n {/* Tabs */}\n <div className=\"mb-6 border-b border-border-subtle\">\n <nav className=\"flex gap-6\">\n {[\n {\n id: \"saml\",\n label: tr(\"auth.sso.samlTab\", \"SAML 2.0\"),\n icon: \"🔐\",\n },\n {\n id: \"oidc\",\n label: tr(\"auth.sso.oidcTab\", \"OIDC Provider\"),\n icon: \"🌐\",\n },\n {\n id: \"clients\",\n label: tr(\"auth.sso.clientsTab\", \"OIDC Clients\"),\n icon: \"🔑\",\n },\n {\n id: \"test\",\n label: tr(\"auth.sso.testTab\", \"Test SSO\"),\n icon: \"🧪\",\n },\n ].map((tab) => (\n <button\n type=\"button\"\n key={tab.id}\n onClick={() => setActiveTab(tab.id as typeof activeTab)}\n className={`pb-3 text-sm font-medium transition-colors relative ${\n activeTab === tab.id\n ? \"text-text-link\"\n : \"text-text-secondary hover:text-text-primary\"\n }`}\n >\n <span className=\"flex items-center gap-2\">\n <span>{tab.icon}</span>\n {tab.label}\n </span>\n {activeTab === tab.id && (\n <span className=\"absolute bottom-0 left-0 right-0 h-0.5 bg-action-primary-bg\" />\n )}\n </button>\n ))}\n </nav>\n </div>\n\n {/* Loading */}\n {isLoading && (\n <div className=\"flex items-center justify-center py-12\">\n <SpinnerIcon className=\"size-8 text-text-link animate-spin\" />\n <span className=\"ml-3 text-text-secondary\">\n {tr(\"auth.sso.loadingConfig\", \"Loading configuration...\")}\n </span>\n </div>\n )}\n\n {/* SAML Configuration Tab */}\n {!isLoading && activeTab === \"saml\" && (\n <div className=\"space-y-6\">\n {/* Info Card */}\n <div className=\"p-4 rounded-xl bg-status-info-bg-subtle border border-status-info-border\">\n <h3 className=\"font-medium text-status-info-text mb-2\">\n {tr(\"auth.sso.samlConfigTitle\", \"SAML 2.0 Configuration\")}\n </h3>\n <p className=\"text-sm text-status-info-text\">\n {tr(\n \"auth.sso.samlConfigDesc\",\n \"Configure your Identity Provider (IdP) to enable enterprise SSO. You'll need to get the following information from your IdP (Okta, Azure AD, OneLogin, etc.):\",\n )}\n </p>\n <ul className=\"mt-2 text-sm text-status-info-text list-disc list-inside\">\n <li>{tr(\"auth.sso.entityIdItem\", \"Entity ID (Issuer URL)\")}</li>\n <li>{tr(\"auth.sso.ssoUrlItem\", \"SSO URL (Login URL)\")}</li>\n <li>{tr(\"auth.sso.certificateItem\", \"X.509 Certificate\")}</li>\n </ul>\n </div>\n\n {/* Metadata Import Card */}\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.importMetadata\", \"Import IdP Metadata\")}\n </h3>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n \"auth.sso.importMetadataDesc\",\n \"Automatically configure SSO by importing your IdP's metadata XML file or URL.\",\n )}\n </p>\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n {/* File Upload */}\n <div className=\"space-y-3\">\n <label className=\"block text-sm font-medium text-text-primary\">\n {tr(\"auth.sso.uploadFile\", \"Upload Metadata File\")}\n </label>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".xml,application/xml,text/xml\"\n onChange={handleMetadataFileUpload}\n className=\"hidden\"\n id=\"metadata-file\"\n aria-label={tr(\"auth.sso.uploadFile\", \"Upload Metadata File\")}\n />\n <label\n htmlFor=\"metadata-file\"\n className=\"flex items-center justify-center gap-2 w-full px-4 py-3 border-2 border-dashed border-border-default rounded-xl cursor-pointer hover:border-action-primary-bg transition-colors\"\n >\n {isImporting ? (\n <SpinnerIcon className=\"size-5 animate-spin text-text-link\" />\n ) : (\n <svg\n className=\"size-5 text-text-tertiary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12\"\n />\n </svg>\n )}\n <span className=\"text-sm text-text-secondary\">\n {isImporting\n ? tr(\"auth.sso.importing\", \"Importing...\")\n : tr(\"auth.sso.chooseFile\", \"Choose XML file\")}\n </span>\n </label>\n </div>\n\n {/* URL Fetch */}\n <div className=\"space-y-3\">\n <label className=\"block text-sm font-medium text-text-primary\">\n {tr(\"auth.sso.fetchFromUrl\", \"Fetch from URL\")}\n </label>\n <div className=\"flex gap-2\">\n <input\n id=\"sso-metadata-url\"\n type=\"url\"\n value={metadataUrl}\n onChange={(e) => setMetadataUrl(e.target.value)}\n placeholder=\"https://idp.example.com/metadata.xml\"\n aria-label={tr(\"auth.sso.fetchFromUrl\", \"Fetch from URL\")}\n className=\"flex-1 px-4 py-2.5 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all text-sm\"\n />\n <button\n type=\"button\"\n onClick={handleMetadataUrlFetch}\n disabled={isImporting || !metadataUrl}\n className=\"px-4 py-2.5 rounded-xl bg-action-primary-bg text-white font-medium hover:bg-action-primary-bg-hover disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center gap-2\"\n >\n {isImporting ? (\n <SpinnerIcon className=\"size-4 animate-spin\" />\n ) : (\n <svg\n className=\"size-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\"\n />\n </svg>\n )}\n {tr(\"auth.sso.fetch\", \"Fetch\")}\n </button>\n </div>\n </div>\n </div>\n </div>\n\n {/* SP Metadata Card */}\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.spMetadata\", \"Service Provider (SP) Metadata\")}\n </h3>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n \"auth.sso.spMetadataDesc\",\n \"Provide these values to your Identity Provider when setting up the SAML integration:\",\n )}\n </p>\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr(\"auth.sso.spEntityId\", \"SP Entity ID / Audience URI\")}\n </label>\n <div className=\"flex items-center gap-2\">\n <code className=\"flex-1 px-3 py-2 rounded-lg bg-bg-sunken text-sm text-text-primary font-mono\">\n {window.location.origin}/auth/saml/metadata\n </code>\n <button\n type=\"button\"\n onClick={() =>\n void copyTextWithNative(\n `${window.location.origin}/auth/saml/metadata`,\n )\n }\n className=\"px-3 py-2 rounded-lg border border-border-default text-text-secondary hover:bg-bg-sunken\"\n >\n {tr(\"auth.sso.copy\", \"Copy\")}\n </button>\n </div>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr(\n \"auth.sso.acsUrl\",\n \"Assertion Consumer Service (ACS) URL\",\n )}\n </label>\n <div className=\"flex items-center gap-2\">\n <code className=\"flex-1 px-3 py-2 rounded-lg bg-bg-sunken text-sm text-text-primary font-mono\">\n {window.location.origin}/auth/sso/callback\n </code>\n <button\n type=\"button\"\n onClick={() =>\n void copyTextWithNative(\n `${window.location.origin}/auth/sso/callback`,\n )\n }\n className=\"px-3 py-2 rounded-lg border border-border-default text-text-secondary hover:bg-bg-sunken\"\n >\n {tr(\"auth.sso.copy\", \"Copy\")}\n </button>\n </div>\n </div>\n </div>\n </div>\n\n {/* IdP Configuration Form */}\n <form\n onSubmit={handleSave}\n className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\"\n >\n <div className=\"flex items-center justify-between mb-6\">\n <h3 className=\"text-lg font-medium text-text-primary\">\n {tr(\"auth.sso.idpSettings\", \"Identity Provider (IdP) Settings\")}\n </h3>\n {!isEditing && ssoConfig && (\n <button\n type=\"button\"\n onClick={() => setIsEditing(true)}\n className=\"px-4 py-2 rounded-lg border border-status-info-border text-text-link hover:bg-status-info-bg-subtle text-sm font-medium transition-colors\"\n >\n {tr(\"auth.sso.editConfig\", \"Edit Configuration\")}\n </button>\n )}\n </div>\n\n <div className=\"space-y-5\">\n <div>\n <label\n htmlFor=\"sso-entity-id\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.sso.idpEntityId\", \"IdP Entity ID / Issuer URL\")}{\" \"}\n <span className=\"text-status-error-text\" aria-hidden=\"true\">\n *\n </span>\n </label>\n <input\n id=\"sso-entity-id\"\n type=\"url\"\n aria-label={tr(\"auth.sso.idpEntityId\", \"IdP Entity ID\")}\n value={formData.entityId}\n onChange={(e) =>\n setFormData({ ...formData, entityId: e.target.value })\n }\n disabled={!isEditing && !!ssoConfig}\n placeholder={tr(\n \"auth.sso.idpEntityIdPlaceholder\",\n \"https://your-idp.example.com/saml/metadata\",\n )}\n required\n aria-required=\"true\"\n aria-describedby=\"sso-entity-id-hint\"\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg disabled:opacity-60 disabled:cursor-not-allowed transition-all\"\n />\n <p\n id=\"sso-entity-id-hint\"\n className=\"mt-1 text-xs text-text-secondary\"\n >\n {tr(\n \"auth.sso.idpEntityIdHelper\",\n \"The unique identifier of your Identity Provider\",\n )}\n </p>\n </div>\n\n <div>\n <label\n htmlFor=\"sso-sso-url\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.sso.ssoUrl\", \"SSO URL (Login URL)\")}{\" \"}\n <span className=\"text-status-error-text\" aria-hidden=\"true\">\n *\n </span>\n </label>\n <input\n id=\"sso-sso-url\"\n type=\"url\"\n aria-label={tr(\"auth.sso.ssoUrl\", \"SSO URL\")}\n value={formData.ssoUrl}\n onChange={(e) =>\n setFormData({ ...formData, ssoUrl: e.target.value })\n }\n disabled={!isEditing && !!ssoConfig}\n placeholder={tr(\n \"auth.sso.ssoUrlPlaceholder\",\n \"https://your-idp.example.com/saml/sso\",\n )}\n required\n aria-required=\"true\"\n aria-describedby=\"sso-sso-url-hint\"\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg disabled:opacity-60 disabled:cursor-not-allowed transition-all\"\n />\n <p\n id=\"sso-sso-url-hint\"\n className=\"mt-1 text-xs text-text-secondary\"\n >\n {tr(\n \"auth.sso.ssoUrlHelper\",\n \"The URL where users are redirected to authenticate\",\n )}\n </p>\n </div>\n\n <div>\n <label\n htmlFor=\"sso-certificate\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.sso.certificate\", \"X.509 Certificate\")}{\" \"}\n <span className=\"text-status-error-text\" aria-hidden=\"true\">\n *\n </span>\n </label>\n <textarea\n id=\"sso-certificate\"\n aria-label={tr(\"auth.sso.certificate\", \"X.509 Certificate\")}\n value={formData.certificate}\n onChange={(e) =>\n setFormData({ ...formData, certificate: e.target.value })\n }\n disabled={!isEditing && !!ssoConfig}\n placeholder={tr(\n \"auth.sso.certificatePlaceholder\",\n \"-----BEGIN CERTIFICATE-----\\nMIIDpDCCAoygAwIBAgIGAX...\\n-----END CERTIFICATE-----\",\n )}\n required\n aria-required=\"true\"\n aria-describedby=\"sso-certificate-hint\"\n rows={6}\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg disabled:opacity-60 disabled:cursor-not-allowed transition-all font-mono text-sm\"\n />\n <p\n id=\"sso-certificate-hint\"\n className=\"mt-1 text-xs text-text-secondary\"\n >\n {tr(\n \"auth.sso.certificateHelper\",\n \"The public X.509 certificate from your IdP for signature verification\",\n )}\n </p>\n </div>\n </div>\n\n {(isEditing || !ssoConfig) && (\n <div className=\"mt-6 flex items-center gap-3\">\n <Button\n type=\"submit\"\n disabled={isSaving}\n variant=\"default\"\n size=\"lg\"\n className=\"font-semibold\"\n >\n {isSaving ? (\n <>\n <SpinnerIcon className=\"size-4 animate-spin\" />\n {tr(\"auth.sso.saving\", \"Saving...\")}\n </>\n ) : (\n tr(\"auth.sso.saveConfig\", \"Save Configuration\")\n )}\n </Button>\n {isEditing && (\n <button\n type=\"button\"\n onClick={() => {\n setIsEditing(false);\n if (ssoConfig) {\n setFormData({\n entityId: ssoConfig.entityId || \"\",\n ssoUrl: ssoConfig.ssoUrl || \"\",\n sloUrl: ssoConfig.sloUrl || \"\",\n certificate: ssoConfig.certificate || \"\",\n enabled: ssoConfig.enabled || false,\n });\n }\n }}\n className=\"px-6 py-3 rounded-xl border border-border-default text-text-primary font-medium hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.sso.cancel\", \"Cancel\")}\n </button>\n )}\n </div>\n )}\n </form>\n\n {/* Danger Zone */}\n {ssoConfig && (\n <div className=\"p-6 rounded-xl border border-status-error-border bg-status-error-bg-subtle\">\n <h3 className=\"text-lg font-medium text-status-error-text mb-2\">\n {tr(\"auth.sso.dangerZone\", \"Danger Zone\")}\n </h3>\n <p className=\"text-sm text-status-error-text mb-4\">\n {tr(\n \"auth.sso.dangerZoneDesc\",\n \"Deleting the SSO configuration will prevent users from signing in with their enterprise credentials. This action cannot be undone.\",\n )}\n </p>\n <button\n type=\"button\"\n onClick={() => setShowDeleteDialog(true)}\n disabled={isDeleting}\n className=\"px-4 py-2 rounded-lg bg-status-error-bg text-white font-medium hover:bg-status-error-bg-hover disabled:opacity-50 transition-colors flex items-center gap-2\"\n >\n {isDeleting ? (\n <>\n <SpinnerIcon className=\"size-4 animate-spin\" />\n {tr(\"auth.sso.deleting\", \"Deleting...\")}\n </>\n ) : (\n tr(\"auth.sso.deleteConfig\", \"Delete SSO Configuration\")\n )}\n </button>\n </div>\n )}\n </div>\n )}\n\n {/* OIDC Provider Tab */}\n {!isLoading && activeTab === \"oidc\" && (\n <div className=\"space-y-6\">\n <div className=\"p-4 rounded-xl bg-accent-purple-subtle border border-accent-purple-subtle\">\n <h3 className=\"font-medium text-accent-purple mb-2\">\n {tr(\"auth.sso.oidcProviderInfo\", \"OIDC Provider Information\")}\n </h3>\n <p className=\"text-sm text-accent-purple\">\n {tr(\n \"auth.sso.oidcProviderInfoDesc\",\n \"Your auth service acts as an OpenID Connect Provider. This allows other applications to authenticate users through your system using standard OAuth 2.0/OIDC flows.\",\n )}\n </p>\n </div>\n\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.discoveryEndpoint\", \"Discovery Endpoint\")}\n </h3>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n \"auth.sso.discoveryEndpointDesc\",\n \"Applications can auto-configure by fetching the OpenID Connect Discovery document:\",\n )}\n </p>\n <div className=\"flex items-center gap-2\">\n <code className=\"flex-1 px-3 py-2 rounded-lg bg-bg-sunken text-sm text-text-primary font-mono break-all\">\n {oidcConfig?.issuer\n ? `${oidcConfig.issuer}/.well-known/openid-configuration`\n : \"Discovery endpoint unavailable until OIDC is configured\"}\n </code>\n <button\n type=\"button\"\n onClick={() => {\n const url = oidcConfig?.issuer\n ? `${oidcConfig.issuer}/.well-known/openid-configuration`\n : \"\";\n if (!url) {\n return;\n }\n void copyTextWithNative(url);\n }}\n disabled={!oidcConfig?.issuer}\n className=\"px-3 py-2 rounded-lg border border-border-default text-text-secondary hover:bg-bg-sunken flex-shrink-0\"\n >\n {tr(\"auth.sso.copy\", \"Copy\")}\n </button>\n </div>\n </div>\n\n {oidcConfig && (\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.oidcEndpoints\", \"OIDC Endpoints\")}\n </h3>\n <div className=\"space-y-4\">\n {[\n {\n label: tr(\"auth.sso.issuer\", \"Issuer\"),\n value: oidcConfig.issuer,\n },\n {\n label: tr(\n \"auth.sso.authorizationEndpoint\",\n \"Authorization Endpoint\",\n ),\n value: oidcConfig.authorizationEndpoint,\n },\n {\n label: tr(\"auth.sso.tokenEndpoint\", \"Token Endpoint\"),\n value: oidcConfig.tokenEndpoint,\n },\n {\n label: tr(\"auth.sso.userinfoEndpoint\", \"UserInfo Endpoint\"),\n value: oidcConfig.userinfoEndpoint,\n },\n {\n label: tr(\"auth.sso.jwksUri\", \"JWKS URI\"),\n value: oidcConfig.jwksUri,\n },\n ].map((item) => (\n <div key={item.label} className=\"flex items-start gap-4\">\n <span className=\"w-48 text-sm font-medium text-text-primary flex-shrink-0\">\n {item.label}\n </span>\n <code className=\"text-sm text-text-secondary font-mono break-all\">\n {item.value}\n </code>\n </div>\n ))}\n </div>\n </div>\n )}\n\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.supportedFeatures\", \"Supported Features\")}\n </h3>\n <div className=\"grid grid-cols-2 gap-4\">\n {[\n {\n name: tr(\n \"auth.sso.featAuthCodePkce\",\n \"Authorization Code + PKCE\",\n ),\n status: true,\n },\n {\n name: tr(\"auth.sso.featClientCreds\", \"Client Credentials\"),\n status: true,\n },\n {\n name: tr(\"auth.sso.featDeviceAuth\", \"Device Authorization\"),\n status: true,\n },\n {\n name: tr(\"auth.sso.featRefreshTokens\", \"Refresh Tokens\"),\n status: true,\n },\n {\n name: tr(\n \"auth.sso.featTokenIntrospection\",\n \"Token Introspection\",\n ),\n status: true,\n },\n {\n name: tr(\"auth.sso.featTokenRevocation\", \"Token Revocation\"),\n status: true,\n },\n ].map((feature) => (\n <div key={feature.name} className=\"flex items-center gap-2\">\n <span\n className={`size-2 rounded-full ${feature.status ? \"bg-status-success-text\" : \"bg-bg-sunken\"}`}\n />\n <span className=\"text-sm text-text-primary\">\n {feature.name}\n </span>\n </div>\n ))}\n </div>\n </div>\n </div>\n )}\n\n {/* OIDC Clients Tab */}\n {!isLoading && activeTab === \"clients\" && (\n <div className=\"space-y-6\">\n <div className=\"p-4 rounded-xl bg-status-warning-bg-subtle border border-status-warning-border\">\n <h3 className=\"font-medium text-status-warning-text mb-2\">\n {tr(\"auth.sso.clientManagement\", \"OIDC Client Management\")}\n </h3>\n <p className=\"text-sm text-status-warning-text\">\n {tr(\n \"auth.sso.clientManagementDesc\",\n \"Register applications that can authenticate users through your OIDC provider. Each client gets unique credentials to use in the OAuth 2.0 / OIDC flow.\",\n )}\n </p>\n </div>\n\n {/* Newly Created Client Display */}\n {createdClient && (\n <div className=\"p-6 rounded-xl border-2 border-status-success-border bg-status-success-bg-subtle\">\n <div className=\"flex items-start justify-between mb-4\">\n <div>\n <h3 className=\"text-lg font-medium text-status-success-text\">\n {tr(\n \"auth.sso.clientCreatedTitle\",\n \"Client Created Successfully!\",\n )}\n </h3>\n <p className=\"text-sm text-status-success-text mt-1\">\n {tr(\n \"auth.sso.clientCreatedDesc\",\n \"Save these credentials securely. The client secret will not be shown again.\",\n )}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => setCreatedClient(null)}\n aria-label={tr(\n \"auth.sso.dismissClientCredentials\",\n \"Dismiss\",\n )}\n className=\"text-status-success-text hover:text-status-success-text\"\n >\n <svg\n className=\"size-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n <div className=\"space-y-3\">\n <div>\n <label className=\"block text-xs font-medium text-status-success-text mb-1\">\n {tr(\"auth.sso.clientId\", \"Client ID\")}\n </label>\n <div className=\"flex gap-2\">\n <code className=\"flex-1 px-3 py-2 rounded-lg bg-bg-surface text-sm font-mono border border-status-success-border\">\n {createdClient.client_id}\n </code>\n <button\n type=\"button\"\n onClick={() =>\n void copyTextWithNative(createdClient.client_id)\n }\n className=\"px-3 py-2 rounded-lg bg-status-success-bg text-white text-sm hover:bg-status-success-bg\"\n >\n {tr(\"auth.sso.copy\", \"Copy\")}\n </button>\n </div>\n </div>\n {createdClient.client_secret && (\n <div>\n <label className=\"block text-xs font-medium text-status-success-text mb-1\">\n {tr(\"auth.sso.clientSecret\", \"Client Secret (save now!)\")}\n </label>\n <div className=\"flex gap-2\">\n <code className=\"flex-1 px-3 py-2 rounded-lg bg-bg-surface text-sm font-mono border border-status-success-border\">\n {createdClient.client_secret}\n </code>\n <button\n type=\"button\"\n onClick={() =>\n void copyTextWithNative(\n createdClient.client_secret || \"\",\n )\n }\n className=\"px-3 py-2 rounded-lg bg-status-success-bg text-white text-sm hover:bg-status-success-bg\"\n >\n {tr(\"auth.sso.copy\", \"Copy\")}\n </button>\n </div>\n </div>\n )}\n <div>\n <label className=\"block text-xs font-medium text-status-success-text mb-1\">\n {tr(\"auth.sso.redirectUris\", \"Redirect URIs\")}\n </label>\n <code className=\"block px-3 py-2 rounded-lg bg-bg-surface text-sm font-mono border border-status-success-border\">\n {createdClient.redirect_uris.join(\", \")}\n </code>\n </div>\n </div>\n </div>\n )}\n\n {/* Register New Client */}\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <div className=\"flex items-center justify-between mb-6\">\n <h3 className=\"text-lg font-medium text-text-primary\">\n {tr(\"auth.sso.registerClient\", \"Register New Client\")}\n </h3>\n {!showClientForm && (\n <button\n type=\"button\"\n onClick={() => setShowClientForm(true)}\n className=\"px-4 py-2 rounded-lg bg-action-primary-bg text-white font-medium hover:bg-action-primary-bg-hover transition-colors flex items-center gap-2\"\n >\n <svg\n className=\"size-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 4v16m8-8H4\"\n />\n </svg>\n {tr(\"auth.sso.newClient\", \"New Client\")}\n </button>\n )}\n </div>\n\n {showClientForm ? (\n <div className=\"space-y-5\">\n <div>\n <label\n htmlFor=\"oidc-client-name\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.sso.clientName\", \"Client Name\")}{\" \"}\n <span className=\"text-status-error-text\" aria-hidden=\"true\">\n *\n </span>\n </label>\n <input\n id=\"oidc-client-name\"\n type=\"text\"\n aria-label={tr(\"auth.sso.oidcClientName\", \"Client Name\")}\n value={newClient.client_name}\n onChange={(e) =>\n setNewClient({\n ...newClient,\n client_name: e.target.value,\n })\n }\n placeholder={tr(\n \"auth.sso.clientNamePlaceholder\",\n \"My Application\",\n )}\n aria-required=\"true\"\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n </div>\n\n <div>\n <label\n htmlFor=\"oidc-redirect-uris\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.sso.redirectUris\", \"Redirect URIs\")}{\" \"}\n <span className=\"text-status-error-text\" aria-hidden=\"true\">\n *\n </span>\n </label>\n <input\n id=\"oidc-redirect-uris\"\n type=\"text\"\n aria-label={tr(\n \"auth.sso.oidcRedirectUris\",\n \"Redirect URIs\",\n )}\n value={newClient.redirect_uris}\n onChange={(e) =>\n setNewClient({\n ...newClient,\n redirect_uris: e.target.value,\n })\n }\n placeholder={tr(\n \"auth.sso.redirectUrisPlaceholder\",\n \"http://localhost:3000/callback, https://app.example.com/callback\",\n )}\n aria-required=\"true\"\n aria-describedby=\"oidc-redirect-uris-hint\"\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n <p\n id=\"oidc-redirect-uris-hint\"\n className=\"mt-1 text-xs text-text-secondary\"\n >\n {tr(\n \"auth.sso.redirectUrisHelper\",\n \"Separate multiple URIs with commas\",\n )}\n </p>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n {tr(\"auth.sso.grantTypes\", \"Grant Types\")}\n </label>\n <div className=\"flex flex-wrap gap-3\">\n {[\n \"authorization_code\",\n \"refresh_token\",\n \"client_credentials\",\n ].map((grant) => (\n <label\n key={grant}\n className=\"flex items-center gap-2 cursor-pointer\"\n >\n <input\n type=\"checkbox\"\n aria-label={grant}\n checked={newClient.grant_types.includes(grant)}\n onChange={(e) => {\n if (e.target.checked) {\n setNewClient({\n ...newClient,\n grant_types: [...newClient.grant_types, grant],\n });\n } else {\n setNewClient({\n ...newClient,\n grant_types: newClient.grant_types.filter(\n (g) => g !== grant,\n ),\n });\n }\n }}\n className=\"size-4 rounded border-border-default text-text-link focus:ring-action-primary-bg\"\n />\n <span className=\"text-sm text-text-primary\">\n {grant.replace(/_/g, \" \")}\n </span>\n </label>\n ))}\n </div>\n </div>\n\n <div>\n <label\n htmlFor=\"oidc-token-auth-method\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\n \"auth.sso.tokenEndpointAuth\",\n \"Token Endpoint Auth Method\",\n )}\n </label>\n <select\n id=\"oidc-token-auth-method\"\n value={newClient.token_endpoint_auth_method}\n onChange={(e) =>\n setNewClient({\n ...newClient,\n token_endpoint_auth_method: e.target.value,\n })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n >\n <option value=\"none\">\n {tr(\n \"auth.sso.tokenAuthNone\",\n \"None (Public Client - SPAs, Mobile Apps)\",\n )}\n </option>\n <option value=\"client_secret_basic\">\n {tr(\"auth.sso.tokenAuthBasic\", \"Client Secret Basic\")}\n </option>\n <option value=\"client_secret_post\">\n {tr(\"auth.sso.tokenAuthPost\", \"Client Secret Post\")}\n </option>\n </select>\n </div>\n\n <div className=\"flex items-center gap-3 pt-2\">\n <Button\n type=\"button\"\n onClick={handleRegisterClient}\n disabled={isCreatingClient}\n variant=\"default\"\n size=\"lg\"\n className=\"font-semibold\"\n >\n {isCreatingClient ? (\n <>\n <SpinnerIcon className=\"size-4 animate-spin\" />\n {tr(\"auth.sso.registering\", \"Registering...\")}\n </>\n ) : (\n tr(\"auth.sso.registerClientButton\", \"Register Client\")\n )}\n </Button>\n <button\n type=\"button\"\n onClick={() => {\n setShowClientForm(false);\n setNewClient({\n client_name: \"\",\n redirect_uris: \"\",\n grant_types: [\"authorization_code\", \"refresh_token\"],\n token_endpoint_auth_method: \"none\",\n });\n }}\n className=\"px-6 py-3 rounded-xl border border-border-default text-text-primary font-medium hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.sso.cancel\", \"Cancel\")}\n </button>\n </div>\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title={tr(\"auth.sso.emptyClientsTitle\", \"No client apps yet\")}\n description={tr(\n \"auth.sso.emptyClients\",\n 'Click \"New Client\" to register an OAuth 2.0 / OIDC client application.',\n )}\n />\n )}\n </div>\n\n {/* Default Clients Info */}\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.preconfiguredClients\", \"Pre-configured Clients\")}\n </h3>\n <div className=\"space-y-4\">\n <div className=\"p-4 rounded-lg bg-bg-canvas/50 border border-border-default\">\n <div className=\"flex items-center justify-between mb-2\">\n <span className=\"font-medium text-text-primary\">\n tenant-frontend\n </span>\n <span className=\"px-2 py-1 rounded-full text-xs bg-status-success-bg-subtle text-status-success-text\">\n {tr(\"auth.sso.active\", \"Active\")}\n </span>\n </div>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"auth.sso.preconfigClientDesc\",\n \"Default frontend client for tenant authentication\",\n )}\n </p>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n <span className=\"px-2 py-0.5 rounded bg-bg-sunken text-xs text-text-primary\">\n authorization_code\n </span>\n <span className=\"px-2 py-0.5 rounded bg-bg-sunken text-xs text-text-primary\">\n refresh_token\n </span>\n <span className=\"px-2 py-0.5 rounded bg-bg-sunken text-xs text-text-primary\">\n {tr(\"auth.sso.pkceRequired\", \"PKCE required\")}\n </span>\n </div>\n </div>\n </div>\n </div>\n </div>\n )}\n\n {/* Test SSO Tab */}\n {!isLoading && activeTab === \"test\" && (\n <div className=\"space-y-6\">\n <div className=\"p-4 rounded-xl bg-status-warning-bg-subtle border border-status-warning-border\">\n <h3 className=\"font-medium text-status-warning-text mb-2\">\n {tr(\"auth.sso.testLoginTitle\", \"Test SSO Login\")}\n </h3>\n <p className=\"text-sm text-status-warning-text\">\n {tr(\n \"auth.sso.testLoginDesc\",\n \"Use this section to test your SSO configuration before rolling it out to users. Make sure your IdP is properly configured with the SP metadata above.\",\n )}\n </p>\n </div>\n\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.spInitiatedTest\", \"SP-Initiated Login Test\")}\n </h3>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n \"auth.sso.spInitiatedTestDesc\",\n \"Click the button below to initiate an SSO login flow. You will be redirected to your IdP to authenticate.\",\n )}\n </p>\n\n {ssoConfig && ssoConfig.enabled ? (\n <a\n href={`${window.location.origin}/auth/sso/login`}\n className=\"inline-flex items-center gap-2 px-6 py-3 rounded-xl bg-status-success-bg text-white font-medium shadow-sm hover:opacity-90 transition-all duration-200\"\n >\n <svg\n className=\"size-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1\"\n />\n </svg>\n {tr(\"auth.sso.testSsoLoginButton\", \"Test SSO Login\")}\n </a>\n ) : (\n <div className=\"p-4 rounded-xl bg-bg-sunken/50 text-text-secondary text-sm\">\n {!ssoConfig\n ? tr(\n \"auth.sso.notConfigured\",\n \"SSO is not configured. Please configure your IdP settings first.\",\n )\n : tr(\n \"auth.sso.disabledTest\",\n \"SSO is disabled. Enable it to test the login flow.\",\n )}\n </div>\n )}\n </div>\n\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface\">\n <h3 className=\"text-lg font-medium text-text-primary mb-4\">\n {tr(\"auth.sso.testResults\", \"Test Results\")}\n </h3>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"auth.sso.testResultsDesc\",\n \"After testing, results will appear here. Check the browser console for detailed logs.\",\n )}\n </p>\n </div>\n </div>\n )}\n\n <NextSteps\n className=\"mt-8\"\n storageKey=\"auth-sso-config\"\n steps={[\n {\n id: \"save-config\",\n label: tr(\"auth.sso.nextSave\", \"Save your IdP configuration\"),\n description: tr(\n \"auth.sso.nextSaveDesc\",\n \"Enter your SAML or OIDC details, then save so the connection exists.\",\n ),\n done: Boolean(ssoConfig),\n },\n {\n id: \"enable-sso\",\n label: tr(\"auth.sso.nextEnable\", \"Enable SSO for sign-in\"),\n description: tr(\n \"auth.sso.nextEnableDesc\",\n \"Flip the connection on once you've confirmed the settings.\",\n ),\n done: Boolean(ssoConfig && formData.enabled),\n onClick: () => {\n if (ssoConfig && !formData.enabled) void handleToggleEnabled();\n },\n },\n {\n id: \"test-login\",\n label: tr(\"auth.sso.nextTest\", \"Test the login flow\"),\n description: tr(\n \"auth.sso.nextTestDesc\",\n \"Run a test sign-in before rolling SSO out to your whole team.\",\n ),\n href:\n ssoConfig && ssoConfig.enabled\n ? `${window.location.origin}/auth/sso/login`\n : undefined,\n },\n ]}\n />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -3,4 +3,4 @@
3
3
  * Allows users to enter their email/company domain to initiate SSO login
4
4
  * Supports both SAML 2.0 and OIDC authentication methods
5
5
  */
6
- export declare function SsoLoginPage(): import("react").JSX.Element;
6
+ export declare function SsoLoginPage(): import('react').JSX.Element;