2FA is currently disabled via a feature flag. All existing infrastructure (API routes, DB columns, Twilio integration, OTP UI) is fully intact — only the routing logic is bypassed. Re-enabling takes one code change and some environment/service checks.
Open src/components/AuthPage.tsx and find this near the top of the file (just above function RightPanel):
const TWO_FA_ENABLED = false;Change it to:
const TWO_FA_ENABLED = true;That's it for the code. The two bypass blocks in handleSignIn and handleSignUp will now be skipped and the full channel-select → OTP flow will run again.
Make sure .env.local (and your production environment) has all three Twilio values set:
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_VERIFY_SERVICE_SID=VAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Find these in the Twilio Console:
- Account SID / Auth Token → Dashboard homepage
- Verify Service SID → Verify → Services → your service → Service SID
If you're on a Twilio trial:
- SMS will only work for verified numbers (verify them at Twilio Console → Phone Numbers → Verified Caller IDs).
- Email (via Twilio Verify) works without restrictions on trial accounts and is the safer default.
Once you upgrade to a paid Twilio account, SMS works for all numbers.
- User enters email + password → Supabase auth succeeds.
- If
two_fa_enabled = falseon their profile (first time) → Channel Select screen. - If
two_fa_enabled = trueand device is trusted (30-day cookie) → skip OTP, go straight to app. - If
two_fa_enabled = trueand device is not trusted → OTP sent via stored channel → OTP screen.
- User fills out the form → Supabase account created.
- → Channel Select screen (choose SMS or Email).
- → OTP screen → on success → Onboarding flow.
- Email → OTP sent immediately via
POST /api/2fa/send { channel: "email" }. - SMS → Phone Setup screen collects number → OTP sent via
POST /api/2fa/send { channel: "sms", phone: "+1..." }.
The /api/2fa/verify route accepts 123456 as a valid code only in NODE_ENV !== "production" (i.e. local dev). This is intentional for testing. It is not active in production.
| File | Purpose |
|---|---|
src/components/AuthPage.tsx |
Feature flag + full UI state machine |
src/app/api/2fa/send/route.ts |
Server route — sends OTP via Twilio |
src/app/api/2fa/verify/route.ts |
Server route — verifies OTP, rate-limits |
src/lib/supabase/server.ts |
Server-side Supabase client used by API routes |
| Column | Type | Purpose |
|---|---|---|
two_fa_enabled |
boolean |
Whether the user has completed 2FA setup |
two_fa_channel |
text ('email' or 'sms') |
User's chosen delivery channel |
phone |
text |
E.164 phone number (set during SMS setup) |
last_otp_sent_at |
timestamptz |
Rate-limit timestamp (30 s cooldown) |