@burdenoff/microfe-auth 2026.510.127
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.
- package/README.md +12 -0
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/auth/AuthRoot.d.ts +30 -0
- package/dist/auth/AuthRoot.d.ts.map +1 -0
- package/dist/auth/AuthRoot.js +82 -0
- package/dist/auth/AuthRoot.js.map +1 -0
- package/dist/auth/AuthRoutes.d.ts +29 -0
- package/dist/auth/AuthRoutes.d.ts.map +1 -0
- package/dist/auth/AuthRoutes.js +271 -0
- package/dist/auth/AuthRoutes.js.map +1 -0
- package/dist/auth/components/AuthIcons.d.ts +17 -0
- package/dist/auth/components/AuthIcons.d.ts.map +1 -0
- package/dist/auth/components/AuthIcons.js +197 -0
- package/dist/auth/components/AuthIcons.js.map +1 -0
- package/dist/auth/components/AuthLayout.d.ts +17 -0
- package/dist/auth/components/AuthLayout.d.ts.map +1 -0
- package/dist/auth/components/AuthLayout.js +237 -0
- package/dist/auth/components/AuthLayout.js.map +1 -0
- package/dist/auth/components/CaptchaV2.d.ts +16 -0
- package/dist/auth/components/CaptchaV2.d.ts.map +1 -0
- package/dist/auth/components/CaptchaV2.js +47 -0
- package/dist/auth/components/CaptchaV2.js.map +1 -0
- package/dist/auth/components/ConfirmActionDialog.d.ts +16 -0
- package/dist/auth/components/ConfirmActionDialog.d.ts.map +1 -0
- package/dist/auth/components/ConfirmActionDialog.js +68 -0
- package/dist/auth/components/ConfirmActionDialog.js.map +1 -0
- package/dist/auth/components/index.d.ts +4 -0
- package/dist/auth/components/index.d.ts.map +1 -0
- package/dist/auth/components/profile/UserProfileMenu.d.ts +42 -0
- package/dist/auth/components/profile/UserProfileMenu.d.ts.map +1 -0
- package/dist/auth/components/profile/UserProfileMenu.js +91 -0
- package/dist/auth/components/profile/UserProfileMenu.js.map +1 -0
- package/dist/auth/components/workspace/WorkspaceSelector.d.ts +76 -0
- package/dist/auth/components/workspace/WorkspaceSelector.d.ts.map +1 -0
- package/dist/auth/components/workspace/WorkspaceSelector.js +240 -0
- package/dist/auth/components/workspace/WorkspaceSelector.js.map +1 -0
- package/dist/auth/constants/permissions.d.ts +30 -0
- package/dist/auth/constants/permissions.d.ts.map +1 -0
- package/dist/auth/constants/permissions.js +18 -0
- package/dist/auth/constants/permissions.js.map +1 -0
- package/dist/auth/constants/sessionKeys.d.ts +18 -0
- package/dist/auth/constants/sessionKeys.d.ts.map +1 -0
- package/dist/auth/constants/sessionKeys.js +6 -0
- package/dist/auth/constants/sessionKeys.js.map +1 -0
- package/dist/auth/hooks/index.d.ts +18 -0
- package/dist/auth/hooks/index.d.ts.map +1 -0
- package/dist/auth/hooks/index.js +16 -0
- package/dist/auth/hooks/useAccountOperations.d.ts +19 -0
- package/dist/auth/hooks/useAccountOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useAccountOperations.js +52 -0
- package/dist/auth/hooks/useAccountOperations.js.map +1 -0
- package/dist/auth/hooks/useApiKeyOperations.d.ts +22 -0
- package/dist/auth/hooks/useApiKeyOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useApiKeyOperations.js +4 -0
- package/dist/auth/hooks/useAppOperations.d.ts +26 -0
- package/dist/auth/hooks/useAppOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useAppOperations.js +4 -0
- package/dist/auth/hooks/useAuthOperations.d.ts +57 -0
- package/dist/auth/hooks/useAuthOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useAuthOperations.js +236 -0
- package/dist/auth/hooks/useAuthOperations.js.map +1 -0
- package/dist/auth/hooks/useAuthPermissions.d.ts +20 -0
- package/dist/auth/hooks/useAuthPermissions.d.ts.map +1 -0
- package/dist/auth/hooks/useAuthPermissions.js +22 -0
- package/dist/auth/hooks/useAuthPermissions.js.map +1 -0
- package/dist/auth/hooks/useCaptchaV3.d.ts +13 -0
- package/dist/auth/hooks/useCaptchaV3.d.ts.map +1 -0
- package/dist/auth/hooks/useCaptchaV3.js +19 -0
- package/dist/auth/hooks/useCaptchaV3.js.map +1 -0
- package/dist/auth/hooks/useContextSwitcherData.d.ts +106 -0
- package/dist/auth/hooks/useContextSwitcherData.d.ts.map +1 -0
- package/dist/auth/hooks/useContextSwitcherData.js +466 -0
- package/dist/auth/hooks/useContextSwitcherData.js.map +1 -0
- package/dist/auth/hooks/useDelegationOperations.d.ts +25 -0
- package/dist/auth/hooks/useDelegationOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useDelegationOperations.js +4 -0
- package/dist/auth/hooks/useMfaOperations.d.ts +18 -0
- package/dist/auth/hooks/useMfaOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useMfaOperations.js +103 -0
- package/dist/auth/hooks/useMfaOperations.js.map +1 -0
- package/dist/auth/hooks/useMyWorkspaces.d.ts +45 -0
- package/dist/auth/hooks/useMyWorkspaces.d.ts.map +1 -0
- package/dist/auth/hooks/useMyWorkspaces.js +140 -0
- package/dist/auth/hooks/useMyWorkspaces.js.map +1 -0
- package/dist/auth/hooks/useOAuthOperations.d.ts +19 -0
- package/dist/auth/hooks/useOAuthOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useOAuthOperations.js +103 -0
- package/dist/auth/hooks/useOAuthOperations.js.map +1 -0
- package/dist/auth/hooks/usePasswordOperations.d.ts +13 -0
- package/dist/auth/hooks/usePasswordOperations.d.ts.map +1 -0
- package/dist/auth/hooks/usePasswordOperations.js +56 -0
- package/dist/auth/hooks/usePasswordOperations.js.map +1 -0
- package/dist/auth/hooks/useSessionOperations.d.ts +41 -0
- package/dist/auth/hooks/useSessionOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useSessionOperations.js +59 -0
- package/dist/auth/hooks/useSessionOperations.js.map +1 -0
- package/dist/auth/hooks/useSsoOperations.d.ts +65 -0
- package/dist/auth/hooks/useSsoOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useSsoOperations.js +236 -0
- package/dist/auth/hooks/useSsoOperations.js.map +1 -0
- package/dist/auth/hooks/useTokenRefresh.d.ts +56 -0
- package/dist/auth/hooks/useTokenRefresh.d.ts.map +1 -0
- package/dist/auth/hooks/useTokenRefresh.js +53 -0
- package/dist/auth/hooks/useTokenRefresh.js.map +1 -0
- package/dist/auth/hooks/useUserOperations.d.ts +32 -0
- package/dist/auth/hooks/useUserOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useUserOperations.js +100 -0
- package/dist/auth/hooks/useUserOperations.js.map +1 -0
- package/dist/auth/hooks/useWorkspaceOperations.d.ts +35 -0
- package/dist/auth/hooks/useWorkspaceOperations.d.ts.map +1 -0
- package/dist/auth/hooks/useWorkspaceOperations.js +35 -0
- package/dist/auth/hooks/useWorkspaceOperations.js.map +1 -0
- package/dist/auth/hooks/useWorkspaceToken.d.ts +56 -0
- package/dist/auth/hooks/useWorkspaceToken.d.ts.map +1 -0
- package/dist/auth/hooks/useWorkspaceToken.js +94 -0
- package/dist/auth/hooks/useWorkspaceToken.js.map +1 -0
- package/dist/auth/index.d.ts +63 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +18 -0
- package/dist/auth/pages/ApiKeysPage.d.ts +5 -0
- package/dist/auth/pages/ApiKeysPage.d.ts.map +1 -0
- package/dist/auth/pages/AppsPage.d.ts +5 -0
- package/dist/auth/pages/AppsPage.d.ts.map +1 -0
- package/dist/auth/pages/AuditLogPage.d.ts +5 -0
- package/dist/auth/pages/AuditLogPage.d.ts.map +1 -0
- package/dist/auth/pages/AuditLogPage.js +129 -0
- package/dist/auth/pages/AuditLogPage.js.map +1 -0
- package/dist/auth/pages/DelegationsPage.d.ts +5 -0
- package/dist/auth/pages/DelegationsPage.d.ts.map +1 -0
- package/dist/auth/pages/EmailVerifyPage.d.ts +5 -0
- package/dist/auth/pages/EmailVerifyPage.d.ts.map +1 -0
- package/dist/auth/pages/EmailVerifyPage.js +166 -0
- package/dist/auth/pages/EmailVerifyPage.js.map +1 -0
- package/dist/auth/pages/LoginPage.d.ts +6 -0
- package/dist/auth/pages/LoginPage.d.ts.map +1 -0
- package/dist/auth/pages/LoginPage.js +575 -0
- package/dist/auth/pages/LoginPage.js.map +1 -0
- package/dist/auth/pages/MagicLinkPage.d.ts +6 -0
- package/dist/auth/pages/MagicLinkPage.d.ts.map +1 -0
- package/dist/auth/pages/MagicLinkPage.js +219 -0
- package/dist/auth/pages/MagicLinkPage.js.map +1 -0
- package/dist/auth/pages/MfaSetupPage.d.ts +5 -0
- package/dist/auth/pages/MfaSetupPage.d.ts.map +1 -0
- package/dist/auth/pages/MfaSetupPage.js +341 -0
- package/dist/auth/pages/MfaSetupPage.js.map +1 -0
- package/dist/auth/pages/MfaVerifyPage.d.ts +7 -0
- package/dist/auth/pages/MfaVerifyPage.d.ts.map +1 -0
- package/dist/auth/pages/MfaVerifyPage.js +189 -0
- package/dist/auth/pages/MfaVerifyPage.js.map +1 -0
- package/dist/auth/pages/OAuthCallbackPage.d.ts +7 -0
- package/dist/auth/pages/OAuthCallbackPage.d.ts.map +1 -0
- package/dist/auth/pages/OAuthCallbackPage.js +100 -0
- package/dist/auth/pages/OAuthCallbackPage.js.map +1 -0
- package/dist/auth/pages/PasswordResetPage.d.ts +6 -0
- package/dist/auth/pages/PasswordResetPage.d.ts.map +1 -0
- package/dist/auth/pages/PasswordResetPage.js +352 -0
- package/dist/auth/pages/PasswordResetPage.js.map +1 -0
- package/dist/auth/pages/ReactivatePage.d.ts +6 -0
- package/dist/auth/pages/ReactivatePage.d.ts.map +1 -0
- package/dist/auth/pages/ReactivatePage.js +217 -0
- package/dist/auth/pages/ReactivatePage.js.map +1 -0
- package/dist/auth/pages/RegisterPage.d.ts +5 -0
- package/dist/auth/pages/RegisterPage.d.ts.map +1 -0
- package/dist/auth/pages/RegisterPage.js +439 -0
- package/dist/auth/pages/RegisterPage.js.map +1 -0
- package/dist/auth/pages/SSORelayCallbackPage.d.ts +8 -0
- package/dist/auth/pages/SSORelayCallbackPage.d.ts.map +1 -0
- package/dist/auth/pages/SSORelayCallbackPage.js +48 -0
- package/dist/auth/pages/SSORelayCallbackPage.js.map +1 -0
- package/dist/auth/pages/SSORelayPage.d.ts +18 -0
- package/dist/auth/pages/SSORelayPage.d.ts.map +1 -0
- package/dist/auth/pages/SSORelayPage.js +134 -0
- package/dist/auth/pages/SSORelayPage.js.map +1 -0
- package/dist/auth/pages/SecurityPage.d.ts +5 -0
- package/dist/auth/pages/SecurityPage.d.ts.map +1 -0
- package/dist/auth/pages/SecurityPage.js +587 -0
- package/dist/auth/pages/SecurityPage.js.map +1 -0
- package/dist/auth/pages/SessionBridgePage.d.ts +14 -0
- package/dist/auth/pages/SessionBridgePage.d.ts.map +1 -0
- package/dist/auth/pages/SessionBridgePage.js +231 -0
- package/dist/auth/pages/SessionBridgePage.js.map +1 -0
- package/dist/auth/pages/SessionsPage.d.ts +5 -0
- package/dist/auth/pages/SessionsPage.d.ts.map +1 -0
- package/dist/auth/pages/SessionsPage.js +258 -0
- package/dist/auth/pages/SessionsPage.js.map +1 -0
- package/dist/auth/pages/SsoCallbackPage.d.ts +8 -0
- package/dist/auth/pages/SsoCallbackPage.d.ts.map +1 -0
- package/dist/auth/pages/SsoCallbackPage.js +188 -0
- package/dist/auth/pages/SsoCallbackPage.js.map +1 -0
- package/dist/auth/pages/SsoConfigPage.d.ts +6 -0
- package/dist/auth/pages/SsoConfigPage.d.ts.map +1 -0
- package/dist/auth/pages/SsoConfigPage.js +1144 -0
- package/dist/auth/pages/SsoConfigPage.js.map +1 -0
- package/dist/auth/pages/SsoLoginPage.d.ts +7 -0
- package/dist/auth/pages/SsoLoginPage.d.ts.map +1 -0
- package/dist/auth/pages/SsoLoginPage.js +236 -0
- package/dist/auth/pages/SsoLoginPage.js.map +1 -0
- package/dist/auth/pages/UserDetailsPage.d.ts +11 -0
- package/dist/auth/pages/UserDetailsPage.d.ts.map +1 -0
- package/dist/auth/pages/UserDetailsPage.js +338 -0
- package/dist/auth/pages/UserDetailsPage.js.map +1 -0
- package/dist/auth/pages/UserProfilePage.d.ts +5 -0
- package/dist/auth/pages/UserProfilePage.d.ts.map +1 -0
- package/dist/auth/pages/UserProfilePage.js +445 -0
- package/dist/auth/pages/UserProfilePage.js.map +1 -0
- package/dist/auth/pages/UsersPage.d.ts +5 -0
- package/dist/auth/pages/UsersPage.d.ts.map +1 -0
- package/dist/auth/pages/UsersPage.js +899 -0
- package/dist/auth/pages/UsersPage.js.map +1 -0
- package/dist/auth/providers/AuthProvider.d.ts +18 -0
- package/dist/auth/providers/AuthProvider.d.ts.map +1 -0
- package/dist/auth/providers/AuthProvider.js +36 -0
- package/dist/auth/providers/AuthProvider.js.map +1 -0
- package/dist/auth/providers/CaptchaProvider.d.ts +13 -0
- package/dist/auth/providers/CaptchaProvider.d.ts.map +1 -0
- package/dist/auth/providers/CaptchaProvider.js +21 -0
- package/dist/auth/providers/CaptchaProvider.js.map +1 -0
- package/dist/auth/store/authStore.d.ts +91 -0
- package/dist/auth/store/authStore.d.ts.map +1 -0
- package/dist/auth/store/authStore.js +314 -0
- package/dist/auth/store/authStore.js.map +1 -0
- package/dist/auth/types/index.d.ts +636 -0
- package/dist/auth/types/index.d.ts.map +1 -0
- package/dist/auth/utils/captchaConfig.d.ts +4 -0
- package/dist/auth/utils/captchaConfig.d.ts.map +1 -0
- package/dist/auth/utils/captchaConfig.js +13 -0
- package/dist/auth/utils/captchaConfig.js.map +1 -0
- package/dist/auth/utils/formatters.d.ts +37 -0
- package/dist/auth/utils/formatters.d.ts.map +1 -0
- package/dist/auth/utils/formatters.js +48 -0
- package/dist/auth/utils/formatters.js.map +1 -0
- package/dist/auth/utils/gatewayBaseUrls.d.ts +6 -0
- package/dist/auth/utils/gatewayBaseUrls.d.ts.map +1 -0
- package/dist/auth/utils/gatewayBaseUrls.js +18 -0
- package/dist/auth/utils/gatewayBaseUrls.js.map +1 -0
- package/dist/auth/utils/index.d.ts +3 -0
- package/dist/auth/utils/index.d.ts.map +1 -0
- package/dist/auth/utils/validation.d.ts +30 -0
- package/dist/auth/utils/validation.d.ts.map +1 -0
- package/dist/auth/utils/validation.js +15 -0
- package/dist/auth/utils/validation.js.map +1 -0
- package/dist/dev/main.d.ts +2 -0
- package/dist/dev/main.d.ts.map +1 -0
- package/dist/generated/global-operations.d.ts +2978 -0
- package/dist/generated/global-operations.d.ts.map +1 -0
- package/dist/generated/global-operations.js +944 -0
- package/dist/generated/global-operations.js.map +1 -0
- package/dist/generated/global-types.d.ts +21253 -0
- package/dist/generated/global-types.d.ts.map +1 -0
- package/dist/generated/wspace-operations.d.ts +2 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -0
- package/dist/generated/wspace-types.d.ts +55214 -0
- package/dist/generated/wspace-types.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/microfe-auth.css +3 -0
- package/dist/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js +70 -0
- package/dist/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js.map +1 -0
- package/dist/node_modules/object-assign/index.js +41 -0
- package/dist/node_modules/object-assign/index.js.map +1 -0
- package/dist/node_modules/prop-types/checkPropTypes.js +46 -0
- package/dist/node_modules/prop-types/checkPropTypes.js.map +1 -0
- package/dist/node_modules/prop-types/factoryWithThrowingShims.js +49 -0
- package/dist/node_modules/prop-types/factoryWithThrowingShims.js.map +1 -0
- package/dist/node_modules/prop-types/factoryWithTypeCheckers.js +272 -0
- package/dist/node_modules/prop-types/factoryWithTypeCheckers.js.map +1 -0
- package/dist/node_modules/prop-types/index.js +16 -0
- package/dist/node_modules/prop-types/index.js.map +1 -0
- package/dist/node_modules/prop-types/lib/ReactPropTypesSecret.js +10 -0
- package/dist/node_modules/prop-types/lib/ReactPropTypesSecret.js.map +1 -0
- package/dist/node_modules/prop-types/lib/has.js +10 -0
- package/dist/node_modules/prop-types/lib/has.js.map +1 -0
- package/dist/node_modules/qrcode.react/lib/esm/index.js +959 -0
- package/dist/node_modules/qrcode.react/lib/esm/index.js.map +1 -0
- package/dist/node_modules/react-async-script/lib/esm/async-script-loader.js +114 -0
- package/dist/node_modules/react-async-script/lib/esm/async-script-loader.js.map +1 -0
- package/dist/node_modules/react-google-recaptcha/lib/esm/index.js +8 -0
- package/dist/node_modules/react-google-recaptcha/lib/esm/index.js.map +1 -0
- package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha-wrapper.js +20 -0
- package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha-wrapper.js.map +1 -0
- package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha.js +148 -0
- package/dist/node_modules/react-google-recaptcha/lib/esm/recaptcha.js.map +1 -0
- package/dist/node_modules/react-google-recaptcha-v3/dist/react-google-recaptcha-v3.esm.js +445 -0
- package/dist/node_modules/react-google-recaptcha-v3/dist/react-google-recaptcha-v3.esm.js.map +1 -0
- package/dist/node_modules/react-is/cjs/react-is.development.js +84 -0
- package/dist/node_modules/react-is/cjs/react-is.development.js.map +1 -0
- package/dist/node_modules/react-is/cjs/react-is.production.min.js +64 -0
- package/dist/node_modules/react-is/cjs/react-is.production.min.js.map +1 -0
- package/dist/node_modules/react-is/index.js +12 -0
- package/dist/node_modules/react-is/index.js.map +1 -0
- package/dist/shared/hooks/index.d.ts +7 -0
- package/dist/shared/hooks/index.d.ts.map +1 -0
- package/dist/shared/index.d.ts +6 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/types/index.d.ts +109 -0
- package/dist/shared/types/index.d.ts.map +1 -0
- package/dist/utils/nativeBridge.d.ts +3 -0
- package/dist/utils/nativeBridge.d.ts.map +1 -0
- package/dist/utils/nativeBridge.js +2 -0
- package/package.json +114 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SsoConfigPage.js","names":[],"sources":["../../../src/auth/pages/SsoConfigPage.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport { useAuthPermissions } from \"../hooks\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\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\n/**\n * SSO Configuration page for managing SAML/OIDC enterprise SSO\n * Admin only - allows configuring Identity Provider settings\n */\nexport function SsoConfigPage() {\n const navigate = useNavigate();\n const { canManageSsoConfig, isLoading: permissionsLoading } =\n useAuthPermissions();\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const {\n ssoConfig,\n oidcConfig,\n isLoading,\n isSaving,\n isDeleting,\n saveSsoConfig,\n deleteSsoConfig,\n } = useSsoOperations(\"burdenoff.com\"); // Use your tenant identifier\n\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n },\n [t],\n );\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 \"SAML metadata imported successfully! Review and save the configuration.\",\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=\"w-8 h-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 <div className=\"text-center py-16 border-2 border-dashed border-border-subtle rounded-xl\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-status-error-bg-subtle flex items-center justify-center\">\n <AlertIcon className=\"w-8 h-8 text-status-error-text\" />\n </div>\n <h2 className=\"text-xl font-semibold text-text-primary mb-2\">\n {tr(\"auth.sso.adminRequired\", \"Admin Access Required\")}\n </h2>\n <p className=\"text-text-secondary\">\n {tr(\n \"auth.sso.adminRequiredDesc\",\n \"You need administrator privileges to configure SSO settings.\",\n )}\n </p>\n </div>\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 onClick={() => navigate(\"/auth/security\")}\n className=\"p-2 rounded-lg hover:bg-bg-sunken transition-colors\"\n >\n <svg\n className=\"w-5 h-5 text-text-secondary\"\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=\"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 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 {/* 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=\"w-5 h-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 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=\"w-5 h-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 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 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=\"w-8 h-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 />\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=\"w-5 h-5 animate-spin text-text-link\" />\n ) : (\n <svg\n className=\"w-5 h-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 type=\"url\"\n value={metadataUrl}\n onChange={(e) => setMetadataUrl(e.target.value)}\n placeholder=\"https://idp.example.com/metadata.xml\"\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=\"w-4 h-4 animate-spin\" />\n ) : (\n <svg\n className=\"w-4 h-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 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 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 className=\"block text-sm font-medium text-text-primary mb-2\">\n {tr(\"auth.sso.idpEntityId\", \"IdP Entity ID / Issuer URL\")}{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"url\"\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 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 className=\"mt-1 text-xs text-text-secondary\">\n {tr(\n \"auth.sso.idpEntityIdHelper\",\n \"The unique identifier of your Identity Provider\",\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.ssoUrl\", \"SSO URL (Login URL)\")}{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"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 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 className=\"mt-1 text-xs text-text-secondary\">\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 className=\"block text-sm font-medium text-text-primary mb-2\">\n {tr(\"auth.sso.sloUrl\", \"Single Logout (SLO) URL\")}\n </label>\n <input\n type=\"url\"\n value={formData.sloUrl}\n onChange={(e) =>\n setFormData({ ...formData, sloUrl: e.target.value })\n }\n disabled={!isEditing && !!ssoConfig}\n placeholder={tr(\n \"auth.sso.sloUrlPlaceholder\",\n \"https://your-idp.example.com/saml/slo\",\n )}\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 className=\"mt-1 text-xs text-text-secondary\">\n {tr(\n \"auth.sso.sloUrlHelper\",\n \"Optional: URL for single logout across all applications\",\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.certificate\", \"X.509 Certificate\")}{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <textarea\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 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 className=\"mt-1 text-xs text-text-secondary\">\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 className=\"auth-primary-button flex items-center gap-2 px-6 py-3 font-medium\"\n >\n {isSaving ? (\n <>\n <SpinnerIcon className=\"w-4 h-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 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=\"w-4 h-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 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={`w-2 h-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 onClick={() => setCreatedClient(null)}\n className=\"text-status-success-text hover:text-status-success-text\"\n >\n <svg\n className=\"w-5 h-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 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 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 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=\"w-4 h-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 className=\"block text-sm font-medium text-text-primary mb-2\">\n {tr(\"auth.sso.clientName\", \"Client Name\")}{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"text\"\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 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 className=\"block text-sm font-medium text-text-primary mb-2\">\n {tr(\"auth.sso.redirectUris\", \"Redirect URIs\")}{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"text\"\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 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 className=\"mt-1 text-xs text-text-secondary\">\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 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=\"w-4 h-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 className=\"block text-sm font-medium text-text-primary mb-2\">\n {tr(\n \"auth.sso.tokenEndpointAuth\",\n \"Token Endpoint Auth Method\",\n )}\n </label>\n <select\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 onClick={handleRegisterClient}\n disabled={isCreatingClient}\n className=\"auth-primary-button flex items-center gap-2 px-6 py-3 font-medium\"\n >\n {isCreatingClient ? (\n <>\n <SpinnerIcon className=\"w-4 h-4 animate-spin\" />\n {tr(\"auth.sso.registering\", \"Registering...\")}\n </>\n ) : (\n tr(\"auth.sso.registerClientButton\", \"Register Client\")\n )}\n </button>\n <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 <div className=\"text-center py-8 text-text-secondary\">\n <svg\n className=\"w-12 h-12 mx-auto mb-3 text-text-muted\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z\"\n />\n </svg>\n <p className=\"text-sm\">\n {tr(\n \"auth.sso.emptyClients\",\n 'Click \"New Client\" to register an OAuth 2.0 / OIDC client application.',\n )}\n </p>\n </div>\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-gradient-to-r from-green-600 to-emerald-600 text-white font-medium shadow-lg shadow-green-500/25 hover:shadow-xl hover:shadow-green-500/30 hover:from-green-500 hover:to-emerald-500 transition-all duration-200\"\n >\n <svg\n className=\"w-5 h-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 </div>\n );\n}\n"],"mappings":";;;;;;;;;;;AAgBA,IAAM,IAAqB,OAAO,MAAgC;AAG3D,CAFA,EAAa,QAAQ,EAErB,EADM,MAAM,EAAe,EAAK,GACd,YAAY,QAAQ;;AAc7C,SAAS,EAAkB,GAA8C;AACvE,KAAI;EAEF,IAAM,IADS,IAAI,WAAW,CACX,gBAAgB,GAAW,WAAW,EAGnD,IAAa,EAAI,cAAc,cAAc;AACnD,MAAI,EAEF,QADA,QAAQ,MAAM,oBAAoB,EAAW,YAAY,EAClD;EAKT,IAAM,IADmB,EAAI,cAAc,mBAAmB,EAC3B,aAAa,WAAW,IAAI,IAGzD,IAAgB,EAAI,cAAc,mBAAmB;AAC3D,MAAI,CAAC,EAEH,QADA,QAAQ,MAAM,4BAA4B,EACnC;EAIT,IAAM,IAAc,EAAc,iBAAiB,sBAAsB,EACrE,IAAS;AACb,OAAK,IAAM,KAAW,GAAa;GACjC,IAAM,IAAU,EAAQ,aAAa,UAAU,IAAI;AACnD,OAAI,EAAQ,SAAS,gBAAgB,IAAI,EAAQ,SAAS,YAAY,EAAE;AACtE,QAAS,EAAQ,aAAa,WAAW,IAAI;AAC7C;;;EAKJ,IAAM,IAAc,EAAc,iBAAiB,sBAAsB,EACrE,IAAS;AACb,OAAK,IAAM,KAAW,GAAa;GACjC,IAAM,IAAU,EAAQ,aAAa,UAAU,IAAI;AACnD,OAAI,EAAQ,SAAS,gBAAgB,IAAI,EAAQ,SAAS,YAAY,EAAE;AACtE,QAAS,EAAQ,aAAa,WAAW,IAAI;AAC7C;;;EAMJ,IAAI,IADgB,EAAI,cAAc,kBAAkB,EACzB,aAAa,MAAM,IAAI;AAUtD,SATI,KAAe,CAAC,EAAY,SAAS,aAAa,KACpD,IAAc,gCAAgC,EAAY,+BAGxD,CAAC,KAAY,CAAC,KAAU,CAAC,KAC3B,QAAQ,MAAM,wCAAwC,EAC/C,QAGF;GAAE;GAAU;GAAQ;GAAQ;GAAa;UACzC,GAAO;AAEd,SADA,QAAQ,MAAM,kCAAkC,EAAM,EAC/C;;;AAuBX,SAAgB,IAAgB;CAC9B,IAAM,IAAW,GAAa,EACxB,EAAE,uBAAoB,WAAW,OACrC,GAAoB,EAChB,IAAe,EAAyB,KAAK,EAE7C,EACJ,cACA,eACA,cACA,aACA,eACA,kBACA,uBACE,EAAiB,gBAAgB,EAE/B,EAAE,SAAM,GAAS,EACjB,IAAK,GACR,GAAa,MAA6B;EACzC,IAAM,IAAa,EAAE,EAAI;AACzB,SAAO,MAAe,IAAM,IAAW;IAEzC,CAAC,EAAE,CACJ,EAEK,CAAC,GAAW,KAAgB,EAEhC,OAAO,EACH,CAAC,GAAW,KAAgB,EAAS,GAAM,EAC3C,CAAC,GAAkB,KAAuB,EAAS,GAAM,EACzD,CAAC,GAAO,KAAY,EAAwB,KAAK,EACjD,CAAC,GAAS,KAAc,EAAwB,KAAK,EAGrD,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAa,KAAkB,EAAS,GAAM,EAG/C,CAAC,GAAgB,KAAqB,EAAS,GAAM,EACrD,CAAC,GAAW,KAAgB,EAAS;EACzC,aAAa;EACb,eAAe;EACf,aAAa,CAAC,sBAAsB,gBAAgB;EACpD,4BAA4B;EAC7B,CAAC,EACI,CAAC,GAAkB,KAAuB,EAAS,GAAM,EACzD,CAAC,GAAe,KAAoB,EAA4B,KAAK,EAGrE,CAAC,GAAU,KAAe,EAAyB;EACvD,UAAU;EACV,QAAQ;EACR,QAAQ;EACR,aAAa;EACb,SAAS;EACV,CAAC;AAoSF,QAjHA,QAAgB;AACd,EAAI,KACF,EAAY;GACV,UAAU,EAAU,YAAY;GAChC,QAAQ,EAAU,UAAU;GAC5B,QAAQ,EAAU,UAAU;GAC5B,aAAa,EAAU,eAAe;GACtC,SAAS,EAAU,WAAW;GAC/B,CAAC;IAEH,CAAC,EAAU,CAAC,EAqEX,KAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD,EAAa,WAAU,oDAAqD,CAAA,EAC5E,kBAAC,KAAD;IAAG,WAAU;cACV,EAAG,+BAA+B,yBAAyB;IAC1D,CAAA,CACA;;EACF,CAAA,GAIL,IAsBH,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD;IACE,MAAM;IACN,cAAc;IACd,OAAO,EAAG,+BAA+B,4BAA4B;IACrE,aAAa,EACX,8BACA,6GACD;IACD,aAAa,EAAG,gCAAgC,uBAAuB;IACvE,SAAQ;IACR,WAAW;IACX,WA9Fe,YAAY;AAG1B,KAFL,EAAS,KAAK,EACd,EAAW,KAAK,EACX,EAAa,SAAS;AAE3B,SAAI;AAOF,MANA,MAAM,GAAiB,EAClB,EAAa,UAAU,EAC5B,EACE,EAAG,0BAA0B,0CAA0C,CACxE,EACD,EAAoB,GAAM,EAC1B,EAAY;OACV,UAAU;OACV,QAAQ;OACR,QAAQ;OACR,aAAa;OACb,SAAS;OACV,CAAC;cACK,GAAK;AAEZ,MADK,EAAa,QAAQ,EAC1B,EACE,aAAe,QACX,EAAI,UACJ,EAAG,yBAAyB,iCAAiC,CAClE;;;IAsEC,CAAA;GAEF,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,UAAD;MACE,eAAe,EAAS,iBAAiB;MACzC,WAAU;gBAEV,kBAAC,OAAD;OACE,WAAU;OACV,MAAK;OACL,SAAQ;OACR,QAAO;iBAEP,kBAAC,QAAD;QACE,eAAc;QACd,gBAAe;QACf,aAAa;QACb,GAAE;QACF,CAAA;OACE,CAAA;MACC,CAAA,EACT,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAG,kBAAkB,uBAAuB;MAC1C,CAAA,EACL,kBAAC,KAAD;MAAG,WAAU;gBACV,EACC,wBACA,iDACD;MACC,CAAA,CACA,EAAA,CAAA,CACF;QAEL,KACC,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,QAAD;MACE,WAAW,8CACT,EAAS,UACL,yDACA;gBAGL,EAAS,UACN,EAAG,oBAAoB,UAAU,GACjC,EAAG,qBAAqB,WAAW;MAClC,CAAA,EACP,kBAAC,UAAD;MACE,SAnHgB,YAAY;AACtC,SAAS,KAAK;AACd,WAAI;AAEF,QADA,MAAM,EAAc;SAAE,GAAG;SAAU,SAAS,CAAC,EAAS;SAAS,CAAC,EAChE,EACE,EAAS,UACL,EAAG,wBAAwB,eAAe,GAC1C,EAAG,uBAAuB,cAAc,CAC7C;gBACM,GAAK;AACZ,UACE,aAAe,QACX,EAAI,UACJ,EAAG,+BAA+B,0BAA0B,CACjE;;;MAsGO,UAAU;MACV,WAAU;gBAET,EAAS,UACN,EAAG,oBAAoB,UAAU,GACjC,EAAG,mBAAmB,SAAS;MAC5B,CAAA,CACL;OAEJ;;GAGL,KACC,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAW,WAAU,uDAAwD,CAAA,EAC7E,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBAAkC;MAAU,CAAA,EACzD,kBAAC,UAAD;MACE,eAAe,EAAS,KAAK;MAC7B,WAAU;gBAET,EAAG,oBAAoB,UAAU;MAC3B,CAAA,CACL;OACF;;GAGP,KACC,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KACE,WAAU;KACV,MAAK;KACL,SAAQ;eAER,kBAAC,QAAD;MACE,UAAS;MACT,GAAE;MACF,UAAS;MACT,CAAA;KACE,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBAAoC;MAAY,CAAA,EAC7D,kBAAC,UAAD;MACE,eAAe,EAAW,KAAK;MAC/B,WAAU;gBAET,EAAG,oBAAoB,UAAU;MAC3B,CAAA,CACL;OACF;;GAIR,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eACZ;MACC;OACE,IAAI;OACJ,OAAO,EAAG,oBAAoB,WAAW;OACzC,MAAM;OACP;MACD;OACE,IAAI;OACJ,OAAO,EAAG,oBAAoB,gBAAgB;OAC9C,MAAM;OACP;MACD;OACE,IAAI;OACJ,OAAO,EAAG,uBAAuB,eAAe;OAChD,MAAM;OACP;MACD;OACE,IAAI;OACJ,OAAO,EAAG,oBAAoB,WAAW;OACzC,MAAM;OACP;MACF,CAAC,KAAK,MACL,kBAAC,UAAD;MAEE,eAAe,EAAa,EAAI,GAAuB;MACvD,WAAW,uDACT,MAAc,EAAI,KACd,mBACA;gBANR,CASE,kBAAC,QAAD;OAAM,WAAU;iBAAhB,CACE,kBAAC,QAAD,EAAA,UAAO,EAAI,MAAY,CAAA,EACtB,EAAI,MACA;UACN,MAAc,EAAI,MACjB,kBAAC,QAAD,EAAM,WAAU,+DAAgE,CAAA,CAE3E;QAfF,EAAI,GAeF,CACT;KACE,CAAA;IACF,CAAA;GAGL,KACC,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAa,WAAU,uCAAwC,CAAA,EAC/D,kBAAC,QAAD;KAAM,WAAU;eACb,EAAG,0BAA0B,2BAA2B;KACpD,CAAA,CACH;;GAIP,CAAC,KAAa,MAAc,UAC3B,kBAAC,OAAD;IAAK,WAAU;cAAf;KAEE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,4BAA4B,yBAAyB;QACtD,CAAA;OACL,kBAAC,KAAD;QAAG,WAAU;kBACV,EACC,2BACA,gKACD;QACC,CAAA;OACJ,kBAAC,MAAD;QAAI,WAAU;kBAAd;SACE,kBAAC,MAAD,EAAA,UAAK,EAAG,yBAAyB,yBAAyB,EAAM,CAAA;SAChE,kBAAC,MAAD,EAAA,UAAK,EAAG,uBAAuB,sBAAsB,EAAM,CAAA;SAC3D,kBAAC,MAAD,EAAA,UAAK,EAAG,4BAA4B,oBAAoB,EAAM,CAAA;SAC3D;;OACD;;KAGN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,2BAA2B,sBAAsB;QAClD,CAAA;OACL,kBAAC,KAAD;QAAG,WAAU;kBACV,EACC,+BACA,gFACD;QACC,CAAA;OAEJ,kBAAC,OAAD;QAAK,WAAU;kBAAf,CAEE,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,SAAD;WAAO,WAAU;qBACd,EAAG,uBAAuB,uBAAuB;WAC5C,CAAA;UACR,kBAAC,SAAD;WACE,KAAK;WACL,MAAK;WACL,QAAO;WACP,UAxfiB,OAC/B,MACG;YACH,IAAM,IAAO,EAAM,OAAO,QAAQ;AAC7B,mBAGL;aADA,EAAS,KAAK,EACd,EAAe,GAAK;AAEpB,iBAAI;cAEF,IAAM,IAAS,EADF,MAAM,EAAK,MAAM,CACQ;AAEtC,cAAI,KACF,EAAY;eACV,GAAG;eACH,UAAU,EAAO;eACjB,QAAQ,EAAO;eACf,QAAQ,EAAO,UAAU;eACzB,aAAa,EAAO;eACrB,CAAC,EACF,EACE,EACE,0BACA,0EACD,CACF,EACD,EAAa,GAAK,IAElB,EACE,EACE,uBACA,qFACD,CACF;qBAEG;AACN,gBAAS,EAAG,sBAAsB,+BAA+B,CAAC;uBAC1D;AAER,cADA,EAAe,GAAM,EACjB,EAAa,YACf,EAAa,QAAQ,QAAQ;;;;WAgdnB,WAAU;WACV,IAAG;WACH,CAAA;UACF,kBAAC,SAAD;WACE,SAAQ;WACR,WAAU;qBAFZ,CAIG,IACC,kBAAC,GAAD,EAAa,WAAU,uCAAwC,CAAA,GAE/D,kBAAC,OAAD;YACE,WAAU;YACV,MAAK;YACL,SAAQ;YACR,QAAO;sBAEP,kBAAC,QAAD;aACE,eAAc;aACd,gBAAe;aACf,aAAa;aACb,GAAE;aACF,CAAA;YACE,CAAA,EAER,kBAAC,QAAD;YAAM,WAAU;sBACb,IACG,EAAG,sBAAsB,eAAe,GACxC,EAAG,uBAAuB,kBAAkB;YAC3C,CAAA,CACD;;UACJ;YAGN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,SAAD;UAAO,WAAU;oBACd,EAAG,yBAAyB,iBAAiB;UACxC,CAAA,EACR,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,SAAD;WACE,MAAK;WACL,OAAO;WACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;WAC/C,aAAY;WACZ,WAAU;WACV,CAAA,EACF,kBAAC,UAAD;WACE,MAAK;WACL,SAzfa,YAAY;AACzC,gBAAI,CAAC,GAAa;AAChB,eAAS,EAAG,qBAAqB,8BAA8B,CAAC;AAChE;;AAIF,YADA,EAAS,KAAK,EACd,EAAe,GAAK;AAEpB,gBAAI;aACF,IAAM,IAAW,MAAM,MAAM,EAAY;AACzC,iBAAI,CAAC,EAAS,GACZ,OAAU,MAAM,oBAAoB,EAAS,aAAa;aAI5D,IAAM,IAAS,EADF,MAAM,EAAS,MAAM,CACI;AAEtC,aAAI,KACF,EAAY;cACV,GAAG;cACH,UAAU,EAAO;cACjB,QAAQ,EAAO;cACf,QAAQ,EAAO,UAAU;cACzB,aAAa,EAAO;cACrB,CAAC,EACF,EACE,0EACD,EACD,EAAa,GAAK,EAClB,EAAe,GAAG,IAElB,EACE,EACE,0BACA,0CACD,CACF;qBAEI,GAAK;AACZ,eACE,aAAe,QACX,EAAI,UACJ,EAAG,uBAAuB,oCAAoC,CACnE;sBACO;AACR,eAAe,GAAM;;;WA4cP,UAAU,KAAe,CAAC;WAC1B,WAAU;qBAJZ,CAMG,IACC,kBAAC,GAAD,EAAa,WAAU,wBAAyB,CAAA,GAEhD,kBAAC,OAAD;YACE,WAAU;YACV,MAAK;YACL,SAAQ;YACR,QAAO;sBAEP,kBAAC,QAAD;aACE,eAAc;aACd,gBAAe;aACf,aAAa;aACb,GAAE;aACF,CAAA;YACE,CAAA,EAEP,EAAG,kBAAkB,QAAQ,CACvB;aACL;YACF;WACF;;OACF;;KAGN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,uBAAuB,iCAAiC;QACzD,CAAA;OACL,kBAAC,KAAD;QAAG,WAAU;kBACV,EACC,2BACA,uFACD;QACC,CAAA;OACJ,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;SAAO,WAAU;mBACd,EAAG,uBAAuB,8BAA8B;SACnD,CAAA,EACR,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAhB,CACG,OAAO,SAAS,QAAO,sBACnB;aACP,kBAAC,UAAD;UACE,eACE,KAAK,EACH,GAAG,OAAO,SAAS,OAAO,qBAC3B;UAEH,WAAU;oBAET,EAAG,iBAAiB,OAAO;UACrB,CAAA,CACL;WACF,EAAA,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;SAAO,WAAU;mBACd,EACC,mBACA,uCACD;SACK,CAAA,EACR,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAhB,CACG,OAAO,SAAS,QAAO,qBACnB;aACP,kBAAC,UAAD;UACE,eACE,KAAK,EACH,GAAG,OAAO,SAAS,OAAO,oBAC3B;UAEH,WAAU;oBAET,EAAG,iBAAiB,OAAO;UACrB,CAAA,CACL;WACF,EAAA,CAAA,CACF;;OACF;;KAGN,kBAAC,QAAD;MACE,UApcS,OAAO,MAAuB;AAG/C,OAFA,EAAE,gBAAgB,EAClB,EAAS,KAAK,EACd,EAAW,KAAK;AAEhB,WAAI;AAKF,QAJA,MAAM,EAAc,EAAS,EAC7B,EACE,EAAG,wBAAwB,wCAAwC,CACpE,EACD,EAAa,GAAM;gBACZ,GAAK;AACZ,UACE,aAAe,QACX,EAAI,UACJ,EAAG,uBAAuB,+BAA+B,CAC9D;;;MAqbK,WAAU;gBAFZ;OAIE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAG,wBAAwB,mCAAmC;SAC5D,CAAA,EACJ,CAAC,KAAa,KACb,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAa,GAAK;SACjC,WAAU;mBAET,EAAG,uBAAuB,qBAAqB;SACzC,CAAA,CAEP;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD,EAAA,UAAA;UACE,kBAAC,SAAD;WAAO,WAAU;qBAAjB;YACG,EAAG,wBAAwB,6BAA6B;YAAE;YAC3D,kBAAC,QAAD;aAAM,WAAU;uBAAyB;aAAQ,CAAA;YAC3C;;UACR,kBAAC,SAAD;WACE,MAAK;WACL,OAAO,EAAS;WAChB,WAAW,MACT,EAAY;YAAE,GAAG;YAAU,UAAU,EAAE,OAAO;YAAO,CAAC;WAExD,UAAU,CAAC,KAAa,CAAC,CAAC;WAC1B,aAAa,EACX,mCACA,6CACD;WACD,UAAA;WACA,WAAU;WACV,CAAA;UACF,kBAAC,KAAD;WAAG,WAAU;qBACV,EACC,8BACA,kDACD;WACC,CAAA;UACA,EAAA,CAAA;SAEN,kBAAC,OAAD,EAAA,UAAA;UACE,kBAAC,SAAD;WAAO,WAAU;qBAAjB;YACG,EAAG,mBAAmB,sBAAsB;YAAE;YAC/C,kBAAC,QAAD;aAAM,WAAU;uBAAyB;aAAQ,CAAA;YAC3C;;UACR,kBAAC,SAAD;WACE,MAAK;WACL,OAAO,EAAS;WAChB,WAAW,MACT,EAAY;YAAE,GAAG;YAAU,QAAQ,EAAE,OAAO;YAAO,CAAC;WAEtD,UAAU,CAAC,KAAa,CAAC,CAAC;WAC1B,aAAa,EACX,8BACA,wCACD;WACD,UAAA;WACA,WAAU;WACV,CAAA;UACF,kBAAC,KAAD;WAAG,WAAU;qBACV,EACC,yBACA,qDACD;WACC,CAAA;UACA,EAAA,CAAA;SAEN,kBAAC,OAAD,EAAA,UAAA;UACE,kBAAC,SAAD;WAAO,WAAU;qBACd,EAAG,mBAAmB,0BAA0B;WAC3C,CAAA;UACR,kBAAC,SAAD;WACE,MAAK;WACL,OAAO,EAAS;WAChB,WAAW,MACT,EAAY;YAAE,GAAG;YAAU,QAAQ,EAAE,OAAO;YAAO,CAAC;WAEtD,UAAU,CAAC,KAAa,CAAC,CAAC;WAC1B,aAAa,EACX,8BACA,wCACD;WACD,WAAU;WACV,CAAA;UACF,kBAAC,KAAD;WAAG,WAAU;qBACV,EACC,yBACA,0DACD;WACC,CAAA;UACA,EAAA,CAAA;SAEN,kBAAC,OAAD,EAAA,UAAA;UACE,kBAAC,SAAD;WAAO,WAAU;qBAAjB;YACG,EAAG,wBAAwB,oBAAoB;YAAE;YAClD,kBAAC,QAAD;aAAM,WAAU;uBAAyB;aAAQ,CAAA;YAC3C;;UACR,kBAAC,YAAD;WACE,OAAO,EAAS;WAChB,WAAW,MACT,EAAY;YAAE,GAAG;YAAU,aAAa,EAAE,OAAO;YAAO,CAAC;WAE3D,UAAU,CAAC,KAAa,CAAC,CAAC;WAC1B,aAAa,EACX,mCACA,oFAGD;WACD,UAAA;WACA,MAAM;WACN,WAAU;WACV,CAAA;UACF,kBAAC,KAAD;WAAG,WAAU;qBACV,EACC,8BACA,wEACD;WACC,CAAA;UACA,EAAA,CAAA;SACF;;QAEJ,KAAa,CAAC,MACd,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,UAAD;SACE,MAAK;SACL,UAAU;SACV,WAAU;mBAET,IACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAa,WAAU,wBAAyB,CAAA,EAC/C,EAAG,mBAAmB,YAAY,CAClC,EAAA,CAAA,GAEH,EAAG,uBAAuB,qBAAqB;SAE1C,CAAA,EACR,KACC,kBAAC,UAAD;SACE,MAAK;SACL,eAAe;AAEb,UADA,EAAa,GAAM,EACf,KACF,EAAY;WACV,UAAU,EAAU,YAAY;WAChC,QAAQ,EAAU,UAAU;WAC5B,QAAQ,EAAU,UAAU;WAC5B,aAAa,EAAU,eAAe;WACtC,SAAS,EAAU,WAAW;WAC/B,CAAC;;SAGN,WAAU;mBAET,EAAG,mBAAmB,SAAS;SACzB,CAAA,CAEP;;OAEH;;KAGN,KACC,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,uBAAuB,cAAc;QACtC,CAAA;OACL,kBAAC,KAAD;QAAG,WAAU;kBACV,EACC,2BACA,qIACD;QACC,CAAA;OACJ,kBAAC,UAAD;QACE,eAAe,EAAoB,GAAK;QACxC,UAAU;QACV,WAAU;kBAET,IACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAa,WAAU,wBAAyB,CAAA,EAC/C,EAAG,qBAAqB,cAAc,CACtC,EAAA,CAAA,GAEH,EAAG,yBAAyB,2BAA2B;QAElD,CAAA;OACL;;KAEJ;;GAIP,CAAC,KAAa,MAAc,UAC3B,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,6BAA6B,4BAA4B;OAC1D,CAAA,EACL,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,iCACA,sKACD;OACC,CAAA,CACA;;KAEN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,8BAA8B,qBAAqB;QACpD,CAAA;OACL,kBAAC,KAAD;QAAG,WAAU;kBACV,EACC,kCACA,qFACD;QACC,CAAA;OACJ,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBACb,GAAY,SACT,GAAG,EAAW,OAAO,qCACrB;SACC,CAAA,EACP,kBAAC,UAAD;SACE,eAAe;UACb,IAAM,IAAM,GAAY,SACpB,GAAG,EAAW,OAAO,qCACrB;AACC,eAGA,EAAmB,EAAI;;SAE9B,UAAU,CAAC,GAAY;SACvB,WAAU;mBAET,EAAG,iBAAiB,OAAO;SACrB,CAAA,CACL;;OACF;;KAEL,KACC,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,0BAA0B,iBAAiB;OAC5C,CAAA,EACL,kBAAC,OAAD;OAAK,WAAU;iBACZ;QACC;SACE,OAAO,EAAG,mBAAmB,SAAS;SACtC,OAAO,EAAW;SACnB;QACD;SACE,OAAO,EACL,kCACA,yBACD;SACD,OAAO,EAAW;SACnB;QACD;SACE,OAAO,EAAG,0BAA0B,iBAAiB;SACrD,OAAO,EAAW;SACnB;QACD;SACE,OAAO,EAAG,6BAA6B,oBAAoB;SAC3D,OAAO,EAAW;SACnB;QACD;SACE,OAAO,EAAG,oBAAoB,WAAW;SACzC,OAAO,EAAW;SACnB;QACF,CAAC,KAAK,MACL,kBAAC,OAAD;QAAsB,WAAU;kBAAhC,CACE,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAK;SACD,CAAA,EACP,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAK;SACD,CAAA,CACH;UAPI,EAAK,MAOT,CACN;OACE,CAAA,CACF;;KAGR,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,8BAA8B,qBAAqB;OACpD,CAAA,EACL,kBAAC,OAAD;OAAK,WAAU;iBACZ;QACC;SACE,MAAM,EACJ,6BACA,4BACD;SACD,QAAQ;SACT;QACD;SACE,MAAM,EAAG,4BAA4B,qBAAqB;SAC1D,QAAQ;SACT;QACD;SACE,MAAM,EAAG,2BAA2B,uBAAuB;SAC3D,QAAQ;SACT;QACD;SACE,MAAM,EAAG,8BAA8B,iBAAiB;SACxD,QAAQ;SACT;QACD;SACE,MAAM,EACJ,mCACA,sBACD;SACD,QAAQ;SACT;QACD;SACE,MAAM,EAAG,gCAAgC,mBAAmB;SAC5D,QAAQ;SACT;QACF,CAAC,KAAK,MACL,kBAAC,OAAD;QAAwB,WAAU;kBAAlC,CACE,kBAAC,QAAD,EACE,WAAW,wBAAwB,EAAQ,SAAS,2BAA2B,kBAC/E,CAAA,EACF,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAQ;SACJ,CAAA,CACH;UAPI,EAAQ,KAOZ,CACN;OACE,CAAA,CACF;;KACF;;GAIP,CAAC,KAAa,MAAc,aAC3B,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,6BAA6B,yBAAyB;OACvD,CAAA,EACL,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,iCACA,yJACD;OACC,CAAA,CACA;;KAGL,KACC,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EACC,+BACA,+BACD;QACE,CAAA,EACL,kBAAC,KAAD;QAAG,WAAU;kBACV,EACC,8BACA,8EACD;QACC,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,UAAD;QACE,eAAe,EAAiB,KAAK;QACrC,WAAU;kBAEV,kBAAC,OAAD;SACE,WAAU;SACV,MAAK;SACL,SAAQ;SACR,QAAO;mBAEP,kBAAC,QAAD;UACE,eAAc;UACd,gBAAe;UACf,aAAa;UACb,GAAE;UACF,CAAA;SACE,CAAA;QACC,CAAA,CACL;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;SAAO,WAAU;mBACd,EAAG,qBAAqB,YAAY;SAC/B,CAAA,EACR,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBACb,EAAc;UACV,CAAA,EACP,kBAAC,UAAD;UACE,eACE,KAAK,EAAmB,EAAc,UAAU;UAElD,WAAU;oBAET,EAAG,iBAAiB,OAAO;UACrB,CAAA,CACL;WACF,EAAA,CAAA;QACL,EAAc,iBACb,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;SAAO,WAAU;mBACd,EAAG,yBAAyB,4BAA4B;SACnD,CAAA,EACR,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBACb,EAAc;UACV,CAAA,EACP,kBAAC,UAAD;UACE,eACE,KAAK,EACH,EAAc,iBAAiB,GAChC;UAEH,WAAU;oBAET,EAAG,iBAAiB,OAAO;UACrB,CAAA,CACL;WACF,EAAA,CAAA;QAER,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;SAAO,WAAU;mBACd,EAAG,yBAAyB,gBAAgB;SACvC,CAAA,EACR,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAc,cAAc,KAAK,KAAK;SAClC,CAAA,CACH,EAAA,CAAA;QACF;SACF;;KAIR,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,2BAA2B,sBAAsB;QAClD,CAAA,EACJ,CAAC,KACA,kBAAC,UAAD;QACE,eAAe,EAAkB,GAAK;QACtC,WAAU;kBAFZ,CAIE,kBAAC,OAAD;SACE,WAAU;SACV,MAAK;SACL,SAAQ;SACR,QAAO;mBAEP,kBAAC,QAAD;UACE,eAAc;UACd,gBAAe;UACf,aAAa;UACb,GAAE;UACF,CAAA;SACE,CAAA,EACL,EAAG,sBAAsB,aAAa,CAChC;UAEP;UAEL,IACC,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;SAAO,WAAU;mBAAjB;UACG,EAAG,uBAAuB,cAAc;UAAE;UAC3C,kBAAC,QAAD;WAAM,WAAU;qBAAyB;WAAQ,CAAA;UAC3C;YACR,kBAAC,SAAD;SACE,MAAK;SACL,OAAO,EAAU;SACjB,WAAW,MACT,EAAa;UACX,GAAG;UACH,aAAa,EAAE,OAAO;UACvB,CAAC;SAEJ,aAAa,EACX,kCACA,iBACD;SACD,WAAU;SACV,CAAA,CACE,EAAA,CAAA;QAEN,kBAAC,OAAD,EAAA,UAAA;SACE,kBAAC,SAAD;UAAO,WAAU;oBAAjB;WACG,EAAG,yBAAyB,gBAAgB;WAAE;WAC/C,kBAAC,QAAD;YAAM,WAAU;sBAAyB;YAAQ,CAAA;WAC3C;;SACR,kBAAC,SAAD;UACE,MAAK;UACL,OAAO,EAAU;UACjB,WAAW,MACT,EAAa;WACX,GAAG;WACH,eAAe,EAAE,OAAO;WACzB,CAAC;UAEJ,aAAa,EACX,oCACA,mEACD;UACD,WAAU;UACV,CAAA;SACF,kBAAC,KAAD;UAAG,WAAU;oBACV,EACC,+BACA,qCACD;UACC,CAAA;SACA,EAAA,CAAA;QAEN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;SAAO,WAAU;mBACd,EAAG,uBAAuB,cAAc;SACnC,CAAA,EACR,kBAAC,OAAD;SAAK,WAAU;mBACZ;UACC;UACA;UACA;UACD,CAAC,KAAK,MACL,kBAAC,SAAD;UAEE,WAAU;oBAFZ,CAIE,kBAAC,SAAD;WACE,MAAK;WACL,SAAS,EAAU,YAAY,SAAS,EAAM;WAC9C,WAAW,MAAM;AACf,YAAI,EAAE,OAAO,UACX,EAAa;aACX,GAAG;aACH,aAAa,CAAC,GAAG,EAAU,aAAa,EAAM;aAC/C,CAAC,GAEF,EAAa;aACX,GAAG;aACH,aAAa,EAAU,YAAY,QAChC,MAAM,MAAM,EACd;aACF,CAAC;;WAGN,WAAU;WACV,CAAA,EACF,kBAAC,QAAD;WAAM,WAAU;qBACb,EAAM,QAAQ,MAAM,IAAI;WACpB,CAAA,CACD;YA1BD,EA0BC,CACR;SACE,CAAA,CACF,EAAA,CAAA;QAEN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;SAAO,WAAU;mBACd,EACC,8BACA,6BACD;SACK,CAAA,EACR,kBAAC,UAAD;SACE,OAAO,EAAU;SACjB,WAAW,MACT,EAAa;UACX,GAAG;UACH,4BAA4B,EAAE,OAAO;UACtC,CAAC;SAEJ,WAAU;mBARZ;UAUE,kBAAC,UAAD;WAAQ,OAAM;qBACX,EACC,0BACA,2CACD;WACM,CAAA;UACT,kBAAC,UAAD;WAAQ,OAAM;qBACX,EAAG,2BAA2B,sBAAsB;WAC9C,CAAA;UACT,kBAAC,UAAD;WAAQ,OAAM;qBACX,EAAG,0BAA0B,qBAAqB;WAC5C,CAAA;UACF;WACL,EAAA,CAAA;QAEN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,UAAD;UACE,SA3nCW,YAAY;AACvC,eAAI,CAAC,EAAU,eAAe,CAAC,EAAU,eAAe;AACtD,cACE,EACE,2BACA,4CACD,CACF;AACD;;AAIF,WADA,EAAoB,GAAK,EACzB,EAAS,KAAK;AAEd,eAAI;YACF,IAAM,IAAuB,GAAY;AAEzC,gBAAI,CAAC,EACH,OAAU,MACR,EACE,8BACA,2EACD,CACF;YAGH,IAAM,IAAW,MAAM,MAAM,GAAsB;aACjD,QAAQ;aACR,SAAS,EACP,gBAAgB,oBACjB;aACD,MAAM,KAAK,UAAU;cACnB,aAAa,EAAU;cACvB,eAAe,EAAU,cACtB,MAAM,IAAI,CACV,KAAK,MAAQ,EAAI,MAAM,CAAC;cAC3B,aAAa,EAAU;cACvB,gBAAgB,CAAC,OAAO;cACxB,4BAA4B,EAAU;cACvC,CAAC;aACH,CAAC;AAEF,gBAAI,CAAC,EAAS,IAAI;aAChB,IAAM,IAAY,MAAM,EAAS,MAAM;AACvC,mBAAU,MACR,EAAU,qBACR,EAAU,SACV,sBACH;;AAYH,YARA,EADe,MAAM,EAAS,MAAM,CACZ,EACxB,EACE,EACE,6BACA,oEACD,CACF,EACD,EAAkB,GAAM,EACxB,EAAa;aACX,aAAa;aACb,eAAe;aACf,aAAa,CAAC,sBAAsB,gBAAgB;aACpD,4BAA4B;aAC7B,CAAC;oBACK,GAAK;AACZ,cACE,aAAe,QACX,EAAI,UACJ,EAAG,2BAA2B,4BAA4B,CAC/D;qBACO;AACR,cAAoB,GAAM;;;UAmjCZ,UAAU;UACV,WAAU;oBAET,IACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAa,WAAU,wBAAyB,CAAA,EAC/C,EAAG,wBAAwB,iBAAiB,CAC5C,EAAA,CAAA,GAEH,EAAG,iCAAiC,kBAAkB;UAEjD,CAAA,EACT,kBAAC,UAAD;UACE,eAAe;AAEb,WADA,EAAkB,GAAM,EACxB,EAAa;YACX,aAAa;YACb,eAAe;YACf,aAAa,CAAC,sBAAsB,gBAAgB;YACpD,4BAA4B;YAC7B,CAAC;;UAEJ,WAAU;oBAET,EAAG,mBAAmB,SAAS;UACzB,CAAA,CACL;;QACF;WAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QACE,WAAU;QACV,MAAK;QACL,SAAQ;QACR,QAAO;kBAEP,kBAAC,QAAD;SACE,eAAc;SACd,gBAAe;SACf,aAAa;SACb,GAAE;SACF,CAAA;QACE,CAAA,EACN,kBAAC,KAAD;QAAG,WAAU;kBACV,EACC,yBACA,2EACD;QACC,CAAA,CACA;SAEJ;;KAGN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,iCAAiC,yBAAyB;OAC3D,CAAA,EACL,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAgC;WAEzC,CAAA,EACP,kBAAC,QAAD;WAAM,WAAU;qBACb,EAAG,mBAAmB,SAAS;WAC3B,CAAA,CACH;;SACN,kBAAC,KAAD;UAAG,WAAU;oBACV,EACC,gCACA,oDACD;UACC,CAAA;SACJ,kBAAC,OAAD;UAAK,WAAU;oBAAf;WACE,kBAAC,QAAD;YAAM,WAAU;sBAA6D;YAEtE,CAAA;WACP,kBAAC,QAAD;YAAM,WAAU;sBAA6D;YAEtE,CAAA;WACP,kBAAC,QAAD;YAAM,WAAU;sBACb,EAAG,yBAAyB,gBAAgB;YACxC,CAAA;WACH;;SACF;;OACF,CAAA,CACF;;KACF;;GAIP,CAAC,KAAa,MAAc,UAC3B,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,2BAA2B,iBAAiB;OAC7C,CAAA,EACL,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,0BACA,wJACD;OACC,CAAA,CACA;;KAEN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,4BAA4B,0BAA0B;QACvD,CAAA;OACL,kBAAC,KAAD;QAAG,WAAU;kBACV,EACC,gCACA,4GACD;QACC,CAAA;OAEH,KAAa,EAAU,UACtB,kBAAC,KAAD;QACE,MAAM,GAAG,OAAO,SAAS,OAAO;QAChC,WAAU;kBAFZ,CAIE,kBAAC,OAAD;SACE,WAAU;SACV,MAAK;SACL,SAAQ;SACR,QAAO;mBAEP,kBAAC,QAAD;UACE,eAAc;UACd,gBAAe;UACf,aAAa;UACb,GAAE;UACF,CAAA;SACE,CAAA,EACL,EAAG,+BAA+B,iBAAiB,CAClD;YAEJ,kBAAC,OAAD;QAAK,WAAU;kBACX,IAKE,EACE,yBACA,qDACD,GAPD,EACE,0BACA,mEACD;QAKD,CAAA;OAEJ;;KAEN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,wBAAwB,eAAe;OACxC,CAAA,EACL,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,4BACA,wFACD;OACC,CAAA,CACA;;KACF;;GAEJ;MArnCJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD,EAAW,WAAU,kCAAmC,CAAA;KACpD,CAAA;IACN,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,0BAA0B,wBAAwB;KACnD,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,8BACA,+DACD;KACC,CAAA;IACA;;EACF,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSO Login Page
|
|
3
|
+
* Allows users to enter their email/company domain to initiate SSO login
|
|
4
|
+
* Supports both SAML 2.0 and OIDC authentication methods
|
|
5
|
+
*/
|
|
6
|
+
export declare function SsoLoginPage(): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=SsoLoginPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SsoLoginPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/SsoLoginPage.tsx"],"names":[],"mappings":"AASA;;;;GAIG;AACH,wBAAgB,YAAY,4CA6X3B"}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { useSsoOperations as e } from "../hooks/useSsoOperations.js";
|
|
2
|
+
import { AuthLayout as t } from "../components/AuthLayout.js";
|
|
3
|
+
import { AlertIcon as n, EmailIcon as r, SpinnerIcon as i } from "../components/AuthIcons.js";
|
|
4
|
+
import { useEffect as a, useState as o } from "react";
|
|
5
|
+
import { useNavigate as s, useSearchParams as c } from "react-router-dom";
|
|
6
|
+
import { useI18n as l } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
7
|
+
import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
8
|
+
//#region src/auth/pages/SsoLoginPage.tsx
|
|
9
|
+
function p() {
|
|
10
|
+
let { t: p } = l(), m = (e, t) => {
|
|
11
|
+
let n = p(e);
|
|
12
|
+
return n === e ? t : n;
|
|
13
|
+
}, h = s(), [g] = c(), _ = g.get("tenant"), v = g.get("method"), { initiateSsoLogin: y, initiateExternalOidcLogin: b, isGeneratingRequest: x, isGeneratingOidcUrl: S } = e(_ ?? void 0), [C, w] = o(""), [T, E] = o(null), [D, O] = o("oidc"), [k, A] = o(!1), [j, M] = o(!1);
|
|
14
|
+
a(() => {
|
|
15
|
+
(v === "saml" || v === "oidc") && O(v);
|
|
16
|
+
}, [v]);
|
|
17
|
+
let N = async (e) => {
|
|
18
|
+
e.preventDefault(), E(null), M(!1), A(!0);
|
|
19
|
+
try {
|
|
20
|
+
let e = C.split("@")[1];
|
|
21
|
+
if (!e) {
|
|
22
|
+
E("Please enter a valid email address with your company domain"), A(!1);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
let t = _ || e;
|
|
26
|
+
sessionStorage.setItem("sso_email", C), D === "oidc" ? await b(t, "/dashboard") : await y(t, "/dashboard");
|
|
27
|
+
} catch (e) {
|
|
28
|
+
console.error("SSO login failed:", e);
|
|
29
|
+
let t = e instanceof Error ? e.message : "Failed to initiate SSO login. Please check your configuration.";
|
|
30
|
+
t.toLowerCase().includes("sso") && (t.toLowerCase().includes("not configured") || t.toLowerCase().includes("not set up")) ? (M(!0), E("SSO is not configured for your organization. Please use regular email/password login or contact your administrator to set up SSO.")) : E(t), A(!1);
|
|
31
|
+
}
|
|
32
|
+
}, P = x || S || k;
|
|
33
|
+
return /* @__PURE__ */ f(t, {
|
|
34
|
+
title: m("auth.ssoLogin.title", "Enterprise SSO"),
|
|
35
|
+
subtitle: m("auth.ssoLogin.subtitle", "Sign in with your company's identity provider"),
|
|
36
|
+
children: [
|
|
37
|
+
/* @__PURE__ */ f("form", {
|
|
38
|
+
onSubmit: N,
|
|
39
|
+
className: "space-y-5",
|
|
40
|
+
children: [
|
|
41
|
+
T && /* @__PURE__ */ f("div", {
|
|
42
|
+
className: `flex items-start gap-3 p-4 rounded-xl border ${j ? "bg-status-warning-bg-subtle border-status-warning-border" : "bg-status-error-bg-subtle border-status-error-border"}`,
|
|
43
|
+
children: [/* @__PURE__ */ d(n, { className: `w-5 h-5 flex-shrink-0 mt-0.5 ${j ? "text-status-warning-text" : "text-status-error-text"}` }), /* @__PURE__ */ f("div", {
|
|
44
|
+
className: "flex-1",
|
|
45
|
+
children: [/* @__PURE__ */ d("p", {
|
|
46
|
+
className: `text-sm ${j ? "text-status-warning-text" : "text-status-error-text"}`,
|
|
47
|
+
children: T
|
|
48
|
+
}), j && /* @__PURE__ */ f("button", {
|
|
49
|
+
type: "button",
|
|
50
|
+
onClick: () => h("/auth/login", { state: { email: C } }),
|
|
51
|
+
className: "mt-3 inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-status-warning-bg-subtle hover:bg-status-warning-bg-subtle text-status-warning-text text-sm font-semibold transition-all",
|
|
52
|
+
children: [/* @__PURE__ */ d("svg", {
|
|
53
|
+
className: "w-4 h-4",
|
|
54
|
+
fill: "none",
|
|
55
|
+
viewBox: "0 0 24 24",
|
|
56
|
+
stroke: "currentColor",
|
|
57
|
+
children: /* @__PURE__ */ d("path", {
|
|
58
|
+
strokeLinecap: "round",
|
|
59
|
+
strokeLinejoin: "round",
|
|
60
|
+
strokeWidth: 2,
|
|
61
|
+
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"
|
|
62
|
+
})
|
|
63
|
+
}), m("auth.ssoLogin.useEmailLogin", "Use Email/Password Login Instead")]
|
|
64
|
+
})]
|
|
65
|
+
})]
|
|
66
|
+
}),
|
|
67
|
+
/* @__PURE__ */ f("div", {
|
|
68
|
+
className: "space-y-2",
|
|
69
|
+
children: [/* @__PURE__ */ d("label", {
|
|
70
|
+
className: "block text-sm font-medium text-[var(--color-text-primary)]",
|
|
71
|
+
children: m("auth.ssoLogin.authMethod", "Authentication Method")
|
|
72
|
+
}), /* @__PURE__ */ f("div", {
|
|
73
|
+
className: "grid grid-cols-2 gap-3",
|
|
74
|
+
children: [/* @__PURE__ */ d("button", {
|
|
75
|
+
type: "button",
|
|
76
|
+
onClick: () => O("oidc"),
|
|
77
|
+
className: `p-4 rounded-xl border-2 transition-all ${D === "oidc" ? "border-action-primary-bg bg-status-info-bg-subtle" : "border-border-subtle hover:border-border-default"}`,
|
|
78
|
+
children: /* @__PURE__ */ f("div", {
|
|
79
|
+
className: "flex items-center gap-3",
|
|
80
|
+
children: [/* @__PURE__ */ d("div", {
|
|
81
|
+
className: `w-10 h-10 rounded-lg flex items-center justify-center ${D === "oidc" ? "bg-status-info-bg-subtle0" : "bg-bg-sunken"}`,
|
|
82
|
+
children: /* @__PURE__ */ d("svg", {
|
|
83
|
+
className: `w-5 h-5 ${D === "oidc" ? "text-white" : "text-text-secondary"}`,
|
|
84
|
+
fill: "none",
|
|
85
|
+
viewBox: "0 0 24 24",
|
|
86
|
+
stroke: "currentColor",
|
|
87
|
+
children: /* @__PURE__ */ d("path", {
|
|
88
|
+
strokeLinecap: "round",
|
|
89
|
+
strokeLinejoin: "round",
|
|
90
|
+
strokeWidth: 2,
|
|
91
|
+
d: "M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9"
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
}), /* @__PURE__ */ f("div", {
|
|
95
|
+
className: "text-left",
|
|
96
|
+
children: [/* @__PURE__ */ d("div", {
|
|
97
|
+
className: `font-medium ${D === "oidc" ? "text-text-linkHover" : "text-text-primary"}`,
|
|
98
|
+
children: "OpenID Connect"
|
|
99
|
+
}), /* @__PURE__ */ d("div", {
|
|
100
|
+
className: "text-xs text-text-secondary",
|
|
101
|
+
children: m("auth.ssoLogin.modernRecommended", "Modern & Recommended")
|
|
102
|
+
})]
|
|
103
|
+
})]
|
|
104
|
+
})
|
|
105
|
+
}), /* @__PURE__ */ d("button", {
|
|
106
|
+
type: "button",
|
|
107
|
+
onClick: () => O("saml"),
|
|
108
|
+
className: `p-4 rounded-xl border-2 transition-all ${D === "saml" ? "border-accent-purple bg-accent-purple-subtle" : "border-border-subtle hover:border-border-default"}`,
|
|
109
|
+
children: /* @__PURE__ */ f("div", {
|
|
110
|
+
className: "flex items-center gap-3",
|
|
111
|
+
children: [/* @__PURE__ */ d("div", {
|
|
112
|
+
className: `w-10 h-10 rounded-lg flex items-center justify-center ${D === "saml" ? "bg-accent-purple-subtle0" : "bg-bg-sunken"}`,
|
|
113
|
+
children: /* @__PURE__ */ d("svg", {
|
|
114
|
+
className: `w-5 h-5 ${D === "saml" ? "text-white" : "text-text-secondary"}`,
|
|
115
|
+
fill: "none",
|
|
116
|
+
viewBox: "0 0 24 24",
|
|
117
|
+
stroke: "currentColor",
|
|
118
|
+
children: /* @__PURE__ */ d("path", {
|
|
119
|
+
strokeLinecap: "round",
|
|
120
|
+
strokeLinejoin: "round",
|
|
121
|
+
strokeWidth: 2,
|
|
122
|
+
d: "M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"
|
|
123
|
+
})
|
|
124
|
+
})
|
|
125
|
+
}), /* @__PURE__ */ f("div", {
|
|
126
|
+
className: "text-left",
|
|
127
|
+
children: [/* @__PURE__ */ d("div", {
|
|
128
|
+
className: `font-medium ${D === "saml" ? "text-accent-purple" : "text-text-primary"}`,
|
|
129
|
+
children: "SAML 2.0"
|
|
130
|
+
}), /* @__PURE__ */ d("div", {
|
|
131
|
+
className: "text-xs text-text-secondary",
|
|
132
|
+
children: m("auth.ssoLogin.enterpriseLegacy", "Enterprise Legacy")
|
|
133
|
+
})]
|
|
134
|
+
})]
|
|
135
|
+
})
|
|
136
|
+
})]
|
|
137
|
+
})]
|
|
138
|
+
}),
|
|
139
|
+
/* @__PURE__ */ d("div", {
|
|
140
|
+
className: `p-4 rounded-xl border ${D === "oidc" ? "bg-status-info-bg-subtle border-status-info-border" : "bg-accent-purple-subtle border-accent-purple-subtle"}`,
|
|
141
|
+
children: /* @__PURE__ */ d("p", {
|
|
142
|
+
className: `text-sm ${D === "oidc" ? "text-status-info-text" : "text-accent-purple"}`,
|
|
143
|
+
children: D === "oidc" ? "Sign in using OpenID Connect with your identity provider. Supports modern SSO with PKCE security." : "Sign in using SAML 2.0 with your enterprise identity provider (Okta, Azure AD, etc.)."
|
|
144
|
+
})
|
|
145
|
+
}),
|
|
146
|
+
/* @__PURE__ */ f("div", {
|
|
147
|
+
className: "space-y-2",
|
|
148
|
+
children: [
|
|
149
|
+
/* @__PURE__ */ d("label", {
|
|
150
|
+
htmlFor: "email",
|
|
151
|
+
className: "block text-sm font-medium text-[var(--color-text-primary)]",
|
|
152
|
+
children: m("auth.ssoLogin.workEmail", "Work Email Address")
|
|
153
|
+
}),
|
|
154
|
+
/* @__PURE__ */ f("div", {
|
|
155
|
+
className: "relative",
|
|
156
|
+
children: [/* @__PURE__ */ d("div", {
|
|
157
|
+
className: "absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none",
|
|
158
|
+
children: /* @__PURE__ */ d(r, { className: "w-5 h-5 text-[var(--color-text-tertiary)]" })
|
|
159
|
+
}), /* @__PURE__ */ d("input", {
|
|
160
|
+
id: "email",
|
|
161
|
+
type: "email",
|
|
162
|
+
required: !0,
|
|
163
|
+
value: C,
|
|
164
|
+
onChange: (e) => w(e.target.value),
|
|
165
|
+
className: "block w-full pl-[3.5rem] pr-4 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all",
|
|
166
|
+
placeholder: "you@company.com"
|
|
167
|
+
})]
|
|
168
|
+
}),
|
|
169
|
+
/* @__PURE__ */ d("p", {
|
|
170
|
+
className: "text-xs text-[var(--color-text-tertiary)]",
|
|
171
|
+
children: m("auth.ssoLogin.useCompanyEmail", "Use your company email (e.g., @yourcompany.com)")
|
|
172
|
+
})
|
|
173
|
+
]
|
|
174
|
+
}),
|
|
175
|
+
/* @__PURE__ */ d("button", {
|
|
176
|
+
type: "submit",
|
|
177
|
+
disabled: P || !C,
|
|
178
|
+
className: `w-full py-3 px-4 rounded-xl font-semibold shadow-lg transition-all duration-200 flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed disabled:shadow-none ${D === "oidc" ? "auth-primary-button" : "bg-gradient-to-r from-purple-600 to-pink-600 text-white shadow-purple-500/25 hover:shadow-xl hover:shadow-purple-500/30 hover:from-purple-500 hover:to-pink-500"}`,
|
|
179
|
+
children: P ? /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d(i, { className: "w-5 h-5 animate-spin" }), /* @__PURE__ */ d("span", { children: "Redirecting..." })] }) : /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d("svg", {
|
|
180
|
+
className: "w-5 h-5",
|
|
181
|
+
fill: "none",
|
|
182
|
+
viewBox: "0 0 24 24",
|
|
183
|
+
stroke: "currentColor",
|
|
184
|
+
children: /* @__PURE__ */ d("path", {
|
|
185
|
+
strokeLinecap: "round",
|
|
186
|
+
strokeLinejoin: "round",
|
|
187
|
+
strokeWidth: 2,
|
|
188
|
+
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"
|
|
189
|
+
})
|
|
190
|
+
}), /* @__PURE__ */ f("span", { children: ["Continue with ", D === "oidc" ? "OIDC" : "SAML"] })] })
|
|
191
|
+
})
|
|
192
|
+
]
|
|
193
|
+
}),
|
|
194
|
+
/* @__PURE__ */ d("div", {
|
|
195
|
+
className: "mt-6 text-center",
|
|
196
|
+
children: /* @__PURE__ */ d("button", {
|
|
197
|
+
onClick: () => h("/auth/login"),
|
|
198
|
+
className: "text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors",
|
|
199
|
+
children: /* @__PURE__ */ d("span", {
|
|
200
|
+
className: "font-semibold text-text-link hover:text-text-linkHover",
|
|
201
|
+
children: m("auth.ssoLogin.backToLogin", "Back to regular login")
|
|
202
|
+
})
|
|
203
|
+
})
|
|
204
|
+
}),
|
|
205
|
+
/* @__PURE__ */ d("div", {
|
|
206
|
+
className: "mt-4 text-center",
|
|
207
|
+
children: /* @__PURE__ */ f("button", {
|
|
208
|
+
onClick: () => h("/auth/reactivate"),
|
|
209
|
+
className: "text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors",
|
|
210
|
+
children: [
|
|
211
|
+
m("auth.ssoLogin.deactivatedAccount", "Have a deactivated account?"),
|
|
212
|
+
" ",
|
|
213
|
+
/* @__PURE__ */ d("span", {
|
|
214
|
+
className: "font-semibold text-status-success-text hover:text-status-success-text",
|
|
215
|
+
children: m("auth.ssoLogin.reactivateIt", "Reactivate it")
|
|
216
|
+
})
|
|
217
|
+
]
|
|
218
|
+
})
|
|
219
|
+
}),
|
|
220
|
+
/* @__PURE__ */ f("div", {
|
|
221
|
+
className: "mt-6 p-4 rounded-xl bg-bg-canvas/50 border border-border-subtle",
|
|
222
|
+
children: [/* @__PURE__ */ d("h4", {
|
|
223
|
+
className: "text-sm font-medium text-[var(--color-text-primary)] mb-2",
|
|
224
|
+
children: m("auth.ssoLogin.noSso", "Don't see your company's SSO?")
|
|
225
|
+
}), /* @__PURE__ */ d("p", {
|
|
226
|
+
className: "text-xs text-[var(--color-text-secondary)]",
|
|
227
|
+
children: m("auth.ssoLogin.contactIT", "Contact your IT administrator to set up SSO for your organization. They'll need to configure your identity provider with our service.")
|
|
228
|
+
})]
|
|
229
|
+
})
|
|
230
|
+
]
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
//#endregion
|
|
234
|
+
export { p as SsoLoginPage };
|
|
235
|
+
|
|
236
|
+
//# sourceMappingURL=SsoLoginPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SsoLoginPage.js","names":[],"sources":["../../../src/auth/pages/SsoLoginPage.tsx"],"sourcesContent":["import { useState, useEffect } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useNavigate, useSearchParams } from \"react-router-dom\";\nimport { useSsoOperations } from \"../hooks/useSsoOperations\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport { EmailIcon, SpinnerIcon, AlertIcon } from \"../components/AuthIcons\";\n\ntype SsoMethod = \"saml\" | \"oidc\";\n\n/**\n * SSO Login Page\n * Allows users to enter their email/company domain to initiate SSO login\n * Supports both SAML 2.0 and OIDC authentication methods\n */\nexport function SsoLoginPage() {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n\n const navigate = useNavigate();\n const [searchParams] = useSearchParams();\n const tenantFromUrl = searchParams.get(\"tenant\");\n const methodFromUrl = searchParams.get(\"method\") as SsoMethod | null;\n const {\n initiateSsoLogin,\n initiateExternalOidcLogin,\n isGeneratingRequest,\n isGeneratingOidcUrl,\n } = useSsoOperations(tenantFromUrl ?? undefined);\n\n const [email, setEmail] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n const [ssoMethod, setSsoMethod] = useState<SsoMethod>(\"oidc\");\n const [isInitiating, setIsInitiating] = useState(false);\n const [isSsoNotConfigured, setIsSsoNotConfigured] = useState(false);\n\n // Set method from URL if provided\n useEffect(() => {\n if (methodFromUrl === \"saml\" || methodFromUrl === \"oidc\") {\n setSsoMethod(methodFromUrl);\n }\n }, [methodFromUrl]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setIsSsoNotConfigured(false);\n setIsInitiating(true);\n\n try {\n // Extract domain from email\n const domain = email.split(\"@\")[1];\n if (!domain) {\n setError(\"Please enter a valid email address with your company domain\");\n setIsInitiating(false);\n return;\n }\n\n // In a real app, you would look up the tenant by domain\n // For now, we'll use the tenant from URL or the domain itself\n const tenantId = tenantFromUrl || domain;\n\n // Store email for post-login\n sessionStorage.setItem(\"sso_email\", email);\n\n if (ssoMethod === \"oidc\") {\n // External OIDC flow (Azure AD, Google, etc.)\n await initiateExternalOidcLogin(tenantId, \"/dashboard\");\n } else {\n await initiateSsoLogin(tenantId, \"/dashboard\");\n }\n } catch (err) {\n console.error(\"SSO login failed:\", err);\n const errorMessage =\n err instanceof Error\n ? err.message\n : \"Failed to initiate SSO login. Please check your configuration.\";\n\n // Check if error is about SSO not being configured\n if (\n errorMessage.toLowerCase().includes(\"sso\") &&\n (errorMessage.toLowerCase().includes(\"not configured\") ||\n errorMessage.toLowerCase().includes(\"not set up\"))\n ) {\n setIsSsoNotConfigured(true);\n setError(\n \"SSO is not configured for your organization. Please use regular email/password login or contact your administrator to set up SSO.\",\n );\n } else {\n setError(errorMessage);\n }\n\n setIsInitiating(false);\n }\n };\n\n const isSubmitting =\n isGeneratingRequest || isGeneratingOidcUrl || isInitiating;\n\n return (\n <AuthLayout\n title={tr(\"auth.ssoLogin.title\", \"Enterprise SSO\")}\n subtitle={tr(\n \"auth.ssoLogin.subtitle\",\n \"Sign in with your company's identity provider\",\n )}\n >\n <form onSubmit={handleSubmit} className=\"space-y-5\">\n {/* Error Alert */}\n {error && (\n <div\n className={`flex items-start gap-3 p-4 rounded-xl border ${\n isSsoNotConfigured\n ? \"bg-status-warning-bg-subtle border-status-warning-border\"\n : \"bg-status-error-bg-subtle border-status-error-border\"\n }`}\n >\n <AlertIcon\n className={`w-5 h-5 flex-shrink-0 mt-0.5 ${\n isSsoNotConfigured\n ? \"text-status-warning-text\"\n : \"text-status-error-text\"\n }`}\n />\n <div className=\"flex-1\">\n <p\n className={`text-sm ${\n isSsoNotConfigured\n ? \"text-status-warning-text\"\n : \"text-status-error-text\"\n }`}\n >\n {error}\n </p>\n {isSsoNotConfigured && (\n <button\n type=\"button\"\n onClick={() => navigate(\"/auth/login\", { state: { email } })}\n className=\"mt-3 inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-status-warning-bg-subtle hover:bg-status-warning-bg-subtle text-status-warning-text text-sm font-semibold transition-all\"\n >\n <svg\n className=\"w-4 h-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=\"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(\n \"auth.ssoLogin.useEmailLogin\",\n \"Use Email/Password Login Instead\",\n )}\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* SSO Method Toggle */}\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-[var(--color-text-primary)]\">\n {tr(\"auth.ssoLogin.authMethod\", \"Authentication Method\")}\n </label>\n <div className=\"grid grid-cols-2 gap-3\">\n <button\n type=\"button\"\n onClick={() => setSsoMethod(\"oidc\")}\n className={`p-4 rounded-xl border-2 transition-all ${\n ssoMethod === \"oidc\"\n ? \"border-action-primary-bg bg-status-info-bg-subtle\"\n : \"border-border-subtle hover:border-border-default\"\n }`}\n >\n <div className=\"flex items-center gap-3\">\n <div\n className={`w-10 h-10 rounded-lg flex items-center justify-center ${\n ssoMethod === \"oidc\"\n ? \"bg-status-info-bg-subtle0\"\n : \"bg-bg-sunken\"\n }`}\n >\n <svg\n className={`w-5 h-5 ${ssoMethod === \"oidc\" ? \"text-white\" : \"text-text-secondary\"}`}\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=\"M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9\"\n />\n </svg>\n </div>\n <div className=\"text-left\">\n <div\n className={`font-medium ${ssoMethod === \"oidc\" ? \"text-text-linkHover\" : \"text-text-primary\"}`}\n >\n OpenID Connect\n </div>\n <div className=\"text-xs text-text-secondary\">\n {tr(\n \"auth.ssoLogin.modernRecommended\",\n \"Modern & Recommended\",\n )}\n </div>\n </div>\n </div>\n </button>\n\n <button\n type=\"button\"\n onClick={() => setSsoMethod(\"saml\")}\n className={`p-4 rounded-xl border-2 transition-all ${\n ssoMethod === \"saml\"\n ? \"border-accent-purple bg-accent-purple-subtle\"\n : \"border-border-subtle hover:border-border-default\"\n }`}\n >\n <div className=\"flex items-center gap-3\">\n <div\n className={`w-10 h-10 rounded-lg flex items-center justify-center ${\n ssoMethod === \"saml\"\n ? \"bg-accent-purple-subtle0\"\n : \"bg-bg-sunken\"\n }`}\n >\n <svg\n className={`w-5 h-5 ${ssoMethod === \"saml\" ? \"text-white\" : \"text-text-secondary\"}`}\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=\"M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z\"\n />\n </svg>\n </div>\n <div className=\"text-left\">\n <div\n className={`font-medium ${ssoMethod === \"saml\" ? \"text-accent-purple\" : \"text-text-primary\"}`}\n >\n SAML 2.0\n </div>\n <div className=\"text-xs text-text-secondary\">\n {tr(\"auth.ssoLogin.enterpriseLegacy\", \"Enterprise Legacy\")}\n </div>\n </div>\n </div>\n </button>\n </div>\n </div>\n\n {/* Info Banner */}\n <div\n className={`p-4 rounded-xl border ${\n ssoMethod === \"oidc\"\n ? \"bg-status-info-bg-subtle border-status-info-border\"\n : \"bg-accent-purple-subtle border-accent-purple-subtle\"\n }`}\n >\n <p\n className={`text-sm ${\n ssoMethod === \"oidc\"\n ? \"text-status-info-text\"\n : \"text-accent-purple\"\n }`}\n >\n {ssoMethod === \"oidc\"\n ? \"Sign in using OpenID Connect with your identity provider. Supports modern SSO with PKCE security.\"\n : \"Sign in using SAML 2.0 with your enterprise identity provider (Okta, Azure AD, etc.).\"}\n </p>\n </div>\n\n {/* Email Input */}\n <div className=\"space-y-2\">\n <label\n htmlFor=\"email\"\n className=\"block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr(\"auth.ssoLogin.workEmail\", \"Work Email Address\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <EmailIcon className=\"w-5 h-5 text-[var(--color-text-tertiary)]\" />\n </div>\n <input\n id=\"email\"\n type=\"email\"\n required\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n className=\"block w-full pl-[3.5rem] pr-4 py-3 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] placeholder:text-[var(--color-text-tertiary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n placeholder=\"you@company.com\"\n />\n </div>\n <p className=\"text-xs text-[var(--color-text-tertiary)]\">\n {tr(\n \"auth.ssoLogin.useCompanyEmail\",\n \"Use your company email (e.g., @yourcompany.com)\",\n )}\n </p>\n </div>\n\n {/* Submit Button */}\n <button\n type=\"submit\"\n disabled={isSubmitting || !email}\n className={`w-full py-3 px-4 rounded-xl font-semibold shadow-lg transition-all duration-200 flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed disabled:shadow-none ${\n ssoMethod === \"oidc\"\n ? \"auth-primary-button\"\n : \"bg-gradient-to-r from-purple-600 to-pink-600 text-white shadow-purple-500/25 hover:shadow-xl hover:shadow-purple-500/30 hover:from-purple-500 hover:to-pink-500\"\n }`}\n >\n {isSubmitting ? (\n <>\n <SpinnerIcon className=\"w-5 h-5 animate-spin\" />\n <span>Redirecting...</span>\n </>\n ) : (\n <>\n <svg\n className=\"w-5 h-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 <span>\n Continue with {ssoMethod === \"oidc\" ? \"OIDC\" : \"SAML\"}\n </span>\n </>\n )}\n </button>\n </form>\n\n {/* Back to Regular Login */}\n <div className=\"mt-6 text-center\">\n <button\n onClick={() => navigate(\"/auth/login\")}\n className=\"text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors\"\n >\n <span className=\"font-semibold text-text-link hover:text-text-linkHover\">\n {tr(\"auth.ssoLogin.backToLogin\", \"Back to regular login\")}\n </span>\n </button>\n </div>\n\n {/* Reactivate Account Link */}\n <div className=\"mt-4 text-center\">\n <button\n onClick={() => navigate(\"/auth/reactivate\")}\n className=\"text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] transition-colors\"\n >\n {tr(\n \"auth.ssoLogin.deactivatedAccount\",\n \"Have a deactivated account?\",\n )}{\" \"}\n <span className=\"font-semibold text-status-success-text hover:text-status-success-text\">\n {tr(\"auth.ssoLogin.reactivateIt\", \"Reactivate it\")}\n </span>\n </button>\n </div>\n\n {/* Help Text */}\n <div className=\"mt-6 p-4 rounded-xl bg-bg-canvas/50 border border-border-subtle\">\n <h4 className=\"text-sm font-medium text-[var(--color-text-primary)] mb-2\">\n {tr(\"auth.ssoLogin.noSso\", \"Don't see your company's SSO?\")}\n </h4>\n <p className=\"text-xs text-[var(--color-text-secondary)]\">\n {tr(\n \"auth.ssoLogin.contactIT\",\n \"Contact your IT administrator to set up SSO for your organization. They'll need to configure your identity provider with our service.\",\n )}\n </p>\n </div>\n </AuthLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User details page (admin only).
|
|
3
|
+
*
|
|
4
|
+
* Route: /auth/users/:id
|
|
5
|
+
*
|
|
6
|
+
* Renders the full profile of a single user, with admin actions
|
|
7
|
+
* (edit, deactivate, hard-delete). Reuses the same getUser query
|
|
8
|
+
* that UsersPage relies on.
|
|
9
|
+
*/
|
|
10
|
+
export declare function UserDetailsPage(): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
//# sourceMappingURL=UserDetailsPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UserDetailsPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/UserDetailsPage.tsx"],"names":[],"mappings":"AA4CA;;;;;;;;GAQG;AACH,wBAAgB,eAAe,4CA8W9B"}
|