From 4f6e57cc9c4c8d5f9eaade0dcf868dca6a2e7a9c Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Sat, 6 Jun 2026 03:37:31 -0600 Subject: [PATCH] refactor: simplify forward authentication handling in UI and API - Removed the selection of SSO providers from the UI, streamlining the process to enable/disable SSO for domains. - Updated the API to eliminate the need for a provider ID when enabling forward authentication, relying on the configured settings instead. - Enhanced user feedback by updating toast messages to reflect the current state of SSO authentication. - Improved the UI layout for better clarity on SSO status and actions. This refactor enhances the user experience by simplifying the SSO configuration process and ensuring clearer communication of actions taken. --- .../domains/handle-forward-auth.tsx | 140 +++++------------- .../api/routers/proprietary/forward-auth.ts | 9 +- .../src/services/proprietary/forward-auth.ts | 9 +- 3 files changed, 42 insertions(+), 116 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/domains/handle-forward-auth.tsx b/apps/dokploy/components/dashboard/application/domains/handle-forward-auth.tsx index 66638e87e..86bf0a5b4 100644 --- a/apps/dokploy/components/dashboard/application/domains/handle-forward-auth.tsx +++ b/apps/dokploy/components/dashboard/application/domains/handle-forward-auth.tsx @@ -1,5 +1,5 @@ import { ShieldCheck } from "lucide-react"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import { toast } from "sonner"; import { AlertBlock } from "@/components/shared/alert-block"; import { Button } from "@/components/ui/button"; @@ -12,13 +12,7 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; +import { Switch } from "@/components/ui/switch"; import { api } from "@/utils/api"; interface Props { @@ -28,35 +22,28 @@ interface Props { export const HandleForwardAuth = ({ domainId, applicationId }: Props) => { const [isOpen, setIsOpen] = useState(false); - const [selectedProviderId, setSelectedProviderId] = useState(""); const { data: haveValidLicense } = api.licenseKey.haveValidLicenseKey.useQuery(); const utils = api.useUtils(); - const { data: status, isLoading: isLoadingStatus } = - api.forwardAuth.status.useQuery({ domainId }, { enabled: isOpen }); - const { data: providers, isLoading: isLoadingProviders } = - api.forwardAuth.listProviders.useQuery(undefined, { enabled: isOpen }); + const { data: status } = api.forwardAuth.status.useQuery( + { domainId }, + { enabled: isOpen }, + ); const { mutateAsync: enable, isPending: isEnabling } = api.forwardAuth.enable.useMutation(); const { mutateAsync: disable, isPending: isDisabling } = api.forwardAuth.disable.useMutation(); - useEffect(() => { - if (status?.providerId) { - setSelectedProviderId(status.providerId); - } - }, [status?.providerId]); - if (!haveValidLicense) { return null; } const isEnabled = !!status?.enabled; - const hasProviders = (providers?.length ?? 0) > 0; + const isPending = isEnabling || isDisabling; const refresh = async () => { await utils.forwardAuth.status.invalidate({ domainId }); @@ -64,32 +51,21 @@ export const HandleForwardAuth = ({ domainId, applicationId }: Props) => { await utils.application.readTraefikConfig.invalidate({ applicationId }); }; - const handleEnable = async () => { - if (!selectedProviderId) { - toast.error("Select an SSO provider first"); - return; - } + const handleToggle = async (next: boolean) => { try { - await enable({ domainId, providerId: selectedProviderId }); + if (next) { + await enable({ domainId }); + toast.success("SSO authentication enabled for this domain"); + } else { + await disable({ domainId }); + toast.success("SSO authentication disabled for this domain"); + } await refresh(); - toast.success("SSO authentication enabled for this domain"); - setIsOpen(false); } catch (error) { toast.error( - error instanceof Error ? error.message : "Error enabling SSO", - ); - } - }; - - const handleDisable = async () => { - try { - await disable({ domainId }); - await refresh(); - toast.success("SSO authentication disabled for this domain"); - setIsOpen(false); - } catch (error) { - toast.error( - error instanceof Error ? error.message : "Error disabling SSO", + error instanceof Error + ? error.message + : "Error updating SSO authentication", ); } }; @@ -121,72 +97,32 @@ export const HandleForwardAuth = ({ domainId, applicationId }: Props) => { - {!isLoadingProviders && !hasProviders && ( - - No SSO providers configured. Add an OIDC provider in your - organization SSO settings first. - - )} - - Requires the authentication domain + proxy to be configured in SSO - settings, and this app's domain to share its base domain. + The authentication proxy must be deployed for this app's server in SSO + settings. The domain must share its base domain. -
-
- Identity provider - +
+
+ + Protect this domain with SSO + + + {isEnabled + ? "Visitors must log in via your identity provider." + : "The domain is publicly accessible."} +
- - {isEnabled && ( - - SSO is currently enabled for this domain. - - )} +
- - {isEnabled && ( - - )} - diff --git a/apps/dokploy/server/api/routers/proprietary/forward-auth.ts b/apps/dokploy/server/api/routers/proprietary/forward-auth.ts index 6890e8d61..6eb00b902 100644 --- a/apps/dokploy/server/api/routers/proprietary/forward-auth.ts +++ b/apps/dokploy/server/api/routers/proprietary/forward-auth.ts @@ -124,12 +124,7 @@ export const forwardAuthRouter = createTRPCRouter({ .query(({ ctx, input }) => getDomainSsoStatus(ctx, input.domainId)), enable: enterpriseProcedure - .input( - z.object({ - domainId: z.string().min(1), - providerId: z.string().min(1), - }), - ) + .input(z.object({ domainId: z.string().min(1) })) .mutation(async ({ ctx, input }) => { const domain = await assertApplicationDomainAccess( ctx, @@ -138,8 +133,6 @@ export const forwardAuthRouter = createTRPCRouter({ ); const result = await enableForwardAuthOnDomain({ domainId: input.domainId, - providerId: input.providerId, - organizationId: ctx.session.activeOrganizationId, }); await audit(ctx, { action: "update", diff --git a/packages/server/src/services/proprietary/forward-auth.ts b/packages/server/src/services/proprietary/forward-auth.ts index 6d9d53e9b..a43f4b3ec 100644 --- a/packages/server/src/services/proprietary/forward-auth.ts +++ b/packages/server/src/services/proprietary/forward-auth.ts @@ -326,19 +326,16 @@ export const assertApplicationDomainAccess = async ( export const enableForwardAuthOnDomain = async (input: { domainId: string; - providerId: string; - organizationId: string; }) => { const { application } = await resolveApplicationDomain(input.domainId); - await findProviderForOrg(input.providerId, input.organizationId); const serverId = application.serverId ?? undefined; const settings = await getForwardAuthSettings(serverId ?? null); - if (!settings) { + if (!settings?.providerId) { throw new TRPCError({ code: "PRECONDITION_FAILED", message: - "Set the authentication domain and deploy the proxy for this server first.", + "Deploy the authentication proxy for this server in SSO settings first.", }); } @@ -352,7 +349,7 @@ export const enableForwardAuthOnDomain = async (input: { } await updateDomainById(input.domainId, { - forwardAuthProviderId: input.providerId, + forwardAuthProviderId: settings.providerId, }); const domain = await findDomainById(input.domainId); await manageDomain(application, domain);