Customer accounts
Orders were guest-only until this existed: retrieved by an unguessable Stripe
session id, with no way back for a buyer who lost the confirmation email.
customers and customer_addresses add a second login under /account on the
storefront and /api/account/* on the API: sign in, register, order history, an
address book, password reset.
A different surface, the same posture
Section titled “A different surface, the same posture”A customer session sets req.session.customerId, never adminId, so requireAdmin
refuses it exactly like an anonymous request. server/security.test.ts asserts a
signed-in customer gets 401 on every admin route.
Registration, login and a password-reset request all answer identically for a
known and an unknown email. createCustomer hashes the password before it
discovers the email is taken, so the two branches cost about the same, not just
look the same.
The gate that cannot be skipped
Section titled “The gate that cannot be skipped”Orders are only ever linked to an account after the email is verified. Registering creates the account immediately, so a new customer can sign in right away, but claiming past guest orders under that address, and the address book that comes with it, waits for the emailed verification link.
Skipping that gate would let anyone register with a stranger’s email and read their order history and shipping address. It is the sharpest edge in this feature. The same gate applies when a guest checkout completes under an email that already belongs to a verified account: the webhook links it there, never to an unverified one.
Guest checkout stays the default
Section titled “Guest checkout stays the default”Nothing in the cart forces an account. The cart page only offers signing in, and prefills the shipping country from a signed-in buyer’s default address.
Tokens
Section titled “Tokens”Reset and verification tokens follow the staff-invite pattern: only a hash is stored, single-use, and short-lived. An hour for a reset link, since it is a live credential; a day for verification, since it is an onboarding step.
In the API
Section titled “In the API”POST /api/account/register, /verify, /session, DELETE /session,
/password/forgot, /password/reset, and under /api/account/me the profile,
orders, and addresses. Every write carries the session’s CSRF token.