Skip to content

Commit e640102

Browse files
authored
feat(otp): added environemnt variable to control enforcement of verified accounts (#1411)
* feat(otp): added environemnt variable to control enforcement of verified accounts * added to helm
1 parent 16f5819 commit e640102

File tree

8 files changed

+53
-20
lines changed

8 files changed

+53
-20
lines changed
Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import { hasEmailService } from '@/lib/email/mailer'
2-
import { isProd } from '@/lib/environment'
2+
import { isEmailVerificationEnabled, isProd } from '@/lib/environment'
33
import { VerifyContent } from '@/app/(auth)/verify/verify-content'
44

55
export const dynamic = 'force-dynamic'
66

77
export default function VerifyPage() {
88
const emailServiceConfigured = hasEmailService()
99

10-
return <VerifyContent hasEmailService={emailServiceConfigured} isProduction={isProd} />
10+
return (
11+
<VerifyContent
12+
hasEmailService={emailServiceConfigured}
13+
isProduction={isProd}
14+
isEmailVerificationEnabled={isEmailVerificationEnabled}
15+
/>
16+
)
1117
}

apps/sim/app/(auth)/verify/use-verification.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const logger = createLogger('useVerification')
1010
interface UseVerificationParams {
1111
hasEmailService: boolean
1212
isProduction: boolean
13+
isEmailVerificationEnabled: boolean
1314
}
1415

1516
interface UseVerificationReturn {
@@ -22,6 +23,7 @@ interface UseVerificationReturn {
2223
isOtpComplete: boolean
2324
hasEmailService: boolean
2425
isProduction: boolean
26+
isEmailVerificationEnabled: boolean
2527
verifyCode: () => Promise<void>
2628
resendCode: () => void
2729
handleOtpChange: (value: string) => void
@@ -30,6 +32,7 @@ interface UseVerificationReturn {
3032
export function useVerification({
3133
hasEmailService,
3234
isProduction,
35+
isEmailVerificationEnabled,
3336
}: UseVerificationParams): UseVerificationReturn {
3437
const router = useRouter()
3538
const searchParams = useSearchParams()
@@ -157,7 +160,7 @@ export function useVerification({
157160
}
158161

159162
function resendCode() {
160-
if (!email || !hasEmailService) return
163+
if (!email || !hasEmailService || !isEmailVerificationEnabled) return
161164

162165
setIsLoading(true)
163166
setErrorMessage('')
@@ -197,14 +200,14 @@ export function useVerification({
197200

198201
useEffect(() => {
199202
if (typeof window !== 'undefined') {
200-
if (!isProduction && !hasEmailService) {
203+
if (!isEmailVerificationEnabled) {
201204
setIsVerified(true)
202205

203206
const handleRedirect = async () => {
204207
try {
205208
await refetchSession()
206209
} catch (error) {
207-
logger.warn('Failed to refetch session during dev verification skip:', error)
210+
logger.warn('Failed to refetch session during verification skip:', error)
208211
}
209212

210213
if (isInviteFlow && redirectUrl) {
@@ -217,7 +220,7 @@ export function useVerification({
217220
handleRedirect()
218221
}
219222
}
220-
}, [isProduction, hasEmailService, router, isInviteFlow, redirectUrl])
223+
}, [isEmailVerificationEnabled, router, isInviteFlow, redirectUrl])
221224

222225
return {
223226
otp,
@@ -229,6 +232,7 @@ export function useVerification({
229232
isOtpComplete,
230233
hasEmailService,
231234
isProduction,
235+
isEmailVerificationEnabled,
232236
verifyCode,
233237
resendCode,
234238
handleOtpChange,

apps/sim/app/(auth)/verify/verify-content.tsx

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,17 @@ import { soehne } from '@/app/fonts/soehne/soehne'
1212
interface VerifyContentProps {
1313
hasEmailService: boolean
1414
isProduction: boolean
15+
isEmailVerificationEnabled: boolean
1516
}
1617

1718
function VerificationForm({
1819
hasEmailService,
1920
isProduction,
21+
isEmailVerificationEnabled,
2022
}: {
2123
hasEmailService: boolean
2224
isProduction: boolean
25+
isEmailVerificationEnabled: boolean
2326
}) {
2427
const {
2528
otp,
@@ -32,7 +35,7 @@ function VerificationForm({
3235
verifyCode,
3336
resendCode,
3437
handleOtpChange,
35-
} = useVerification({ hasEmailService, isProduction })
38+
} = useVerification({ hasEmailService, isProduction, isEmailVerificationEnabled })
3639

3740
const [countdown, setCountdown] = useState(0)
3841
const [isResendDisabled, setIsResendDisabled] = useState(false)
@@ -93,15 +96,17 @@ function VerificationForm({
9396
<p className={`${inter.className} font-[380] text-[16px] text-muted-foreground`}>
9497
{isVerified
9598
? 'Your email has been verified. Redirecting to dashboard...'
96-
: hasEmailService
97-
? `A verification code has been sent to ${email || 'your email'}`
98-
: !isProduction
99-
? 'Development mode: Check your console logs for the verification code'
100-
: 'Error: Invalid API key configuration'}
99+
: !isEmailVerificationEnabled
100+
? 'Email verification is disabled. Redirecting to dashboard...'
101+
: hasEmailService
102+
? `A verification code has been sent to ${email || 'your email'}`
103+
: !isProduction
104+
? 'Development mode: Check your console logs for the verification code'
105+
: 'Error: Email verification is enabled but no email service is configured'}
101106
</p>
102107
</div>
103108

104-
{!isVerified && (
109+
{!isVerified && isEmailVerificationEnabled && (
105110
<div className={`${inter.className} mt-8 space-y-8`}>
106111
<div className='space-y-6'>
107112
<p className='text-center text-muted-foreground text-sm'>
@@ -245,10 +250,18 @@ function VerificationFormFallback() {
245250
)
246251
}
247252

248-
export function VerifyContent({ hasEmailService, isProduction }: VerifyContentProps) {
253+
export function VerifyContent({
254+
hasEmailService,
255+
isProduction,
256+
isEmailVerificationEnabled,
257+
}: VerifyContentProps) {
249258
return (
250259
<Suspense fallback={<VerificationFormFallback />}>
251-
<VerificationForm hasEmailService={hasEmailService} isProduction={isProduction} />
260+
<VerificationForm
261+
hasEmailService={hasEmailService}
262+
isProduction={isProduction}
263+
isEmailVerificationEnabled={isEmailVerificationEnabled}
264+
/>
252265
</Suspense>
253266
)
254267
}

apps/sim/lib/auth.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ import {
3232
handleInvoicePaymentFailed,
3333
handleInvoicePaymentSucceeded,
3434
} from '@/lib/billing/webhooks/invoices'
35-
import { hasEmailService, sendEmail } from '@/lib/email/mailer'
35+
import { sendEmail } from '@/lib/email/mailer'
3636
import { getFromEmailAddress } from '@/lib/email/utils'
3737
import { quickValidateEmail } from '@/lib/email/validation'
3838
import { env, isTruthy } from '@/lib/env'
39-
import { isBillingEnabled, isProd } from '@/lib/environment'
39+
import { isBillingEnabled, isEmailVerificationEnabled } from '@/lib/environment'
4040
import { createLogger } from '@/lib/logs/console/logger'
4141

4242
const logger = createLogger('Auth')
@@ -165,7 +165,7 @@ export const auth = betterAuth({
165165
},
166166
emailAndPassword: {
167167
enabled: true,
168-
requireEmailVerification: isProd && hasEmailService(),
168+
requireEmailVerification: isEmailVerificationEnabled,
169169
sendVerificationOnSignUp: false,
170170
throwOnMissingCredentials: true,
171171
throwOnInvalidCredentials: true,
@@ -240,8 +240,8 @@ export const auth = betterAuth({
240240
otp: string
241241
type: 'sign-in' | 'email-verification' | 'forget-password'
242242
}) => {
243-
if (!isProd) {
244-
logger.info('Skipping email verification in dev/docker')
243+
if (!isEmailVerificationEnabled) {
244+
logger.info('Skipping email verification')
245245
return
246246
}
247247
try {

apps/sim/lib/env.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export const env = createEnv({
5151
BILLING_ENABLED: z.boolean().optional(), // Enable billing enforcement and usage tracking
5252

5353
// Email & Communication
54+
EMAIL_VERIFICATION_ENABLED: z.boolean().optional(), // Enable email verification for user registration and login (defaults to false)
5455
RESEND_API_KEY: z.string().min(1).optional(), // Resend API key for transactional emails
5556
FROM_EMAIL_ADDRESS: z.string().min(1).optional(), // Complete from address (e.g., "Sim <[email protected]>" or "[email protected]")
5657
EMAIL_DOMAIN: z.string().min(1).optional(), // Domain for sending emails (fallback when FROM_EMAIL_ADDRESS not set)

apps/sim/lib/environment.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ export const isHosted =
3030
*/
3131
export const isBillingEnabled = isTruthy(env.BILLING_ENABLED)
3232

33+
/**
34+
* Is email verification enabled
35+
*/
36+
export const isEmailVerificationEnabled = isTruthy(env.EMAIL_VERIFICATION_ENABLED)
37+
3338
/**
3439
* Get cost multiplier based on environment
3540
*/

helm/sim/examples/values-production.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ app:
3030
BETTER_AUTH_SECRET: "your-production-auth-secret-here"
3131
ENCRYPTION_KEY: "your-production-encryption-key-here"
3232

33+
# Email verification (set to true if you want to require email verification)
34+
EMAIL_VERIFICATION_ENABLED: "false"
35+
3336
# Optional third-party service integrations (configure as needed)
3437
RESEND_API_KEY: "your-resend-api-key"
3538
GOOGLE_CLIENT_ID: "your-google-client-id"

helm/sim/values.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ app:
6565
ENCRYPTION_KEY: "" # REQUIRED - set via --set flag or external secret manager
6666

6767
# Email & Communication
68+
EMAIL_VERIFICATION_ENABLED: "false" # Enable email verification for user registration and login (defaults to false)
6869
RESEND_API_KEY: "" # Resend API key for transactional emails
6970
FROM_EMAIL_ADDRESS: "" # Complete from address (e.g., "Sim <[email protected]>" or "[email protected]")
7071
EMAIL_DOMAIN: "" # Domain for sending emails (fallback when FROM_EMAIL_ADDRESS not set)

0 commit comments

Comments
 (0)