@burdenoff/microfe-auth 2026.527.1 → 2026.527.2
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/dist/auth/AuthRoutes.js +1 -1
- package/dist/auth/AuthRoutes.js.map +1 -1
- package/dist/auth/components/AuthLayout.js +14 -14
- package/dist/auth/components/AuthLayout.js.map +1 -1
- package/dist/auth/components/CaptchaV2.js +1 -4
- package/dist/auth/components/CaptchaV2.js.map +1 -1
- package/dist/auth/components/ConfirmActionDialog.js +3 -3
- package/dist/auth/components/ConfirmActionDialog.js.map +1 -1
- package/dist/auth/components/profile/UserProfileMenu.js +10 -6
- package/dist/auth/components/profile/UserProfileMenu.js.map +1 -1
- package/dist/auth/components/workspace/WorkspaceSelector.js +5 -5
- package/dist/auth/components/workspace/WorkspaceSelector.js.map +1 -1
- package/dist/auth/hooks/index.js +2 -2
- package/dist/auth/index.js +4 -4
- package/dist/auth/pages/AuditLogPage.js +7 -7
- package/dist/auth/pages/AuditLogPage.js.map +1 -1
- package/dist/auth/pages/EmailVerifyPage.js +10 -8
- package/dist/auth/pages/EmailVerifyPage.js.map +1 -1
- package/dist/auth/pages/LoginPage.js +20 -19
- package/dist/auth/pages/LoginPage.js.map +1 -1
- package/dist/auth/pages/MagicLinkPage.js +10 -8
- package/dist/auth/pages/MagicLinkPage.js.map +1 -1
- package/dist/auth/pages/MfaSetupPage.js +26 -21
- package/dist/auth/pages/MfaSetupPage.js.map +1 -1
- package/dist/auth/pages/MfaVerifyPage.js +21 -21
- package/dist/auth/pages/MfaVerifyPage.js.map +1 -1
- package/dist/auth/pages/OAuthCallbackPage.js +7 -6
- package/dist/auth/pages/OAuthCallbackPage.js.map +1 -1
- package/dist/auth/pages/PasswordResetPage.js +25 -22
- package/dist/auth/pages/PasswordResetPage.js.map +1 -1
- package/dist/auth/pages/ReactivatePage.js +17 -15
- package/dist/auth/pages/ReactivatePage.js.map +1 -1
- package/dist/auth/pages/RegisterPage.js +198 -194
- package/dist/auth/pages/RegisterPage.js.map +1 -1
- package/dist/auth/pages/SSOClearPage.js +1 -1
- package/dist/auth/pages/SSOClearPage.js.map +1 -1
- package/dist/auth/pages/SSODepositPage.js +1 -1
- package/dist/auth/pages/SSODepositPage.js.map +1 -1
- package/dist/auth/pages/SSORelayCallbackPage.js +1 -1
- package/dist/auth/pages/SSORelayCallbackPage.js.map +1 -1
- package/dist/auth/pages/SSORelayPage.js +1 -1
- package/dist/auth/pages/SSORelayPage.js.map +1 -1
- package/dist/auth/pages/SecurityPage.js +15 -16
- package/dist/auth/pages/SecurityPage.js.map +1 -1
- package/dist/auth/pages/SessionsPage.js +19 -20
- package/dist/auth/pages/SessionsPage.js.map +1 -1
- package/dist/auth/pages/SsoCallbackPage.js +19 -15
- package/dist/auth/pages/SsoCallbackPage.js.map +1 -1
- package/dist/auth/pages/SsoConfigPage.js +41 -27
- package/dist/auth/pages/SsoConfigPage.js.map +1 -1
- package/dist/auth/pages/SsoLoginPage.js +16 -14
- package/dist/auth/pages/SsoLoginPage.js.map +1 -1
- package/dist/auth/pages/UserDetailsPage.js +16 -17
- package/dist/auth/pages/UserDetailsPage.js.map +1 -1
- package/dist/auth/pages/UserProfilePage.js +31 -25
- package/dist/auth/pages/UserProfilePage.js.map +1 -1
- package/dist/auth/pages/UsersPage.js +46 -42
- package/dist/auth/pages/UsersPage.js.map +1 -1
- package/dist/index.js +11 -11
- package/dist/microfe-auth.css +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useAuthStore as e } from "../store/authStore.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { AlertIcon as t, SpinnerIcon as n } from "../components/AuthIcons.js";
|
|
3
|
+
import { useSsoOperations as r } from "../hooks/useSsoOperations.js";
|
|
4
4
|
import { useEffect as i, useRef as a, useState as o } from "react";
|
|
5
5
|
import { useNavigate as s, useSearchParams as c } from "react-router-dom";
|
|
6
6
|
import { useI18n as l } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
@@ -10,7 +10,7 @@ function p() {
|
|
|
10
10
|
let { t: p } = l(), m = (e, t) => {
|
|
11
11
|
let n = p(e);
|
|
12
12
|
return n === e ? t : n;
|
|
13
|
-
}, h = s(), [g] = c(), _ = e((e) => e.setAuthTokens), v = e((e) => e.setAuthenticated), { exchangeOidcCode: y, validateOidcState: b, isExternalOidcCallback: x, handleExternalOidcCallback: S } =
|
|
13
|
+
}, h = s(), [g] = c(), _ = e((e) => e.setAuthTokens), v = e((e) => e.setAuthenticated), { exchangeOidcCode: y, validateOidcState: b, isExternalOidcCallback: x, handleExternalOidcCallback: S } = r(), [C, w] = o(null), [T, E] = o("processing"), [D, O] = o("unknown"), k = a(!1), A = a(null);
|
|
14
14
|
return i(() => {
|
|
15
15
|
if (k.current) return;
|
|
16
16
|
k.current = !0;
|
|
@@ -31,7 +31,7 @@ function p() {
|
|
|
31
31
|
sessionStorage.setItem("mfa_challenge_id", i), sessionStorage.setItem("mfa_pending_token", e), sessionStorage.setItem("mfa_pending_refresh", t || ""), sessionStorage.setItem("mfa_redirect", n || "/dashboard"), h("/auth/mfa-verify", { replace: !0 });
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
|
-
_(e, t || ""), v(!0), E("success"), setTimeout(() => {
|
|
34
|
+
_(e, t || ""), v(!0), E("success"), A.current = setTimeout(() => {
|
|
35
35
|
h(n || "/dashboard", { replace: !0 });
|
|
36
36
|
}, 1500);
|
|
37
37
|
}, n = async (e, t) => {
|
|
@@ -41,7 +41,7 @@ function p() {
|
|
|
41
41
|
if (!n.success) throw Error(n.error || "Failed to authenticate with external OIDC provider");
|
|
42
42
|
E("success");
|
|
43
43
|
let r = n.redirectPath || "/dashboard";
|
|
44
|
-
setTimeout(() => {
|
|
44
|
+
A.current = setTimeout(() => {
|
|
45
45
|
h(r, { replace: !0 });
|
|
46
46
|
}, 1500);
|
|
47
47
|
return;
|
|
@@ -55,11 +55,13 @@ function p() {
|
|
|
55
55
|
}
|
|
56
56
|
E("success");
|
|
57
57
|
let r = sessionStorage.getItem("oidc_redirect") || "/dashboard";
|
|
58
|
-
sessionStorage.removeItem("oidc_redirect"), sessionStorage.removeItem("oidc_client_id"), setTimeout(() => {
|
|
58
|
+
sessionStorage.removeItem("oidc_redirect"), sessionStorage.removeItem("oidc_client_id"), A.current = setTimeout(() => {
|
|
59
59
|
h(r, { replace: !0 });
|
|
60
60
|
}, 1500);
|
|
61
61
|
};
|
|
62
|
-
e()
|
|
62
|
+
return e(), () => {
|
|
63
|
+
A.current &&= (clearTimeout(A.current), null);
|
|
64
|
+
};
|
|
63
65
|
}, [
|
|
64
66
|
g,
|
|
65
67
|
h,
|
|
@@ -79,9 +81,9 @@ function p() {
|
|
|
79
81
|
/* @__PURE__ */ d("div", {
|
|
80
82
|
className: "mb-6",
|
|
81
83
|
children: /* @__PURE__ */ d("div", {
|
|
82
|
-
className: "auth-brand-badge mx-auto flex
|
|
84
|
+
className: "auth-brand-badge mx-auto flex size-16 items-center justify-center rounded-xl",
|
|
83
85
|
children: /* @__PURE__ */ d("svg", {
|
|
84
|
-
className: "
|
|
86
|
+
className: "size-8 text-white",
|
|
85
87
|
fill: "none",
|
|
86
88
|
viewBox: "0 0 24 24",
|
|
87
89
|
stroke: "currentColor",
|
|
@@ -105,14 +107,14 @@ function p() {
|
|
|
105
107
|
}),
|
|
106
108
|
/* @__PURE__ */ d("div", {
|
|
107
109
|
className: "flex justify-center",
|
|
108
|
-
children: /* @__PURE__ */ d(
|
|
110
|
+
children: /* @__PURE__ */ d(n, { className: "size-10 text-text-link animate-spin" })
|
|
109
111
|
})
|
|
110
112
|
] }),
|
|
111
113
|
T === "success" && /* @__PURE__ */ f(u, { children: [
|
|
112
114
|
/* @__PURE__ */ d("div", {
|
|
113
|
-
className: "
|
|
115
|
+
className: "size-16 mx-auto mb-4 rounded-full bg-status-success-bg-subtle flex items-center justify-center",
|
|
114
116
|
children: /* @__PURE__ */ d("svg", {
|
|
115
|
-
className: "
|
|
117
|
+
className: "size-8 text-status-success-text",
|
|
116
118
|
fill: "none",
|
|
117
119
|
viewBox: "0 0 24 24",
|
|
118
120
|
stroke: "currentColor",
|
|
@@ -134,13 +136,13 @@ function p() {
|
|
|
134
136
|
}),
|
|
135
137
|
/* @__PURE__ */ d("div", {
|
|
136
138
|
className: "flex justify-center",
|
|
137
|
-
children: /* @__PURE__ */ d(
|
|
139
|
+
children: /* @__PURE__ */ d(n, { className: "size-6 text-status-success-text animate-spin" })
|
|
138
140
|
})
|
|
139
141
|
] }),
|
|
140
142
|
T === "error" && /* @__PURE__ */ f(u, { children: [
|
|
141
143
|
/* @__PURE__ */ d("div", {
|
|
142
|
-
className: "
|
|
143
|
-
children: /* @__PURE__ */ d(
|
|
144
|
+
className: "size-16 mx-auto mb-4 rounded-full bg-status-error-bg-subtle flex items-center justify-center",
|
|
145
|
+
children: /* @__PURE__ */ d(t, { className: "size-8 text-status-error-text" })
|
|
144
146
|
}),
|
|
145
147
|
/* @__PURE__ */ d("h1", {
|
|
146
148
|
className: "text-2xl font-semibold text-text-primary mb-4",
|
|
@@ -153,10 +155,12 @@ function p() {
|
|
|
153
155
|
/* @__PURE__ */ f("div", {
|
|
154
156
|
className: "space-y-3",
|
|
155
157
|
children: [/* @__PURE__ */ d("button", {
|
|
158
|
+
type: "button",
|
|
156
159
|
onClick: () => h("/auth/sso/login", { replace: !0 }),
|
|
157
160
|
className: "auth-primary-button w-full px-6 py-3 font-medium",
|
|
158
161
|
children: m("auth.ssoCallback.tryAgain", "Try Again")
|
|
159
162
|
}), /* @__PURE__ */ d("button", {
|
|
163
|
+
type: "button",
|
|
160
164
|
onClick: () => h("/auth/login", { replace: !0 }),
|
|
161
165
|
className: "w-full px-6 py-3 rounded-xl border border-border-default text-text-primary font-medium hover:bg-bg-sunken transition-colors",
|
|
162
166
|
children: m("auth.ssoCallback.backToLogin", "Back to Login")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SsoCallbackPage.js","names":[],"sources":["../../../src/auth/pages/SsoCallbackPage.tsx"],"sourcesContent":["import { useEffect, useState, useRef } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useNavigate, useSearchParams } from \"react-router-dom\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { useSsoOperations } from \"../hooks/useSsoOperations\";\nimport { SpinnerIcon, AlertIcon } from \"../components/AuthIcons\";\n\n/**\n * SSO Callback Page\n * Handles redirects from:\n * - SAML ACS server (with token/refreshToken in query params)\n * - OIDC Authorization Server (with code/state in query params)\n */\nexport function SsoCallbackPage() {\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 setAuthTokens = useAuthStore((state) => state.setAuthTokens);\n const setAuthenticated = useAuthStore((state) => state.setAuthenticated);\n const {\n exchangeOidcCode,\n validateOidcState,\n isExternalOidcCallback,\n handleExternalOidcCallback,\n } = useSsoOperations();\n\n const [error, setError] = useState<string | null>(null);\n const [status, setStatus] = useState<\"processing\" | \"success\" | \"error\">(\n \"processing\",\n );\n const [callbackType, setCallbackType] = useState<\"saml\" | \"oidc\" | \"unknown\">(\n \"unknown\",\n );\n const processedRef = useRef(false);\n\n useEffect(() => {\n // Prevent double execution in React StrictMode\n if (processedRef.current) {\n return;\n }\n processedRef.current = true;\n\n const processCallback = async () => {\n try {\n // Check for error from either SSO provider\n const errorParam = searchParams.get(\"error\");\n const errorMessage =\n searchParams.get(\"message\") || searchParams.get(\"error_description\");\n\n if (errorParam) {\n throw new Error(\n errorMessage || `SSO authentication failed: ${errorParam}`,\n );\n }\n\n // Detect callback type based on query parameters\n const token = searchParams.get(\"token\");\n const code = searchParams.get(\"code\");\n const state = searchParams.get(\"state\");\n\n if (token) {\n // SAML callback - token already exchanged by ACS server\n setCallbackType(\"saml\");\n await handleSamlCallback(token);\n } else if (code) {\n // OIDC callback - need to exchange code for tokens\n setCallbackType(\"oidc\");\n await handleOidcCallback(code, state);\n } else {\n throw new Error(\n \"Invalid SSO callback. No token or authorization code received.\",\n );\n }\n } catch (err) {\n console.error(\"[SSO Callback] Error:\", err);\n setError(\n err instanceof Error ? err.message : \"Failed to process SSO response\",\n );\n setStatus(\"error\");\n }\n };\n\n /**\n * Handle SAML callback from ACS server\n * Token is already exchanged, just store and redirect\n * Also handles MFA if required\n */\n const handleSamlCallback = async (token: string) => {\n const refreshToken = searchParams.get(\"refreshToken\");\n const redirect = searchParams.get(\"redirect\");\n const requiresMFA = searchParams.get(\"requiresMFA\") === \"true\";\n const mfaChallengeId = searchParams.get(\"mfaChallengeId\");\n\n // Check if MFA is required\n if (requiresMFA && mfaChallengeId) {\n // Store partial auth state and MFA info\n sessionStorage.setItem(\"mfa_challenge_id\", mfaChallengeId);\n sessionStorage.setItem(\"mfa_pending_token\", token);\n sessionStorage.setItem(\"mfa_pending_refresh\", refreshToken || \"\");\n sessionStorage.setItem(\"mfa_redirect\", redirect || \"/dashboard\");\n\n // Redirect to MFA verification\n navigate(\"/auth/mfa-verify\", { replace: true });\n return;\n }\n\n // Store tokens\n setAuthTokens(token, refreshToken || \"\");\n setAuthenticated(true);\n\n setStatus(\"success\");\n\n // Redirect to the specified URL or default to dashboard\n setTimeout(() => {\n const redirectUrl = redirect || \"/dashboard\";\n navigate(redirectUrl, { replace: true });\n }, 1500);\n };\n\n /**\n * Handle OIDC callback - exchange code for tokens\n */\n const handleOidcCallback = async (code: string, state: string | null) => {\n const isExternal = isExternalOidcCallback();\n\n // Check if this is an external OIDC flow (Azure AD, Google, etc.)\n if (isExternal) {\n if (!state) {\n throw new Error(\"State parameter is required for external OIDC flow\");\n }\n\n // Use the external OIDC handler\n const result = await handleExternalOidcCallback(code, state);\n\n if (!result.success) {\n throw new Error(\n result.error ||\n \"Failed to authenticate with external OIDC provider\",\n );\n }\n\n setStatus(\"success\");\n\n // Redirect after brief success message using the redirect path from result\n const redirectUrl = result.redirectPath || \"/dashboard\";\n setTimeout(() => {\n navigate(redirectUrl, { replace: true });\n }, 1500);\n return;\n }\n\n // Internal OIDC flow (our auth service as provider)\n // Validate state to prevent CSRF\n if (state && !validateOidcState(state)) {\n throw new Error(\n \"Invalid state parameter. This may be a CSRF attack. Please try logging in again.\",\n );\n }\n\n // Get client configuration from session storage\n const clientId =\n sessionStorage.getItem(\"oidc_client_id\") || \"default-client\";\n const redirectUri = window.location.origin + \"/auth/sso/callback\";\n\n // Exchange code for tokens\n const result = await exchangeOidcCode(code, clientId, redirectUri);\n\n if (!result.success) {\n throw new Error(\n result.error || \"Failed to exchange authorization code\",\n );\n }\n\n // Check if MFA is required after OIDC authentication\n if (result.requiresMFA && result.mfaChallengeId) {\n // Store MFA challenge info for the verification page\n sessionStorage.setItem(\"mfa_challenge_id\", result.mfaChallengeId);\n sessionStorage.setItem(\n \"mfa_redirect\",\n sessionStorage.getItem(\"oidc_redirect\") || \"/dashboard\",\n );\n\n // Clean up OIDC session data\n sessionStorage.removeItem(\"oidc_redirect\");\n sessionStorage.removeItem(\"oidc_client_id\");\n\n // Redirect to MFA verification\n navigate(\"/auth/mfa-verify\", { replace: true });\n return;\n }\n\n setStatus(\"success\");\n\n // Get redirect URL from state or session storage\n const redirect = sessionStorage.getItem(\"oidc_redirect\") || \"/dashboard\";\n sessionStorage.removeItem(\"oidc_redirect\");\n sessionStorage.removeItem(\"oidc_client_id\");\n\n // Redirect after brief success message\n setTimeout(() => {\n navigate(redirect, { replace: true });\n }, 1500);\n };\n\n processCallback();\n }, [\n searchParams,\n navigate,\n setAuthTokens,\n setAuthenticated,\n exchangeOidcCode,\n validateOidcState,\n isExternalOidcCallback,\n handleExternalOidcCallback,\n ]);\n\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-bg-canvas p-4\">\n <div className=\"w-full max-w-md\">\n <div className=\"bg-bg-surface rounded-2xl shadow-xl p-8 text-center\">\n {/* Logo */}\n <div className=\"mb-6\">\n <div className=\"auth-brand-badge mx-auto flex h-16 w-16 items-center justify-center rounded-xl\">\n <svg\n className=\"w-8 h-8 text-white\"\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>\n\n {/* Processing State */}\n {status === \"processing\" && (\n <>\n <h1 className=\"text-2xl font-semibold text-text-primary mb-4\">\n {tr(\"auth.ssoCallback.completing\", \"Completing Sign In\")}\n </h1>\n <p className=\"text-text-secondary mb-6\">\n {callbackType === \"oidc\"\n ? tr(\n \"auth.ssoCallback.exchangingCode\",\n \"Exchanging authorization code for access tokens...\",\n )\n : callbackType === \"saml\"\n ? tr(\n \"auth.ssoCallback.validatingSaml\",\n \"Validating your SAML credentials...\",\n )\n : tr(\n \"auth.ssoCallback.validatingCreds\",\n \"Validating your credentials from your identity provider...\",\n )}\n </p>\n <div className=\"flex justify-center\">\n <SpinnerIcon className=\"w-10 h-10 text-text-link animate-spin\" />\n </div>\n </>\n )}\n\n {/* Success State */}\n {status === \"success\" && (\n <>\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-status-success-bg-subtle flex items-center justify-center\">\n <svg\n className=\"w-8 h-8 text-status-success-text\"\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=\"M5 13l4 4L19 7\"\n />\n </svg>\n </div>\n <h1 className=\"text-2xl font-semibold text-text-primary mb-4\">\n {tr(\"auth.ssoCallback.success\", \"Sign In Successful\")}\n </h1>\n <p className=\"text-text-secondary mb-6\">\n {callbackType === \"oidc\"\n ? tr(\n \"auth.ssoCallback.oidcComplete\",\n \"OIDC authentication complete. Redirecting...\",\n )\n : callbackType === \"saml\"\n ? tr(\n \"auth.ssoCallback.samlComplete\",\n \"SAML authentication complete. Redirecting...\",\n )\n : tr(\n \"auth.ssoCallback.authSuccess\",\n \"You have been authenticated successfully. Redirecting...\",\n )}\n </p>\n <div className=\"flex justify-center\">\n <SpinnerIcon className=\"w-6 h-6 text-status-success-text animate-spin\" />\n </div>\n </>\n )}\n\n {/* Error State */}\n {status === \"error\" && (\n <>\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 <h1 className=\"text-2xl font-semibold text-text-primary mb-4\">\n {tr(\"auth.ssoCallback.failed\", \"Sign In Failed\")}\n </h1>\n <p className=\"text-status-error-text mb-6 text-sm\">{error}</p>\n <div className=\"space-y-3\">\n <button\n onClick={() => navigate(\"/auth/sso/login\", { replace: true })}\n className=\"auth-primary-button w-full px-6 py-3 font-medium\"\n >\n {tr(\"auth.ssoCallback.tryAgain\", \"Try Again\")}\n </button>\n <button\n onClick={() => navigate(\"/auth/login\", { replace: true })}\n className=\"w-full 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.ssoCallback.backToLogin\", \"Back to Login\")}\n </button>\n </div>\n </>\n )}\n\n {/* SSO Type Badge */}\n {callbackType !== \"unknown\" && (\n <div className=\"mt-6\">\n <span\n className={`inline-flex items-center px-3 py-1 rounded-full text-xs font-medium ${\n callbackType === \"oidc\"\n ? \"bg-accent-purple-subtle text-accent-purple\"\n : \"bg-status-info-bg-subtle text-text-linkHover\"\n }`}\n >\n {callbackType === \"oidc\" ? \"OpenID Connect\" : \"SAML 2.0\"}\n </span>\n </div>\n )}\n\n {/* Help Text */}\n <div className=\"mt-8 pt-6 border-t border-border-subtle\">\n <p className=\"text-xs text-text-secondary\">\n {tr(\n \"auth.ssoCallback.helpText\",\n \"Having trouble? Contact your organization's IT administrator for assistance with SSO login.\",\n )}\n </p>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SsoCallbackPage.js","names":[],"sources":["../../../src/auth/pages/SsoCallbackPage.tsx"],"sourcesContent":["import { useEffect, useState, useRef } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useNavigate, useSearchParams } from \"react-router-dom\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { useSsoOperations } from \"../hooks/useSsoOperations\";\nimport { SpinnerIcon, AlertIcon } from \"../components/AuthIcons\";\n\n/**\n * SSO Callback Page\n * Handles redirects from:\n * - SAML ACS server (with token/refreshToken in query params)\n * - OIDC Authorization Server (with code/state in query params)\n */\nexport function SsoCallbackPage() {\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 setAuthTokens = useAuthStore((state) => state.setAuthTokens);\n const setAuthenticated = useAuthStore((state) => state.setAuthenticated);\n const {\n exchangeOidcCode,\n validateOidcState,\n isExternalOidcCallback,\n handleExternalOidcCallback,\n } = useSsoOperations();\n\n const [error, setError] = useState<string | null>(null);\n const [status, setStatus] = useState<\"processing\" | \"success\" | \"error\">(\n \"processing\",\n );\n const [callbackType, setCallbackType] = useState<\"saml\" | \"oidc\" | \"unknown\">(\n \"unknown\",\n );\n const processedRef = useRef(false);\n const redirectTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n // Prevent double execution in React StrictMode\n if (processedRef.current) {\n return;\n }\n processedRef.current = true;\n\n const processCallback = async () => {\n try {\n // Check for error from either SSO provider\n const errorParam = searchParams.get(\"error\");\n const errorMessage =\n searchParams.get(\"message\") || searchParams.get(\"error_description\");\n\n if (errorParam) {\n throw new Error(\n errorMessage || `SSO authentication failed: ${errorParam}`,\n );\n }\n\n // Detect callback type based on query parameters\n const token = searchParams.get(\"token\");\n const code = searchParams.get(\"code\");\n const state = searchParams.get(\"state\");\n\n if (token) {\n // SAML callback - token already exchanged by ACS server\n setCallbackType(\"saml\");\n await handleSamlCallback(token);\n } else if (code) {\n // OIDC callback - need to exchange code for tokens\n setCallbackType(\"oidc\");\n await handleOidcCallback(code, state);\n } else {\n throw new Error(\n \"Invalid SSO callback. No token or authorization code received.\",\n );\n }\n } catch (err) {\n console.error(\"[SSO Callback] Error:\", err);\n setError(\n err instanceof Error ? err.message : \"Failed to process SSO response\",\n );\n setStatus(\"error\");\n }\n };\n\n /**\n * Handle SAML callback from ACS server\n * Token is already exchanged, just store and redirect\n * Also handles MFA if required\n */\n const handleSamlCallback = async (token: string) => {\n const refreshToken = searchParams.get(\"refreshToken\");\n const redirect = searchParams.get(\"redirect\");\n const requiresMFA = searchParams.get(\"requiresMFA\") === \"true\";\n const mfaChallengeId = searchParams.get(\"mfaChallengeId\");\n\n // Check if MFA is required\n if (requiresMFA && mfaChallengeId) {\n // Store partial auth state and MFA info\n sessionStorage.setItem(\"mfa_challenge_id\", mfaChallengeId);\n sessionStorage.setItem(\"mfa_pending_token\", token);\n sessionStorage.setItem(\"mfa_pending_refresh\", refreshToken || \"\");\n sessionStorage.setItem(\"mfa_redirect\", redirect || \"/dashboard\");\n\n // Redirect to MFA verification\n navigate(\"/auth/mfa-verify\", { replace: true });\n return;\n }\n\n // Store tokens\n setAuthTokens(token, refreshToken || \"\");\n setAuthenticated(true);\n\n setStatus(\"success\");\n\n // Redirect to the specified URL or default to dashboard\n redirectTimerRef.current = setTimeout(() => {\n const redirectUrl = redirect || \"/dashboard\";\n navigate(redirectUrl, { replace: true });\n }, 1500);\n };\n\n /**\n * Handle OIDC callback - exchange code for tokens\n */\n const handleOidcCallback = async (code: string, state: string | null) => {\n const isExternal = isExternalOidcCallback();\n\n // Check if this is an external OIDC flow (Azure AD, Google, etc.)\n if (isExternal) {\n if (!state) {\n throw new Error(\"State parameter is required for external OIDC flow\");\n }\n\n // Use the external OIDC handler\n const result = await handleExternalOidcCallback(code, state);\n\n if (!result.success) {\n throw new Error(\n result.error ||\n \"Failed to authenticate with external OIDC provider\",\n );\n }\n\n setStatus(\"success\");\n\n // Redirect after brief success message using the redirect path from result\n const redirectUrl = result.redirectPath || \"/dashboard\";\n redirectTimerRef.current = setTimeout(() => {\n navigate(redirectUrl, { replace: true });\n }, 1500);\n return;\n }\n\n // Internal OIDC flow (our auth service as provider)\n // Validate state to prevent CSRF\n if (state && !validateOidcState(state)) {\n throw new Error(\n \"Invalid state parameter. This may be a CSRF attack. Please try logging in again.\",\n );\n }\n\n // Get client configuration from session storage\n const clientId =\n sessionStorage.getItem(\"oidc_client_id\") || \"default-client\";\n const redirectUri = window.location.origin + \"/auth/sso/callback\";\n\n // Exchange code for tokens\n const result = await exchangeOidcCode(code, clientId, redirectUri);\n\n if (!result.success) {\n throw new Error(\n result.error || \"Failed to exchange authorization code\",\n );\n }\n\n // Check if MFA is required after OIDC authentication\n if (result.requiresMFA && result.mfaChallengeId) {\n // Store MFA challenge info for the verification page\n sessionStorage.setItem(\"mfa_challenge_id\", result.mfaChallengeId);\n sessionStorage.setItem(\n \"mfa_redirect\",\n sessionStorage.getItem(\"oidc_redirect\") || \"/dashboard\",\n );\n\n // Clean up OIDC session data\n sessionStorage.removeItem(\"oidc_redirect\");\n sessionStorage.removeItem(\"oidc_client_id\");\n\n // Redirect to MFA verification\n navigate(\"/auth/mfa-verify\", { replace: true });\n return;\n }\n\n setStatus(\"success\");\n\n // Get redirect URL from state or session storage\n const redirect = sessionStorage.getItem(\"oidc_redirect\") || \"/dashboard\";\n sessionStorage.removeItem(\"oidc_redirect\");\n sessionStorage.removeItem(\"oidc_client_id\");\n\n // Redirect after brief success message\n redirectTimerRef.current = setTimeout(() => {\n navigate(redirect, { replace: true });\n }, 1500);\n };\n\n processCallback();\n return () => {\n if (redirectTimerRef.current) {\n clearTimeout(redirectTimerRef.current);\n redirectTimerRef.current = null;\n }\n };\n }, [\n searchParams,\n navigate,\n setAuthTokens,\n setAuthenticated,\n exchangeOidcCode,\n validateOidcState,\n isExternalOidcCallback,\n handleExternalOidcCallback,\n ]);\n\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-bg-canvas p-4\">\n <div className=\"w-full max-w-md\">\n <div className=\"bg-bg-surface rounded-2xl shadow-xl p-8 text-center\">\n {/* Logo */}\n <div className=\"mb-6\">\n <div className=\"auth-brand-badge mx-auto flex size-16 items-center justify-center rounded-xl\">\n <svg\n className=\"size-8 text-white\"\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>\n\n {/* Processing State */}\n {status === \"processing\" && (\n <>\n <h1 className=\"text-2xl font-semibold text-text-primary mb-4\">\n {tr(\"auth.ssoCallback.completing\", \"Completing Sign In\")}\n </h1>\n <p className=\"text-text-secondary mb-6\">\n {callbackType === \"oidc\"\n ? tr(\n \"auth.ssoCallback.exchangingCode\",\n \"Exchanging authorization code for access tokens...\",\n )\n : callbackType === \"saml\"\n ? tr(\n \"auth.ssoCallback.validatingSaml\",\n \"Validating your SAML credentials...\",\n )\n : tr(\n \"auth.ssoCallback.validatingCreds\",\n \"Validating your credentials from your identity provider...\",\n )}\n </p>\n <div className=\"flex justify-center\">\n <SpinnerIcon className=\"size-10 text-text-link animate-spin\" />\n </div>\n </>\n )}\n\n {/* Success State */}\n {status === \"success\" && (\n <>\n <div className=\"size-16 mx-auto mb-4 rounded-full bg-status-success-bg-subtle flex items-center justify-center\">\n <svg\n className=\"size-8 text-status-success-text\"\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=\"M5 13l4 4L19 7\"\n />\n </svg>\n </div>\n <h1 className=\"text-2xl font-semibold text-text-primary mb-4\">\n {tr(\"auth.ssoCallback.success\", \"Sign In Successful\")}\n </h1>\n <p className=\"text-text-secondary mb-6\">\n {callbackType === \"oidc\"\n ? tr(\n \"auth.ssoCallback.oidcComplete\",\n \"OIDC authentication complete. Redirecting...\",\n )\n : callbackType === \"saml\"\n ? tr(\n \"auth.ssoCallback.samlComplete\",\n \"SAML authentication complete. Redirecting...\",\n )\n : tr(\n \"auth.ssoCallback.authSuccess\",\n \"You have been authenticated successfully. Redirecting...\",\n )}\n </p>\n <div className=\"flex justify-center\">\n <SpinnerIcon className=\"size-6 text-status-success-text animate-spin\" />\n </div>\n </>\n )}\n\n {/* Error State */}\n {status === \"error\" && (\n <>\n <div className=\"size-16 mx-auto mb-4 rounded-full bg-status-error-bg-subtle flex items-center justify-center\">\n <AlertIcon className=\"size-8 text-status-error-text\" />\n </div>\n <h1 className=\"text-2xl font-semibold text-text-primary mb-4\">\n {tr(\"auth.ssoCallback.failed\", \"Sign In Failed\")}\n </h1>\n <p className=\"text-status-error-text mb-6 text-sm\">{error}</p>\n <div className=\"space-y-3\">\n <button type=\"button\"\n onClick={() => navigate(\"/auth/sso/login\", { replace: true })}\n className=\"auth-primary-button w-full px-6 py-3 font-medium\"\n >\n {tr(\"auth.ssoCallback.tryAgain\", \"Try Again\")}\n </button>\n <button type=\"button\"\n onClick={() => navigate(\"/auth/login\", { replace: true })}\n className=\"w-full 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.ssoCallback.backToLogin\", \"Back to Login\")}\n </button>\n </div>\n </>\n )}\n\n {/* SSO Type Badge */}\n {callbackType !== \"unknown\" && (\n <div className=\"mt-6\">\n <span\n className={`inline-flex items-center px-3 py-1 rounded-full text-xs font-medium ${\n callbackType === \"oidc\"\n ? \"bg-accent-purple-subtle text-accent-purple\"\n : \"bg-status-info-bg-subtle text-text-linkHover\"\n }`}\n >\n {callbackType === \"oidc\" ? \"OpenID Connect\" : \"SAML 2.0\"}\n </span>\n </div>\n )}\n\n {/* Help Text */}\n <div className=\"mt-8 pt-6 border-t border-border-subtle\">\n <p className=\"text-xs text-text-secondary\">\n {tr(\n \"auth.ssoCallback.helpText\",\n \"Having trouble? Contact your organization's IT administrator for assistance with SSO login.\",\n )}\n </p>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import "../hooks/
|
|
4
|
-
import { AlertIcon as n, SpinnerIcon as r } from "../components/AuthIcons.js";
|
|
1
|
+
import { AlertIcon as e, SpinnerIcon as t } from "../components/AuthIcons.js";
|
|
2
|
+
import { useSsoOperations as n } from "../hooks/useSsoOperations.js";
|
|
3
|
+
import { useAuthPermissions as r } from "../hooks/useAuthPermissions.js";
|
|
5
4
|
import { ConfirmActionDialog as i } from "../components/ConfirmActionDialog.js";
|
|
6
5
|
import { nativeCopyText as a, nativeImpact as o, nativeNotify as s } from "../../utils/nativeBridge.js";
|
|
7
6
|
import { useCallback as c, useEffect as l, useRef as ee, useState as u } from "react";
|
|
@@ -47,7 +46,7 @@ function g(e) {
|
|
|
47
46
|
}
|
|
48
47
|
}
|
|
49
48
|
function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
50
|
-
let _ = te(), [v] = d(), { canManageSsoConfig: y, isLoading: ie } =
|
|
49
|
+
let _ = te(), [v] = d(), { canManageSsoConfig: y, isLoading: ie } = r(), ae = re("workspace.auth.enterprise-sso"), oe = a || ae?.value === !0, b = ee(null), x = v.get("tenant"), S = v.get("org"), C = v.get("workspace"), { ssoConfig: w, oidcConfig: T, isLoading: E, isSaving: D, isDeleting: O, saveSsoConfig: k, deleteSsoConfig: se } = n(x ?? "burdenoff.com"), { t: A } = ne(), j = c((e, t) => {
|
|
51
50
|
let n = A(e);
|
|
52
51
|
return n === e ? t : n;
|
|
53
52
|
}, [A]), [M, ce] = u("saml"), [N, P] = u(!1), [le, F] = u(!1), [I, L] = u(null), [R, z] = u(null), [B, V] = u(""), [H, U] = u(!1), [W, G] = u(!1), [K, q] = u({
|
|
@@ -74,7 +73,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
74
73
|
className: "max-w-5xl mx-auto p-6",
|
|
75
74
|
children: /* @__PURE__ */ m("div", {
|
|
76
75
|
className: "text-center py-16",
|
|
77
|
-
children: [/* @__PURE__ */ p(
|
|
76
|
+
children: [/* @__PURE__ */ p(t, { className: "size-8 mx-auto text-text-secondary animate-spin" }), /* @__PURE__ */ p("p", {
|
|
78
77
|
className: "mt-4 text-text-secondary",
|
|
79
78
|
children: j("auth.sso.loadingPermissions", "Loading permissions...")
|
|
80
79
|
})]
|
|
@@ -110,11 +109,12 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
110
109
|
children: [/* @__PURE__ */ m("div", {
|
|
111
110
|
className: "flex items-center gap-4",
|
|
112
111
|
children: [/* @__PURE__ */ p("button", {
|
|
112
|
+
type: "button",
|
|
113
113
|
onClick: () => _("/auth/security"),
|
|
114
114
|
"aria-label": j("auth.sso.backToSecurity", "Back to Security"),
|
|
115
115
|
className: "p-2 rounded-lg hover:bg-bg-sunken transition-colors",
|
|
116
116
|
children: /* @__PURE__ */ p("svg", {
|
|
117
|
-
className: "
|
|
117
|
+
className: "size-5 text-text-secondary",
|
|
118
118
|
fill: "none",
|
|
119
119
|
viewBox: "0 0 24 24",
|
|
120
120
|
stroke: "currentColor",
|
|
@@ -139,6 +139,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
139
139
|
className: `px-3 py-1 rounded-full text-sm font-medium ${Q.enabled ? "bg-status-success-bg-subtle text-status-success-text" : "bg-bg-sunken text-text-secondary"}`,
|
|
140
140
|
children: Q.enabled ? j("auth.sso.enabled", "Enabled") : j("auth.sso.disabled", "Disabled")
|
|
141
141
|
}), /* @__PURE__ */ p("button", {
|
|
142
|
+
type: "button",
|
|
142
143
|
onClick: async () => {
|
|
143
144
|
L(null);
|
|
144
145
|
try {
|
|
@@ -202,12 +203,13 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
202
203
|
}),
|
|
203
204
|
I && /* @__PURE__ */ m("div", {
|
|
204
205
|
className: "mb-6 flex items-start gap-3 p-4 rounded-xl bg-status-error-bg-subtle border border-status-error-border",
|
|
205
|
-
children: [/* @__PURE__ */ p(
|
|
206
|
+
children: [/* @__PURE__ */ p(e, { className: "size-5 text-status-error-text flex-shrink-0 mt-0.5" }), /* @__PURE__ */ m("div", {
|
|
206
207
|
className: "flex-1",
|
|
207
208
|
children: [/* @__PURE__ */ p("p", {
|
|
208
209
|
className: "text-sm text-status-error-text",
|
|
209
210
|
children: I
|
|
210
211
|
}), /* @__PURE__ */ p("button", {
|
|
212
|
+
type: "button",
|
|
211
213
|
onClick: () => L(null),
|
|
212
214
|
className: "mt-2 text-sm text-status-error-text hover:underline",
|
|
213
215
|
children: j("auth.sso.dismiss", "Dismiss")
|
|
@@ -217,7 +219,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
217
219
|
R && /* @__PURE__ */ m("div", {
|
|
218
220
|
className: "mb-6 flex items-start gap-3 p-4 rounded-xl bg-status-success-bg-subtle border border-status-success-border",
|
|
219
221
|
children: [/* @__PURE__ */ p("svg", {
|
|
220
|
-
className: "
|
|
222
|
+
className: "size-5 text-status-success-text flex-shrink-0 mt-0.5",
|
|
221
223
|
fill: "currentColor",
|
|
222
224
|
viewBox: "0 0 20 20",
|
|
223
225
|
children: /* @__PURE__ */ p("path", {
|
|
@@ -231,6 +233,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
231
233
|
className: "text-sm text-status-success-text",
|
|
232
234
|
children: R
|
|
233
235
|
}), /* @__PURE__ */ p("button", {
|
|
236
|
+
type: "button",
|
|
234
237
|
onClick: () => z(null),
|
|
235
238
|
className: "mt-2 text-sm text-status-success-text hover:underline",
|
|
236
239
|
children: j("auth.sso.dismiss", "Dismiss")
|
|
@@ -263,6 +266,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
263
266
|
icon: "🧪"
|
|
264
267
|
}
|
|
265
268
|
].map((e) => /* @__PURE__ */ m("button", {
|
|
269
|
+
type: "button",
|
|
266
270
|
onClick: () => ce(e.id),
|
|
267
271
|
className: `pb-3 text-sm font-medium transition-colors relative ${M === e.id ? "text-text-link" : "text-text-secondary hover:text-text-primary"}`,
|
|
268
272
|
children: [/* @__PURE__ */ m("span", {
|
|
@@ -274,7 +278,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
274
278
|
}),
|
|
275
279
|
E && /* @__PURE__ */ m("div", {
|
|
276
280
|
className: "flex items-center justify-center py-12",
|
|
277
|
-
children: [/* @__PURE__ */ p(
|
|
281
|
+
children: [/* @__PURE__ */ p(t, { className: "size-8 text-text-link animate-spin" }), /* @__PURE__ */ p("span", {
|
|
278
282
|
className: "ml-3 text-text-secondary",
|
|
279
283
|
children: j("auth.sso.loadingConfig", "Loading configuration...")
|
|
280
284
|
})]
|
|
@@ -353,8 +357,8 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
353
357
|
/* @__PURE__ */ m("label", {
|
|
354
358
|
htmlFor: "metadata-file",
|
|
355
359
|
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",
|
|
356
|
-
children: [H ? /* @__PURE__ */ p(
|
|
357
|
-
className: "
|
|
360
|
+
children: [H ? /* @__PURE__ */ p(t, { className: "size-5 animate-spin text-text-link" }) : /* @__PURE__ */ p("svg", {
|
|
361
|
+
className: "size-5 text-text-tertiary",
|
|
358
362
|
fill: "none",
|
|
359
363
|
viewBox: "0 0 24 24",
|
|
360
364
|
stroke: "currentColor",
|
|
@@ -412,8 +416,8 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
412
416
|
},
|
|
413
417
|
disabled: H || !B,
|
|
414
418
|
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",
|
|
415
|
-
children: [H ? /* @__PURE__ */ p(
|
|
416
|
-
className: "
|
|
419
|
+
children: [H ? /* @__PURE__ */ p(t, { className: "size-4 animate-spin" }) : /* @__PURE__ */ p("svg", {
|
|
420
|
+
className: "size-4",
|
|
417
421
|
fill: "none",
|
|
418
422
|
viewBox: "0 0 24 24",
|
|
419
423
|
stroke: "currentColor",
|
|
@@ -452,6 +456,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
452
456
|
className: "flex-1 px-3 py-2 rounded-lg bg-bg-sunken text-sm text-text-primary font-mono",
|
|
453
457
|
children: [window.location.origin, "/auth/saml/metadata"]
|
|
454
458
|
}), /* @__PURE__ */ p("button", {
|
|
459
|
+
type: "button",
|
|
455
460
|
onClick: () => void h(`${window.location.origin}/auth/saml/metadata`),
|
|
456
461
|
className: "px-3 py-2 rounded-lg border border-border-default text-text-secondary hover:bg-bg-sunken",
|
|
457
462
|
children: j("auth.sso.copy", "Copy")
|
|
@@ -465,6 +470,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
465
470
|
className: "flex-1 px-3 py-2 rounded-lg bg-bg-sunken text-sm text-text-primary font-mono",
|
|
466
471
|
children: [window.location.origin, "/auth/sso/callback"]
|
|
467
472
|
}), /* @__PURE__ */ p("button", {
|
|
473
|
+
type: "button",
|
|
468
474
|
onClick: () => void h(`${window.location.origin}/auth/sso/callback`),
|
|
469
475
|
className: "px-3 py-2 rounded-lg border border-border-default text-text-secondary hover:bg-bg-sunken",
|
|
470
476
|
children: j("auth.sso.copy", "Copy")
|
|
@@ -637,7 +643,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
637
643
|
type: "submit",
|
|
638
644
|
disabled: D,
|
|
639
645
|
className: "auth-primary-button flex items-center gap-2 px-6 py-3 font-medium",
|
|
640
|
-
children: D ? /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p(
|
|
646
|
+
children: D ? /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p(t, { className: "size-4 animate-spin" }), j("auth.sso.saving", "Saving...")] }) : j("auth.sso.saveConfig", "Save Configuration")
|
|
641
647
|
}), N && /* @__PURE__ */ p("button", {
|
|
642
648
|
type: "button",
|
|
643
649
|
onClick: () => {
|
|
@@ -667,10 +673,11 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
667
673
|
children: j("auth.sso.dangerZoneDesc", "Deleting the SSO configuration will prevent users from signing in with their enterprise credentials. This action cannot be undone.")
|
|
668
674
|
}),
|
|
669
675
|
/* @__PURE__ */ p("button", {
|
|
676
|
+
type: "button",
|
|
670
677
|
onClick: () => F(!0),
|
|
671
678
|
disabled: O,
|
|
672
679
|
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",
|
|
673
|
-
children: O ? /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p(
|
|
680
|
+
children: O ? /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p(t, { className: "size-4 animate-spin" }), j("auth.sso.deleting", "Deleting...")] }) : j("auth.sso.deleteConfig", "Delete SSO Configuration")
|
|
674
681
|
})
|
|
675
682
|
]
|
|
676
683
|
})
|
|
@@ -706,6 +713,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
706
713
|
className: "flex-1 px-3 py-2 rounded-lg bg-bg-sunken text-sm text-text-primary font-mono break-all",
|
|
707
714
|
children: T?.issuer ? `${T.issuer}/.well-known/openid-configuration` : "Discovery endpoint unavailable until OIDC is configured"
|
|
708
715
|
}), /* @__PURE__ */ p("button", {
|
|
716
|
+
type: "button",
|
|
709
717
|
onClick: () => {
|
|
710
718
|
let e = T?.issuer ? `${T.issuer}/.well-known/openid-configuration` : "";
|
|
711
719
|
e && h(e);
|
|
@@ -791,7 +799,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
791
799
|
}
|
|
792
800
|
].map((e) => /* @__PURE__ */ m("div", {
|
|
793
801
|
className: "flex items-center gap-2",
|
|
794
|
-
children: [/* @__PURE__ */ p("span", { className: `
|
|
802
|
+
children: [/* @__PURE__ */ p("span", { className: `size-2 rounded-full ${e.status ? "bg-status-success-text" : "bg-bg-sunken"}` }), /* @__PURE__ */ p("span", {
|
|
795
803
|
className: "text-sm text-text-primary",
|
|
796
804
|
children: e.name
|
|
797
805
|
})]
|
|
@@ -824,10 +832,11 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
824
832
|
className: "text-sm text-status-success-text mt-1",
|
|
825
833
|
children: j("auth.sso.clientCreatedDesc", "Save these credentials securely. The client secret will not be shown again.")
|
|
826
834
|
})] }), /* @__PURE__ */ p("button", {
|
|
835
|
+
type: "button",
|
|
827
836
|
onClick: () => Z(null),
|
|
828
837
|
className: "text-status-success-text hover:text-status-success-text",
|
|
829
838
|
children: /* @__PURE__ */ p("svg", {
|
|
830
|
-
className: "
|
|
839
|
+
className: "size-5",
|
|
831
840
|
fill: "none",
|
|
832
841
|
viewBox: "0 0 24 24",
|
|
833
842
|
stroke: "currentColor",
|
|
@@ -851,6 +860,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
851
860
|
className: "flex-1 px-3 py-2 rounded-lg bg-bg-surface text-sm font-mono border border-status-success-border",
|
|
852
861
|
children: X.client_id
|
|
853
862
|
}), /* @__PURE__ */ p("button", {
|
|
863
|
+
type: "button",
|
|
854
864
|
onClick: () => void h(X.client_id),
|
|
855
865
|
className: "px-3 py-2 rounded-lg bg-status-success-bg text-white text-sm hover:bg-status-success-bg",
|
|
856
866
|
children: j("auth.sso.copy", "Copy")
|
|
@@ -865,6 +875,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
865
875
|
className: "flex-1 px-3 py-2 rounded-lg bg-bg-surface text-sm font-mono border border-status-success-border",
|
|
866
876
|
children: X.client_secret
|
|
867
877
|
}), /* @__PURE__ */ p("button", {
|
|
878
|
+
type: "button",
|
|
868
879
|
onClick: () => void h(X.client_secret || ""),
|
|
869
880
|
className: "px-3 py-2 rounded-lg bg-status-success-bg text-white text-sm hover:bg-status-success-bg",
|
|
870
881
|
children: j("auth.sso.copy", "Copy")
|
|
@@ -888,10 +899,11 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
888
899
|
className: "text-lg font-medium text-text-primary",
|
|
889
900
|
children: j("auth.sso.registerClient", "Register New Client")
|
|
890
901
|
}), !W && /* @__PURE__ */ m("button", {
|
|
902
|
+
type: "button",
|
|
891
903
|
onClick: () => G(!0),
|
|
892
904
|
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",
|
|
893
905
|
children: [/* @__PURE__ */ p("svg", {
|
|
894
|
-
className: "
|
|
906
|
+
className: "size-4",
|
|
895
907
|
fill: "none",
|
|
896
908
|
viewBox: "0 0 24 24",
|
|
897
909
|
stroke: "currentColor",
|
|
@@ -986,7 +998,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
986
998
|
grant_types: K.grant_types.filter((t) => t !== e)
|
|
987
999
|
});
|
|
988
1000
|
},
|
|
989
|
-
className: "
|
|
1001
|
+
className: "size-4 rounded border-border-default text-text-link focus:ring-action-primary-bg"
|
|
990
1002
|
}), /* @__PURE__ */ p("span", {
|
|
991
1003
|
className: "text-sm text-text-primary",
|
|
992
1004
|
children: e.replace(/_/g, " ")
|
|
@@ -1023,6 +1035,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
1023
1035
|
/* @__PURE__ */ m("div", {
|
|
1024
1036
|
className: "flex items-center gap-3 pt-2",
|
|
1025
1037
|
children: [/* @__PURE__ */ p("button", {
|
|
1038
|
+
type: "button",
|
|
1026
1039
|
onClick: async () => {
|
|
1027
1040
|
if (!K.client_name || !K.redirect_uris) {
|
|
1028
1041
|
L(j("auth.sso.clientRequired", "Client name and redirect URI are required"));
|
|
@@ -1061,8 +1074,9 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
1061
1074
|
},
|
|
1062
1075
|
disabled: J,
|
|
1063
1076
|
className: "auth-primary-button flex items-center gap-2 px-6 py-3 font-medium",
|
|
1064
|
-
children: J ? /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p(
|
|
1077
|
+
children: J ? /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p(t, { className: "size-4 animate-spin" }), j("auth.sso.registering", "Registering...")] }) : j("auth.sso.registerClientButton", "Register Client")
|
|
1065
1078
|
}), /* @__PURE__ */ p("button", {
|
|
1079
|
+
type: "button",
|
|
1066
1080
|
onClick: () => {
|
|
1067
1081
|
G(!1), q({
|
|
1068
1082
|
client_name: "",
|
|
@@ -1079,7 +1093,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
1079
1093
|
}) : /* @__PURE__ */ m("div", {
|
|
1080
1094
|
className: "text-center py-8 text-text-secondary",
|
|
1081
1095
|
children: [/* @__PURE__ */ p("svg", {
|
|
1082
|
-
className: "
|
|
1096
|
+
className: "size-12 mx-auto mb-3 text-text-muted",
|
|
1083
1097
|
fill: "none",
|
|
1084
1098
|
viewBox: "0 0 24 24",
|
|
1085
1099
|
stroke: "currentColor",
|
|
@@ -1170,7 +1184,7 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
1170
1184
|
href: `${window.location.origin}/auth/sso/login`,
|
|
1171
1185
|
className: "inline-flex items-center gap-2 px-6 py-3 rounded-xl bg-status-success-bg text-white font-medium shadow-sm hover:opacity-90 transition-all duration-200",
|
|
1172
1186
|
children: [/* @__PURE__ */ p("svg", {
|
|
1173
|
-
className: "
|
|
1187
|
+
className: "size-5",
|
|
1174
1188
|
fill: "none",
|
|
1175
1189
|
viewBox: "0 0 24 24",
|
|
1176
1190
|
stroke: "currentColor",
|
|
@@ -1206,8 +1220,8 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
1206
1220
|
className: "text-center py-16 border-2 border-dashed border-border-subtle rounded-xl",
|
|
1207
1221
|
children: [
|
|
1208
1222
|
/* @__PURE__ */ p("div", {
|
|
1209
|
-
className: "
|
|
1210
|
-
children: /* @__PURE__ */ p(
|
|
1223
|
+
className: "size-16 mx-auto mb-4 rounded-full bg-status-warning-bg-subtle flex items-center justify-center",
|
|
1224
|
+
children: /* @__PURE__ */ p(e, { className: "size-8 text-status-warning-text" })
|
|
1211
1225
|
}),
|
|
1212
1226
|
/* @__PURE__ */ p("h2", {
|
|
1213
1227
|
className: "text-xl font-semibold text-text-primary mb-2",
|
|
@@ -1229,8 +1243,8 @@ function _({ bypassEnterprisePlanGate: a = !1 }) {
|
|
|
1229
1243
|
className: "text-center py-16 border-2 border-dashed border-border-subtle rounded-xl",
|
|
1230
1244
|
children: [
|
|
1231
1245
|
/* @__PURE__ */ p("div", {
|
|
1232
|
-
className: "
|
|
1233
|
-
children: /* @__PURE__ */ p(
|
|
1246
|
+
className: "size-16 mx-auto mb-4 rounded-full bg-status-error-bg-subtle flex items-center justify-center",
|
|
1247
|
+
children: /* @__PURE__ */ p(e, { className: "size-8 text-status-error-text" })
|
|
1234
1248
|
}),
|
|
1235
1249
|
/* @__PURE__ */ p("h2", {
|
|
1236
1250
|
className: "text-xl font-semibold text-text-primary mb-2",
|