Skip to content

E-Commerce — Authentication & User Management

OWNER: aimee (scoping) ALSO_USED_BY: anna (spec), urszula, maxim (backend), floris, floor (frontend) LAST_VERIFIED: 2026-03-26


Overview

Authentication in an e-commerce context goes beyond login/logout. It includes the full customer lifecycle: registration, verification, profile management, and GDPR-mandated account deletion. Guest checkout is always required — never force account creation before purchase.


Feature Decomposition

Registration

SCOPE_ITEM: Email/password registration INCLUDES: email field, password field (min 8 chars, complexity check), confirm password, terms acceptance checkbox, email verification flow OPTIONAL: name fields at registration (can defer to first checkout) COMPLIANCE: GDPR — explicit consent checkbox, link to privacy policy, double opt-in for marketing ESTIMATE_COMPLEXITY: simple STACK_REF: wiki/docs/stack/nextjs/index.md

SCOPE_ITEM: Social login INCLUDES: OAuth 2.0 integration, account linking (same email = same account) OPTIONAL: Google, Apple, Facebook, LinkedIn (pick per client) COMPLIANCE: Each provider has data processing terms; client must register as OAuth app owner ESTIMATE_COMPLEXITY: normal

CHECK: Client wants social login? IF: yes → minimum Google + Apple (covers 90% of users) IF: Netherlands market → consider iDIN (bank-based identity, high trust)

SCOPE_ITEM: Email verification INCLUDES: Verification email on registration, resend link, verification status in DB OPTIONAL: Allow limited browsing before verification, block checkout until verified COMPLIANCE: Required for transactional email delivery reputation ESTIMATE_COMPLEXITY: simple

Login

SCOPE_ITEM: Email/password login INCLUDES: email field, password field, error handling (generic "invalid credentials" — never reveal which field is wrong), rate limiting (5 attempts then 15-min lockout) OPTIONAL: "remember me" checkbox (extends session to 30 days) COMPLIANCE: PSD2/SCA — if storing payment methods, may need step-up auth ESTIMATE_COMPLEXITY: simple

SCOPE_ITEM: Magic link login INCLUDES: Email input, one-time link sent to email, link valid for 15 minutes, single-use OPTIONAL: Can replace password entirely (passwordless) ESTIMATE_COMPLEXITY: simple

SCOPE_ITEM: Two-factor authentication (2FA) INCLUDES: TOTP setup (Google Authenticator, Authy), backup codes (10, single-use), 2FA enforcement toggle in admin OPTIONAL: SMS 2FA (less secure, higher cost), WebAuthn/passkeys COMPLIANCE: Recommended for admin accounts, optional for customers ESTIMATE_COMPLEXITY: normal

Password Management

SCOPE_ITEM: Forgot password INCLUDES: Email input, reset link (valid 1 hour, single-use), new password form, confirmation email OPTIONAL: Security questions (NOT recommended — poor UX, weak security) COMPLIANCE: Reset link must invalidate all previous reset links for same email ESTIMATE_COMPLEXITY: simple

SCOPE_ITEM: Change password INCLUDES: Current password verification, new password with complexity check, session invalidation on all other devices ESTIMATE_COMPLEXITY: simple

Session Management

SCOPE_ITEM: Session handling INCLUDES: httpOnly secure cookies, 24-hour default expiry, refresh token rotation, CSRF protection OPTIONAL: Device management (see active sessions, revoke), concurrent session limit COMPLIANCE: Cookie consent not required for strictly necessary auth cookies ESTIMATE_COMPLEXITY: simple

CHECK: Session storage strategy IF: MVP → signed JWT in httpOnly cookie, short expiry (1h) + refresh token IF: full → database sessions (Drizzle sessions table), server-side revocation

Customer Profile

SCOPE_ITEM: Profile management INCLUDES: Name, email, phone (optional), default shipping address, default billing address OPTIONAL: Avatar/photo, date of birth, company details (for B2B invoicing) COMPLIANCE: GDPR — display what data is stored, purpose for each field ESTIMATE_COMPLEXITY: simple

