Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
f680818
Add enterprise features management: implement license key settings an…
Siumauricio Jan 28, 2026
25fa362
Add enterprise features management: implement license key settings an…
Siumauricio Jan 29, 2026
0c299a3
Refactor license key management: update API calls to use licenseKey r…
Siumauricio Jan 29, 2026
709ffdd
Update better-auth dependency to version 1.2.8 and enhance license ke…
Siumauricio Jan 29, 2026
262960a
Refactor license key management: remove legacy license key settings c…
Siumauricio Jan 29, 2026
cbfa690
Improve error handling in license key management: update error loggin…
Siumauricio Jan 29, 2026
c9ffb99
Refactor license key deactivation process: update API to retrieve the…
Siumauricio Jan 29, 2026
346216f
Add License Settings Page: Introduce a new License settings page with…
Siumauricio Jan 29, 2026
2b52332
Enhance License Key Management: Add loading state for license key val…
Siumauricio Jan 29, 2026
2e7f4dc
Refactor License Key Settings UI: Simplify conditional rendering for …
Siumauricio Jan 29, 2026
7f27601
Implement Single Sign-On (SSO) Feature: Add SSO settings page, integr…
Siumauricio Jan 30, 2026
6064b8c
Implement SAML Provider Registration and Enhance OIDC Dialog: Add a n…
Siumauricio Jan 30, 2026
9a8de9a
Add Enterprise Feature Gate Component: Introduce EnterpriseFeatureGat…
Siumauricio Jan 30, 2026
12a87f9
Enhance License Key Management and Enterprise Features: Update licens…
Siumauricio Jan 30, 2026
82c06a4
Remove refresh-license-validity API endpoint and integrate enterprise…
Siumauricio Jan 30, 2026
f72bc28
Refactor enterprise backup cron job initialization: Simplified the cr…
Siumauricio Jan 30, 2026
30c3e44
Refactor SSO Registration Dialogs: Remove onSuccess prop from Registe…
Siumauricio Jan 30, 2026
61f6bbf
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 31, 2026
3c2f675
Enhance SSO Functionality: Add detailed view for SSO providers in SSO…
Siumauricio Jan 31, 2026
1f33b0f
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 31, 2026
c4515a2
Fix admin creation check in authentication logic: Re-enable the check…
Siumauricio Jan 31, 2026
66b4bf2
Comment out user, session, account, verification, and apikey table de…
Siumauricio Jan 31, 2026
f3d9960
Implement SSO Sign-In Options: Add components for signing in with Git…
Siumauricio Jan 31, 2026
cae7a92
Refactor SSO Registration Dialogs: Update RegisterOidcDialog and Regi…
Siumauricio Jan 31, 2026
68587c3
Add SSO Provider Integration: Introduce getSSOProviders function to f…
Siumauricio Jan 31, 2026
acb3c1d
Add Sign-In Options for Cloud Users: Integrate GitHub and Google sign…
Siumauricio Jan 31, 2026
bc5c65b
Merge branch 'canary' into feat/introduce-license-key-pay
Siumauricio Jan 31, 2026
d22d961
feat(auth): add SSO request handling and provider validation in authe…
Siumauricio Jan 31, 2026
d5de5b8
feat(sso): implement SSO provider registration and update related com…
Siumauricio Jan 31, 2026
7665b38
feat(sso): refine provider query to include user ID for enhanced secu…
Siumauricio Jan 31, 2026
6b42c9d
feat(auth): expand disabled paths for SSO registration and organizati…
Siumauricio Jan 31, 2026
54229b0
Merge branch 'canary' into feat/introduce-license-key-pay
Siumauricio Jan 31, 2026
69ba901
feat(sso): update SSO provider registration to handle multiple domains
Siumauricio Jan 31, 2026
fb06cf8
feat(auth): add Okta domain to SSO provider list and adjust SSO reque…
Siumauricio Jan 31, 2026
dc756e2
refactor(auth): rename forgetPassword to requestPasswordReset for cla…
Siumauricio Jan 31, 2026
00ce8ca
feat(license): enhance license key management and authorization checks
Siumauricio Feb 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions apps/dokploy/components/layouts/side.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ import {
Forward,
GalleryVerticalEnd,
GitBranch,
Key,
KeyRound,
Loader2,
LogIn,
type LucideIcon,
Package,
PieChart,
Expand Down Expand Up @@ -396,6 +398,24 @@ const MENU: Menu = {
// Only enabled for admins in cloud environments
isEnabled: ({ auth, isCloud }) => !!(auth?.role === "owner" && isCloud),
},
{
isSingle: true,
title: "License",
url: "/dashboard/settings/license",
icon: Key,
// Only enabled for admins in non-cloud environments
isEnabled: ({ auth }) =>
!!(auth?.role === "owner" || auth?.role === "admin"),
},
{
isSingle: true,
title: "SSO",
url: "/dashboard/settings/sso",
icon: LogIn,
// Enabled for admins in both cloud and self-hosted (enterprise)
isEnabled: ({ auth }) =>
!!(auth?.role === "owner" || auth?.role === "admin"),
},
],

