diff --git a/apps/sim/lib/auth/auth.ts b/apps/sim/lib/auth/auth.ts index ea2d1f0b227..a18c757f6c2 100644 --- a/apps/sim/lib/auth/auth.ts +++ b/apps/sim/lib/auth/auth.ts @@ -768,6 +768,13 @@ export const auth = betterAuth({ }, emailAndPassword: { enabled: true, + /** + * Same flag that hides the email/password signup form (DISABLE_EMAIL_SIGNUP). + * Blocks /sign-up/email at the better-auth layer so ripping out the frontend + * form cannot be bypassed by calling the endpoint directly. Existing users + * can still sign in. + */ + disableSignUp: isEmailSignupDisabled, requireEmailVerification: isEmailVerificationEnabled, /** * When someone signs up with an already-registered email, better-auth returns a @@ -891,11 +898,6 @@ export const auth = betterAuth({ }) } - if (isEmailSignupDisabled && ctx.path.startsWith('/sign-up/email')) - throw new APIError('FORBIDDEN', { - message: 'Email sign-up is disabled. Please use Google, Microsoft, or GitHub.', - }) - const isSignIn = ctx.path.startsWith('/sign-in') const isSignUp = ctx.path.startsWith('/sign-up') @@ -1039,6 +1041,16 @@ export const auth = betterAuth({ throw error } }, + /** + * Without this, /sign-in/email-otp auto-registers any unknown email — + * bypassing the signup gate entirely (no captcha, no /sign-up path). + * Gated by the same DISABLE_EMAIL_SIGNUP flag as the signup form (and by + * DISABLE_REGISTRATION, whose /sign-up path check has the same blind + * spot); when set, better-auth also silently skips sending OTPs to + * unknown emails (enumeration-safe) while existing users keep OTP + * sign-in. + */ + disableSignUp: isEmailSignupDisabled || isRegistrationDisabled, sendVerificationOnSignUp: false, otpLength: 6, // Explicitly set the OTP length expiresIn: 15 * 60, // 15 minutes in seconds