SCOPE_ITEM: Address book INCLUDES: Multiple saved addresses, set default, edit, delete, address validation OPTIONAL: Google Places autocomplete (adds cost), PostNL address validation API (NL-specific) ESTIMATE_COMPLEXITY: simple

GDPR Account Management

SCOPE_ITEM: Data export (GDPR portability) INCLUDES: "Download my data" button, generates JSON/CSV with all personal data, orders, reviews COMPLIANCE: GDPR Article 20 — must be provided within 30 days, machine-readable format ESTIMATE_COMPLEXITY: normal

SCOPE_ITEM: Account deletion (GDPR right to erasure) INCLUDES: "Delete my account" flow, confirmation step, 30-day grace period (soft delete), hard delete after grace period, anonymize order history (keep for tax records, remove PII) COMPLIANCE: GDPR Article 17 — cannot refuse if no overriding legal basis. Tax records (7 years NL) override for financial data — anonymize, do not delete order amounts ESTIMATE_COMPLEXITY: normal

SCOPE_ITEM: Consent management INCLUDES: Marketing email opt-in (never pre-checked), cookie consent preferences, consent audit log (who, when, what, how) COMPLIANCE: GDPR Article 7 — consent must be freely given, specific, informed, unambiguous ESTIMATE_COMPLEXITY: normal


Implementation Patterns

GE Auth Stack

Authentication flow:
  Next.js middleware → validate session cookie → attach user to request
  Hono API → verify session server-side → return user context

Registration:
  POST /api/auth/register → validate → hash password (bcrypt, 12 rounds) → insert user → send verification email → return session

Login:
  POST /api/auth/login → validate → verify password → create session → set httpOnly cookie → return user

Password reset:
  POST /api/auth/forgot → generate token (crypto.randomUUID) → store hashed token in DB → send email
  POST /api/auth/reset → verify token → hash new password → update user → invalidate token → invalidate all sessions

CHECK: Never roll custom crypto IF: password hashing → bcrypt with cost factor 12 (via bcryptjs) IF: tokens → crypto.randomUUID() or crypto.getRandomValues() IF: session signing → use established library, never manual HMAC

Database Schema Pattern

-- Core auth tables
users (id, email, password_hash, email_verified_at, created_at, updated_at, deleted_at)
sessions (id, user_id, token_hash, expires_at, device_info, created_at)
password_reset_tokens (id, user_id, token_hash, expires_at, used_at)
email_verifications (id, user_id, token_hash, expires_at, verified_at)
consent_log (id, user_id, consent_type, granted, ip_address, user_agent, created_at)

Anti-Patterns

ANTI_PATTERN: Storing plaintext passwords FIX: Always bcrypt hash. Never log passwords. Never return password hash in API responses.

ANTI_PATTERN: Revealing whether an email exists during login FIX: Always return "Invalid credentials" regardless of which field is wrong.

ANTI_PATTERN: Requiring account creation before checkout FIX: Guest checkout MUST always work. Offer account creation post-purchase.

ANTI_PATTERN: Using localStorage for auth tokens FIX: httpOnly secure cookies only. localStorage is XSS-vulnerable.

ANTI_PATTERN: No rate limiting on auth endpoints FIX: Rate limit login (5/15min), registration (3/hour/IP), password reset (3/hour/email).


Integration Points

  • Email service: Verification emails, password reset emails (Brevo (FR) or Mailjet (FR) preferred. Resend/Postmark secondary — US-based, EU data sovereignty risk)
  • OAuth providers: Google, Apple, Facebook (if social login scoped)
  • Address validation: PostNL API (NL), Google Places (international)
  • iDIN: Bank-based identity verification (Netherlands, via Mollie)

Cross-References

READ_ALSO: wiki/docs/archetypes/e-commerce/compliance.md READ_ALSO: wiki/docs/archetypes/e-commerce/cart-checkout.md READ_ALSO: wiki/docs/archetypes/e-commerce/checklist.md READ_ALSO: wiki/docs/stack/nextjs/index.md READ_ALSO: wiki/docs/stack/hono/index.md READ_ALSO: wiki/docs/stack/drizzle/index.md