help: [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"use client";

import { useState } from "react";
import { toast } from "sonner";
import { authClient } from "@/lib/auth-client";
import { Button } from "@/components/ui/button";

export function SignInWithGithub() {
const [isLoading, setIsLoading] = useState(false);

const handleClick = async () => {
setIsLoading(true);
try {
const { error } = await authClient.signIn.social({
provider: "github",
});
if (error) {
toast.error(error.message);
return;
}
} catch (err) {
toast.error("An error occurred while signing in with GitHub", {
description: err instanceof Error ? err.message : "Unknown error",
});
} finally {
setIsLoading(false);
}
};

return (
<Button
variant="outline"
type="button"
className="w-full mb-4"
onClick={handleClick}
isLoading={isLoading}
>
<svg viewBox="0 0 438.549 438.549" className="mr-2 size-4">
<path
fill="currentColor"
d="M409.132 114.573c-19.608-33.596-46.205-60.194-79.798-79.8-33.598-19.607-70.277-29.408-110.063-29.408-39.781 0-76.472 9.804-110.063 29.408-33.596 19.605-60.192 46.204-79.8 79.8C9.803 148.168 0 184.854 0 224.63c0 47.78 13.94 90.745 41.827 128.906 27.884 38.164 63.906 64.572 108.063 79.227 5.14.954 8.945.283 11.419-1.996 2.475-2.282 3.711-5.14 3.711-8.562 0-.571-.049-5.708-.144-15.417a2549.81 2549.81 0 01-.144-25.406l-6.567 1.136c-4.187.767-9.469 1.092-15.846 1-6.374-.089-12.991-.757-19.842-1.999-6.854-1.231-13.229-4.086-19.13-8.559-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-.951-2.568-2.098-3.711-3.429-1.142-1.331-1.997-2.663-2.568-3.997-.572-1.335-.098-2.43 1.427-3.289 1.525-.859 4.281-1.276 8.28-1.276l5.708.853c3.807.763 8.516 3.042 14.133 6.851 5.614 3.806 10.229 8.754 13.846 14.842 4.38 7.806 9.657 13.754 15.846 17.847 6.184 4.093 12.419 6.136 18.699 6.136 6.28 0 11.704-.476 16.274-1.423 4.565-.952 8.848-2.383 12.847-4.285 1.713-12.758 6.377-22.559 13.988-29.41-10.848-1.14-20.601-2.857-29.264-5.14-8.658-2.286-17.605-5.996-26.835-11.14-9.235-5.137-16.896-11.516-22.985-19.126-6.09-7.614-11.088-17.61-14.987-29.979-3.901-12.374-5.852-26.648-5.852-42.826 0-23.035 7.52-42.637 22.557-58.817-7.044-17.318-6.379-36.732 1.997-58.24 5.52-1.715 13.706-.428 24.554 3.853 10.85 4.283 18.794 7.952 23.84 10.994 5.046 3.041 9.089 5.618 12.135 7.708 17.705-4.947 35.976-7.421 54.818-7.421s37.117 2.474 54.823 7.421l10.849-6.849c7.419-4.57 16.18-8.758 26.262-12.565 10.088-3.805 17.802-4.853 23.134-3.138 8.562 21.509 9.325 40.922 2.279 58.24 15.036 16.18 22.559 35.787 22.559 58.817 0 16.178-1.958 30.497-5.853 42.966-3.9 12.471-8.941 22.457-15.125 29.979-6.191 7.521-13.901 13.85-23.131 18.986-9.232 5.14-18.182 8.85-26.84 11.136-8.662 2.286-18.415 4.004-29.263 5.146 9.894 8.562 14.842 22.077 14.842 40.539v60.237c0 3.422 1.19 6.279 3.572 8.562 2.379 2.279 6.136 2.95 11.276 1.995 44.163-14.653 80.185-41.062 108.068-79.226 27.88-38.161 41.825-81.126 41.825-128.906-.01-39.771-9.818-76.454-29.414-110.049z"
/>
</svg>
Sign in with GitHub
</Button>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"use client";

import { useState } from "react";
import { toast } from "sonner";
import { authClient } from "@/lib/auth-client";
import { Button } from "@/components/ui/button";

export function SignInWithGoogle() {
const [isLoading, setIsLoading] = useState(false);

const handleClick = async () => {
setIsLoading(true);
try {
const { error } = await authClient.signIn.social({
provider: "google",
});
if (error) {
toast.error(error.message);
return;
}
} catch (err) {
toast.error("An error occurred while signing in with Google", {
description: err instanceof Error ? err.message : "Unknown error",
});
} finally {
setIsLoading(false);
}
};

return (
<Button
variant="outline"
type="button"
className="w-full mb-4"
onClick={handleClick}
isLoading={isLoading}
>
<svg viewBox="0 0 24 24" className="mr-2 size-4">
<path
fill="currentColor"
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
/>
<path
fill="currentColor"
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
/>
<path
fill="currentColor"
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
/>
<path
fill="currentColor"
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
/>
</svg>
Sign in with Google
</Button>
);
}
114 changes: 114 additions & 0 deletions apps/dokploy/components/proprietary/enterprise-feature-gate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
"use client";

import { Loader2, Lock } from "lucide-react";
import Link from "next/link";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { api } from "@/utils/api";

interface EnterpriseFeatureLockedProps {
/** Optional title override */
title?: string;
/** Optional description override */
description?: string;
/** Optional custom CTA label */
ctaLabel?: string;
/** Optional CTA href (default: /dashboard/settings/license) */
ctaHref?: string;
/** Compact variant (less padding, smaller icon) */
compact?: boolean;
}

/**
* Displays a locked state for enterprise features when the user has no valid license.
* Use standalone or via EnterpriseFeatureGate.
*/
export function EnterpriseFeatureLocked({
title = "Enterprise feature",
description = "This feature is part of Dokploy Enterprise. Add a valid license to use it.",
ctaLabel = "Go to License",
ctaHref = "/dashboard/settings/license",
compact = false,
}: EnterpriseFeatureLockedProps) {
return (
<Card className="border-dashed bg-transparent">
<CardHeader className={compact ? "pb-2" : undefined}>
<div className="flex flex-col items-center gap-3 text-center">
<div
className={
compact
? "rounded-full bg-muted p-3"
: "rounded-full bg-muted p-4"
}
>
<Lock
className={
compact
? "size-6 text-muted-foreground"
: "size-8 text-muted-foreground"
}
/>
</div>
<div className="space-y-1">
<CardTitle className="text-lg">{title}</CardTitle>
<CardDescription className="max-w-sm mx-auto">
{description}
</CardDescription>
</div>
</div>
</CardHeader>
<CardContent className={compact ? "pt-0" : undefined}>
<div className="flex justify-center">
<Button asChild variant="secondary" size={compact ? "sm" : "default"}>
<Link href={ctaHref}>{ctaLabel}</Link>
</Button>
</div>
</CardContent>
</Card>
);
}

interface EnterpriseFeatureGateProps {
children: React.ReactNode;
/** Props for the locked state when license is invalid */
lockedProps?: Omit<EnterpriseFeatureLockedProps, "compact">;
/** Show loading spinner while checking license */
fallback?: React.ReactNode;
}

/**
* Renders children only when the instance has a valid enterprise license.
* Otherwise shows EnterpriseFeatureLocked.
*/
export function EnterpriseFeatureGate({
children,
lockedProps,
fallback,
}: EnterpriseFeatureGateProps) {
const { data: haveValidLicense, isLoading } =
api.licenseKey.haveValidLicenseKey.useQuery();

if (isLoading) {
if (fallback) return <>{fallback}</>;
return (
<div className="flex items-center gap-2 justify-center min-h-[25vh]">
<Loader2 className="size-6 text-muted-foreground animate-spin" />
<span className="text-sm text-muted-foreground">
Checking license...
</span>
</div>
);
}

if (!haveValidLicense) {
return <EnterpriseFeatureLocked {...lockedProps} />;
}

return <>{children}</>;
}
Loading
Loading