AstroBaaS

Customers & accounts

Password Policy Enforcement

Free — GPL coresize Splanned, not built

Generated from docs/plan/core/password-policy-enforcement/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.

Password Policy Enforcement sets minimum requirements — length, complexity, no common passwords — and prevents reuse of old passwords.

The problem

Merchants’ team members use weak passwords like ‘123456’; hackers break in through credential stuffing.

What it does

  • Minimum password length (configurable, default 12)
  • Require uppercase, lowercase, numbers, special chars (configurable)
  • Reject common passwords (NIST/HaveIBeenPwned top-100k)
  • Reject passwords containing username or email
  • Password expiration (optional, configurable, default off)
  • Prevent password reuse (last 5 changes)
  • Show password strength meter during reset
  • Audit log password changes (without storing passwords)
  • Apply policy to invite links (password on first login)

What it deliberately does NOT do

Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.

  • Force password change on next login — policy enforcement at change-time only
  • Compromised password detection (live HaveIBeenPwned API) — static list only
  • Multi-language password policy (Kanji) — Latin alphabet only
  • Per-role password policies — one policy per store
  • HIBP live API checking — static list

Data model

PasswordPolicy: id, store_id, min_length, require_uppercase, require_lowercase, require_numbers, require_special, common_passwords_check, no_email_in_password, min/max_password_age_days. PasswordHistory: user_id, password_hash, set_at. Migration: add password_policy and password_history tables.

API

  • GET /admin/settings/password-policy
  • PATCH /admin/settings/password-policy
  • POST /auth/check-password-strength
  • POST /auth/change-password

Every route added here must also appear in src/pages/openapi.json.ts — a test fails the build if it does not.

Admin

Settings page: sliders for min length, checkboxes for complexity. Test input: real-time feedback (green/red). Policy history: log of changes (when, by whom).

The seam — why this is core

Core owns: policy definition and enforcement, password hash comparison (never plaintext), strength meter. Paid module owns: nothing; core infrastructure.

Core owns the interface + honest policy enforcer; security is infrastructure, not a per-country obligation or credential.

Dependencies

None recorded.

Acceptance checks

Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.

  • min_length=12, attempting ‘abc123’ (6 chars) returns rejected ‘Password too short’
  • require_special=true, attempting ‘Abc123456789’ (no special) returns rejected
  • Password history [hash1-5]; setting to hash1 returns rejected ‘Cannot reuse recent’
  • Password ‘admin@store.com’ where email=admin@store.com returns rejected ‘Password cannot contain email’
  • Password ‘123456’ (NIST common) returns rejected ‘Too common’
  • After 5 password changes, can reuse old password

Risks

Plaintext list in memory causes memory exhaustion. Policy not enforced on invite password setup. Timing-based hints leak common passwords. No email notification if expiration set. Policy change not retroactive.

Commercial context

Suggested pricefree (core)
Rival anchorShopify: included; Magento: included

The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.


Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full catalogue and ../../AI-GUIDE.md for how to work on this repository.