From 8a83e32c420107ea52d9182538b9614f9b83f58a Mon Sep 17 00:00:00 2001 From: miloschwartz Date: Tue, 17 Feb 2026 17:33:24 -0800 Subject: [PATCH] add send email verification opt out --- server/routers/auth/signup.ts | 20 +++++++++++++++----- server/routers/idp/validateOidcCallback.ts | 1 + src/app/auth/signup/page.tsx | 5 +++++ src/components/SignupForm.tsx | 7 +++++-- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/server/routers/auth/signup.ts b/server/routers/auth/signup.ts index c1c344d8..cf8e4141 100644 --- a/server/routers/auth/signup.ts +++ b/server/routers/auth/signup.ts @@ -1,7 +1,7 @@ import { NextFunction, Request, Response } from "express"; import { db, users } from "@server/db"; import HttpCode from "@server/types/HttpCode"; -import { z } from "zod"; +import { email, z } from "zod"; import { fromError } from "zod-validation-error"; import createHttpError from "http-errors"; import response from "@server/lib/response"; @@ -30,7 +30,8 @@ export const signupBodySchema = z.object({ inviteToken: z.string().optional(), inviteId: z.string().optional(), termsAcceptedTimestamp: z.string().nullable().optional(), - marketingEmailConsent: z.boolean().optional() + marketingEmailConsent: z.boolean().optional(), + skipVerificationEmail: z.boolean().optional() }); export type SignUpBody = z.infer; @@ -61,7 +62,8 @@ export async function signup( inviteToken, inviteId, termsAcceptedTimestamp, - marketingEmailConsent + marketingEmailConsent, + skipVerificationEmail } = parsedBody.data; const passwordHash = await hashPassword(password); @@ -214,7 +216,13 @@ export async function signup( } if (config.getRawConfig().flags?.require_email_verification) { - sendEmailVerificationCode(email, userId); + if (!skipVerificationEmail) { + sendEmailVerificationCode(email, userId); + } else { + logger.debug( + `User ${email} opted out of verification email during signup.` + ); + } return response(res, { data: { @@ -222,7 +230,9 @@ export async function signup( }, success: true, error: false, - message: `User created successfully. We sent an email to ${email} with a verification code.`, + message: skipVerificationEmail + ? "User created successfully. Please verify your email." + : `User created successfully. We sent an email to ${email} with a verification code.`, status: HttpCode.OK }); } diff --git a/server/routers/idp/validateOidcCallback.ts b/server/routers/idp/validateOidcCallback.ts index f4065c59..7d756a4a 100644 --- a/server/routers/idp/validateOidcCallback.ts +++ b/server/routers/idp/validateOidcCallback.ts @@ -436,6 +436,7 @@ export async function validateOidcCallback( } } + // These are the orgs that the user should be provisioned into based on the IdP mappings and the token claims logger.debug("User org info", { userOrgInfo }); let existingUserId = existingUser?.userId; diff --git a/src/app/auth/signup/page.tsx b/src/app/auth/signup/page.tsx index 9ab7b7e6..f51ac904 100644 --- a/src/app/auth/signup/page.tsx +++ b/src/app/auth/signup/page.tsx @@ -15,6 +15,7 @@ export default async function Page(props: { redirect: string | undefined; email: string | undefined; fromSmartLogin: string | undefined; + skipVerificationEmail: string | undefined; }>; }) { const searchParams = await props.searchParams; @@ -75,6 +76,10 @@ export default async function Page(props: { inviteId={inviteId} emailParam={searchParams.email} fromSmartLogin={searchParams.fromSmartLogin === "true"} + skipVerificationEmail={ + searchParams.skipVerificationEmail === "true" || + searchParams.skipVerificationEmail === "1" + } />

diff --git a/src/components/SignupForm.tsx b/src/components/SignupForm.tsx index a54b1c23..23c7713e 100644 --- a/src/components/SignupForm.tsx +++ b/src/components/SignupForm.tsx @@ -72,6 +72,7 @@ type SignupFormProps = { inviteToken?: string; emailParam?: string; fromSmartLogin?: boolean; + skipVerificationEmail?: boolean; }; const formSchema = z @@ -103,7 +104,8 @@ export default function SignupForm({ inviteId, inviteToken, emailParam, - fromSmartLogin = false + fromSmartLogin = false, + skipVerificationEmail = false }: SignupFormProps) { const router = useRouter(); const { env } = useEnvContext(); @@ -147,7 +149,8 @@ export default function SignupForm({ inviteToken, termsAcceptedTimestamp: termsAgreedAt, marketingEmailConsent: - build === "saas" ? marketingEmailConsent : undefined + build === "saas" ? marketingEmailConsent : undefined, + skipVerificationEmail: skipVerificationEmail || undefined }) .catch((e) => { console.error(e);