Skip to main content
In this recipe you’ll add email-and-password authentication to an Express API backed by Esix. You’ll define a User model that stores a hashed password, build signup and login endpoints, and write a small middleware that loads the current user from a JWT on every request. Esix features used: findBy, create, instance methods, and find for loading the current user.

What You’ll Build

Dependencies

Note: Never store plaintext passwords. The model below hashes on save and exposes a verifyPassword method so route handlers never touch the raw hash.

The User Model

Encapsulate password handling inside the model so callers can’t forget to hash:
A static register factory keeps hashing in one place, and the instance method verifyPassword lets login handlers stay tiny.

Signing and Verifying Tokens

A pair of tiny helpers wrap jsonwebtoken:

The requireAuth Middleware

This middleware loads the current user from the Authorization header. By attaching the resolved model to request.user, downstream handlers don’t have to repeat the lookup:

Auth Schemas

Validate the request body with zod before reaching for the database. Defining the schemas alongside the routes keeps the auth surface area in one place:

Auth Routes

Note the use of findBy to look up users by email — this is the idiomatic way to query a single record by any indexed field.

Protected Route

Mount the middleware in front of any handler that needs an authenticated user:

Trying It Out

Sign up:
Call the protected endpoint:

Pattern Notes

  • Hashing in a static factory. Putting register on the model means the hash never leaks into route code, and there’s only one place to change the hashing algorithm later.
  • Look-up by email is just findBy. Add a unique index on email in MongoDB so the race-free upsert path is handled at the database layer.
  • Validate before you query. SignupSchema.parse(request.body) is a one-liner that turns “anything the client sends” into a typed object — enforce minimums on password length here rather than after the database round trip.
  • Don’t return the hash. The responses above only echo safe fields. If you find yourself reaching for a generic toJSON, build one on User that omits passwordHash.

What’s Next

  • REST API for a Blog — the patterns above drop straight into a CRUD API.
  • Defining Models — more on instance methods and schema conventions.
  • Testing — verify your auth flows against the in-memory adapter.