Password Policy
Configure minimum password strength requirements, breach detection, and password change policies in HelloJohn.
Password Policy
HelloJohn lets you configure password requirements globally and override them per tenant.
Default policy
Out of the box, HelloJohn requires:
- Minimum 8 characters
- No character class requirements (uppercase, number, symbol are not forced)
- Passwords checked against the HaveIBeenPwned breach database
This follows NIST SP 800-63B guidelines, which recommend length over complexity and breach checking over forced character classes.
Global configuration
Set in environment variables or the admin dashboard under Settings → Security → Password Policy:
| Variable | Default | Description |
|---|---|---|
PASSWORD_MIN_LENGTH | 8 | Minimum password length |
PASSWORD_MAX_LENGTH | 128 | Maximum password length |
PASSWORD_REQUIRE_UPPERCASE | false | Require at least one uppercase letter |
PASSWORD_REQUIRE_LOWERCASE | false | Require at least one lowercase letter |
PASSWORD_REQUIRE_NUMBER | false | Require at least one digit |
PASSWORD_REQUIRE_SYMBOL | false | Require at least one special character |
PASSWORD_BREACH_CHECK | true | Check against HaveIBeenPwned |
PASSWORD_BREACH_CHECK_THRESHOLD | 1 | Reject if found this many times or more |
PASSWORD_HISTORY_COUNT | 0 | Prevent reuse of last N passwords (0 = disabled) |
PASSWORD_EXPIRY_DAYS | 0 | Force password change after N days (0 = never) |
PASSWORD_ZXCVBN_MIN_SCORE | 0 | Minimum zxcvbn strength score (0–4; 0 = disabled) |
Per-tenant override
Individual tenants can have stricter (but not looser) password policies:
PATCH /v1/tenants/{tenant_id}/config
Authorization: Bearer <admin_api_key>
Content-Type: application/json
{
"password_policy": {
"min_length": 12,
"require_uppercase": true,
"require_number": true,
"require_symbol": true,
"breach_check": true,
"zxcvbn_min_score": 3,
"history_count": 5
}
}HaveIBeenPwned breach check
When enabled, HelloJohn uses the HIBP Passwords API with the k-anonymity model:
- The password is hashed with SHA-1
- Only the first 5 characters of the hash are sent to HIBP
- HIBP returns all hashes starting with those 5 characters
- HelloJohn checks the full hash locally — the full password and hash are never sent to HIBP
This is zero-knowledge: HIBP cannot learn your users' passwords.
# Example: how k-anonymity works
# Password: "hunter2"
# SHA-1: F3BBBD8...
# Request sent to HIBP:
GET https://api.pwnedpasswords.com/range/F3BBB
# HIBP returns all hashes starting with F3BBB
# HelloJohn checks if the remaining suffix matches locallyTo disable breach checking (not recommended):
PASSWORD_BREACH_CHECK=falsezxcvbn strength scoring
zxcvbn is a password strength estimator that models realistic attack scenarios (dictionary attacks, common patterns, keyboard walks, etc.) rather than character class rules.
| Score | Strength | Crack time estimate |
|---|---|---|
| 0 | Very weak | < 1 second |
| 1 | Weak | < 1 minute |
| 2 | Fair | < 1 hour |
| 3 | Strong | < 1 day |
| 4 | Very strong | > 1 year |
Recommended: PASSWORD_ZXCVBN_MIN_SCORE=2 for consumer apps, 3 for business apps.
Password history
Prevent users from cycling back to old passwords:
PASSWORD_HISTORY_COUNT=5 # reject if matches any of last 5 passwordsHelloJohn stores password history hashes (Argon2id) — not the passwords themselves.
Password expiry
Force users to change their password periodically:
PASSWORD_EXPIRY_DAYS=90 # require change every 90 daysNote: NIST SP 800-63B no longer recommends periodic password rotation without evidence of compromise. Only enable this if required by your compliance framework (e.g., PCI DSS).
When a password expires:
- The user's access token contains
password_expired: true - Your app should redirect to a password change flow
- After changing, the flag is cleared
Communicating requirements to users
Use the password policy endpoint to show requirements in your UI:
GET /v1/tenants/{tenant_id}/config/password-policy
# Returns the effective policy for this tenant{
"min_length": 12,
"require_uppercase": true,
"require_number": true,
"require_symbol": false,
"breach_check": true,
"zxcvbn_min_score": 2
}Build a real-time strength indicator using the policy settings and a zxcvbn client library:
import { zxcvbn } from '@zxcvbn-ts/core';
function PasswordStrengthIndicator({ password, policy }) {
const result = zxcvbn(password);
const meetsLength = password.length >= policy.min_length;
const meetsStrength = result.score >= policy.zxcvbn_min_score;
return (
<div>
<progress value={result.score} max={4} />
{!meetsLength && <p>At least {policy.min_length} characters required</p>}
{!meetsStrength && <p>{result.feedback.suggestions[0]}</p>}
</div>
);
}