Now we’ll write some more schemas and middleware functions that we’ll use for user authentication in the next lesson.

Authentication endpoints typically need validation that is different from basic user data.

We’ll add these to a new file: middleware/auth-validation.ts.

Registration Schema

Registration needs to validate new user signup data.

Here, we require the password to be at least eight characters long, including uppercase and lowercase letters, a number, and a special character.

// Add this to middleware/auth-validation.ts
import { z } from "zod";
import { Request, Response, NextFunction } from "express";

const registerSchema = z.object({
  username: z
    .string()
    .min(3, "Username must be at least 3 characters")
    .max(50, "Username must not exceed 50 characters"),
  email: z.email("Email must be a valid email"),
  password: z
    .string()
    .regex(
      /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,}$/,
      "Password must be at least 8 characters long and include uppercase, lowercase, number, and a special character"
    ),
});

Login Schema

Login only needs email and password.

Note: We only validate the password structure (length, character types, etc.) during registration or password change. At login, we simply check whether the entered password matches the stored one. Re-validating structure during login can lock out users with older passwords and may leak information about your password rules to attackers

const loginSchema = z.object({
  email: z.email("Email must be a valid email"),
  password: z.string(),
});

Auth Validation Middleware

Following the same pattern as our other validation middleware:

// Registration validation middleware
export function validateRegistration(
  req: Request,
  res: Response,
  next: NextFunction
) {
  const result = registerSchema.safeParse(req.body);

  if (!result.success) {
    return res.status(400).json({
      error: "Validation failed",
      details: result.error.issues.map((issue) => issue.message),
    });
  }

  next();
}

// Login validation middleware
export function validateLogin(req: Request, res: Response, next: NextFunction) {
  const result = loginSchema.safeParse(req.body);

  if (!result.success) {
    return res.status(400).json({
      error: "Validation failed",
      details: result.error.issues.map((issue) => issue.message),
    });
  }

  next();
}

Key Authentication Validation Principles

Authentication validation differs from basic user data validation in several important ways:

  • Complex password requirements: Uses regex to enforce security rules (uppercase, lowercase, numbers, special characters).
  • Registration vs login logic: Registration validates password structure, but login accepts any password string to avoid revealing security rules to potential attackers.
  • Security-first approach: These schemas follow production security practices that protect both your application and your users.

In the next lesson, we’ll use these schemas to build real authentication with password hashing and user registration.



Repo link

Tags: