DEV Community

linou518
linou518

Posted on

Dropping Email Required: Migrating to Phone-or-Email Authentication

Dropping Email Required: Migrating to Phone-or-Email Authentication

Our registration form said "just enter your phone number," but the backend still rejected requests without an email address. A minor bug, but real users were stuck. Here's how we fixed it.


Background

Our LINE-integrated e-commerce platform targets users who often lack email addresses or prefer not to provide them. Despite our registration form showing "phone number only," submissions consistently failed with 400 Bad Request errors.

The root cause was simple: our frontend sent only phone numbers, but backend validation still enforced email: required.


The Solution

Frontend Changes (Vue + Vite)

Made the email field optional and updated the label accordingly:

<input
  v-model="form.email"
  type="email"
  placeholder="Email address (optional)"
/>
Enter fullscreen mode Exit fullscreen mode

Removed email validation from the client-side submission logic.

Backend Changes (Node.js / ts-node)

Updated the /api/auth/register endpoint validation:

// Before
const schema = z.object({
  phone: z.string(),
  email: z.string().email(),  // ← This was the problem
  password: z.string().min(6),
});

// After
const schema = z.object({
  phone: z.string().optional(),
  email: z.string().email().optional(),
  password: z.string().min(6),
}).refine(data => data.phone || data.email, {
  message: 'Either phone or email is required',
});
Enter fullscreen mode Exit fullscreen mode

Login was similarly updated to search by either phone or email:

const user = await User.findOne({
  where: phone ? { phone } : { email },
});
Enter fullscreen mode Exit fullscreen mode

Pitfalls

Existing User Conflicts

During testing, we encountered "phone number already registered" errors. Investigation revealed that test admin accounts had been assigned real user phone numbers. This highlighted the risks of developing against production data.

Our solution: when users hit this error, we now guide them to the login flow with "Already registered? Please log in instead" messaging.


Key Takeaways

"Required" fields depend entirely on user context.

While email addresses feel natural to developers, phone numbers are far more familiar to end users—especially older users or those with lower tech literacy. For B2C services targeting these demographics, authentication UX directly impacts conversion rates.

Zod's .refine() method is powerful.

"Either A or B is required" logic can't be expressed through individual field validation. The .refine() method enables clean object-level validation rules.


Top comments (0)