Email + Password
Classic email and password sign-up and sign-in.
The default. Users sign up with an email and a password, then log in with the same.
Server config
To disable email signup but keep email login: leave emailAuth.enabled: true and set registration.enabled: false (or registration.requireInvitation: true).
Endpoints
| Method | Path | Purpose |
|---|---|---|
POST | /auth/signup | Create a user with { email, password, … } |
POST | /auth/login | Login with { providerName: 'email', credentials: { email, password } } |
Client call
React hook
Password hashing
The library hashes with argon2id. Change the cost via password.argon2. Replace the algorithm entirely via password.hash / password.verify hooks (see Hooks Reference).
Password policy
Opt in to a built-in strength policy via password.policy. It's enforced uniformly at every password-set path — signup, change-password, reset-password, and admin-set (and admin-console passwords) — because it runs inside the entity's setPassword, so it can't be bypassed:
Failures return 400 with a specific code: PASSWORD_TOO_SHORT, PASSWORD_TOO_LONG, PASSWORD_TOO_COMMON, PASSWORD_CONTAINS_IDENTIFIER, or PASSWORD_BREACHED.
Breached-password check (Have I Been Pwned)
With checkBreached: true, passwords are checked against HIBP's ~1B leaked-password corpus using k-anonymity: the password is SHA-1'd and only the first 5 hex chars of the hash are sent — the password (and its full hash) never leave your server. The check is fail-open by default (an HIBP outage won't block password changes); set hibp.failOpen: false to fail closed. hibp.baseUrl can point at an enterprise proxy.
Prefer this policy over a
registrationHooks.beforeSignuppassword check — the hook only covers signup, whereas the policy also covers change/reset/admin-set.
Forgot password
Three endpoints chain together:
POST /auth/forgot-password{ email }→ emitsPasswordResetRequestedEvent(your listener sends the OTP/link).POST /auth/verify-forgot-password-otp{ email, code }→ returns aresetToken.POST /auth/reset-password{ token, newPassword }→ emitsPasswordResetEvent.
See Sending Emails for the listener wiring.
Requiring a verified email
By default a user is signed in immediately at signup, even before verifying their email. To hard-block unverified users from protected routes, set registration.requireVerifiedEmail:
A signed-in but unverified user then gets 403 EMAIL_NOT_VERIFIED on every guarded route except the library's own verification / logout / current-user / session / refresh / MFA routes (so they can still verify their email or sign out). Mark any of your own routes that must stay reachable with @SkipEmailVerification(). The check re-reads the user's verified state on each request, so it clears the moment they verify — no re-login needed. (This mirrors the mustChangePassword hard-block.)
Wire the actual verification email off your verification event — see Sending Emails.
Blocking disposable email domains
Reject sign-ups from throwaway/disposable email providers. The blocklist lives in the DB and is managed from the admin console (the "Blocked Email Domains" page), seedable from a built-in ~8k default list. Opt in:
A sign-up whose email domain is on the list gets 403 EMAIL_DOMAIN_NOT_ALLOWED (or, in flag mode, is allowed but emits a disposable_email_detected event you can log). Manage the list in the dashboard — search, add, remove, and Import defaults to seed the built-in list. (API: <admin base>/api/blocked-email-domains.)
Related
- Phone + Password.
- Email Verification — separate flow from login.
- Module reference.