import { env } from "@/src/env.mjs"; import { createUserEmailPassword } from "@/src/features/auth-credentials/lib/credentialsServerUtils"; import { signupSchema } from "@/src/features/auth/lib/signupSchema"; import { getSsoAuthProviderIdForDomain } from "@/src/ee/features/multi-tenant-sso/utils"; import type { NextApiRequest, NextApiResponse } from "next"; import { logger } from "@langfuse/shared/src/server"; export function getSSOBlockedDomains() { return ( env.AUTH_DOMAINS_WITH_SSO_ENFORCEMENT?.split(",") .map((domain) => domain.trim().toLowerCase()) .filter(Boolean) ?? [] ); } /* * Sign-up endpoint (email/password users), creates user in database. * SSO users are created by the NextAuth adapters. */ export async function signupApiHandler( req: NextApiRequest, res: NextApiResponse, ) { if (req.method !== "POST") return; // Block if disabled by env if ( env.NEXT_PUBLIC_SIGN_UP_DISABLED === "true" || env.AUTH_DISABLE_SIGNUP === "true" ) { res.status(422).json({ message: "Sign up is disabled." }); return; } if (env.AUTH_DISABLE_USERNAME_PASSWORD === "true") { res.status(422).json({ message: "Sign up with email and password is disabled for this instance. Please use SSO.", }); return; } // parse and type check the request body with zod const validBody = signupSchema.safeParse(req.body); if (!validBody.success) { logger.warn("Signup: Invalid body", validBody.error); res.status(422).json({ message: validBody.error }); return; } const body = validBody.data; // check if email domain is blocked from email/password sign up via env const blockedDomains = getSSOBlockedDomains(); const domain = body.email.split("@")[1]?.toLowerCase(); if (domain && blockedDomains.includes(domain)) { res.status(422).json({ message: "Sign up with email and password is disabled for this domain. Please use SSO.", }); return; } // EE: check if custom SSO configuration is enabled for this domain const multiTenantSsoProvider = await getSsoAuthProviderIdForDomain(domain); if (multiTenantSsoProvider) { res.status(422).json({ message: "You must sign in via SSO for this domain.", }); return; } // create the user let userId: string; try { userId = await createUserEmailPassword( body.email, body.password, body.name, ); } catch (error) { const message = "Signup: Error creating user: " + (error instanceof Error ? error.message : JSON.stringify(error)); logger.warn(message, body.email.toLowerCase(), body.name); res.status(422).json({ message: message }); return; } // Trigger new user signup event if ( env.LANGFUSE_NEW_USER_SIGNUP_WEBHOOK && env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION && env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION !== "STAGING" && env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION !== "DEV" ) { await fetch(env.LANGFUSE_NEW_USER_SIGNUP_WEBHOOK, { method: "POST", body: JSON.stringify({ name: body.name, email: body.email, referralSource: body.referralSource, cloudRegion: env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION, userId: userId, }), headers: { "Content-Type": "application/json", }, }); } res.status(200).json({ message: "User created" }); }