diff --git a/apps/dokploy/components/proprietary/auth/sign-in-with-github.tsx b/apps/dokploy/components/proprietary/auth/sign-in-with-github.tsx index 347507383..60b525867 100644 --- a/apps/dokploy/components/proprietary/auth/sign-in-with-github.tsx +++ b/apps/dokploy/components/proprietary/auth/sign-in-with-github.tsx @@ -13,6 +13,7 @@ export function SignInWithGithub() { try { const { error } = await authClient.signIn.social({ provider: "github", + errorCallbackURL: "/", }); if (error) { toast.error(error.message); diff --git a/apps/dokploy/components/proprietary/auth/sign-in-with-google.tsx b/apps/dokploy/components/proprietary/auth/sign-in-with-google.tsx index e40d8d9b5..1b62a2bee 100644 --- a/apps/dokploy/components/proprietary/auth/sign-in-with-google.tsx +++ b/apps/dokploy/components/proprietary/auth/sign-in-with-google.tsx @@ -13,6 +13,7 @@ export function SignInWithGoogle() { try { const { error } = await authClient.signIn.social({ provider: "google", + errorCallbackURL: "/", }); if (error) { toast.error(error.message); diff --git a/apps/dokploy/components/proprietary/sso/sign-in-with-sso.tsx b/apps/dokploy/components/proprietary/sso/sign-in-with-sso.tsx index e589f4df4..4b0ccbf71 100644 --- a/apps/dokploy/components/proprietary/sso/sign-in-with-sso.tsx +++ b/apps/dokploy/components/proprietary/sso/sign-in-with-sso.tsx @@ -50,6 +50,7 @@ export function SignInWithSSO({ const { data, error } = await authClient.signIn.sso({ email: values.email, callbackURL: "/dashboard/home", + errorCallbackURL: "/", }); if (error) { toast.error(error.message ?? "Failed to sign in with SSO"); diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index e8381c1cb..8f1adae72 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -10,7 +10,7 @@ import { Fingerprint } from "lucide-react"; import type { GetServerSidePropsContext } from "next"; import Link from "next/link"; import { useRouter } from "next/router"; -import { type ReactElement, useState } from "react"; +import { type ReactElement, useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; @@ -85,6 +85,29 @@ export default function Home({ IS_CLOUD, enforceSSO }: Props) { }, }); + useEffect(() => { + const queryError = router.query.error; + if (!queryError) return; + + const raw = Array.isArray(queryError) ? queryError[0] : queryError; + if (!raw) return; + const normalized = raw.replace(/[+_]/g, " ").toLowerCase(); + + setError( + normalized.includes("account not linked") + ? "This account already exists but isn't linked to that sign-in provider yet. Contact your administrator to link it." + : normalized.includes("access denied") + ? "Access was denied by the identity provider." + : "We couldn't complete sign-in. Please try again or contact your administrator.", + ); + + const { error: _removed, ...rest } = router.query; + router.replace({ pathname: router.pathname, query: rest }, undefined, { + shallow: true, + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [router.query.error]); + const onSubmit = async (values: LoginForm) => { setIsLoginLoading(true); try { diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 49c7a2964..ab52c6ca2 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -77,6 +77,9 @@ const createBetterAuth = () => ...(!IS_CLOUD ? ["/verify-email"] : []), ], secret: betterAuthSecret, + onAPIError: { + errorURL: "/", + }, ...(!IS_CLOUD ? { advanced: { @@ -165,6 +168,9 @@ const createBetterAuth = () => user: { create: { before: async (_user, context) => { + if (context?.path.includes("/scim")) { + return { data: { emailVerified: true } }; + } if (!IS_CLOUD) { const xDokployToken = context?.request?.headers?.get("x-dokploy-token"); @@ -197,8 +203,7 @@ const createBetterAuth = () => } } else { const isSSORequest = context?.path.includes("/sso"); - const isSCIMRequest = context?.path.includes("/scim"); - if (isSSORequest || isSCIMRequest) { + if (isSSORequest) { return; } const isAdminPresent = await db.query.member.findFirst({ @@ -251,6 +256,20 @@ const createBetterAuth = () => } if (isSCIMRequest) { + const membership = await db.query.member.findFirst({ + where: eq(schema.member.userId, user.id), + }); + if (membership) { + const defaultRole = await resolveOrganizationDefaultRole( + membership.organizationId, + ); + if (defaultRole !== membership.role) { + await db + .update(schema.member) + .set({ role: defaultRole }) + .where(eq(schema.member.id, membership.id)); + } + } return; }