PasswordService
in package
PasswordService — single source of truth for password hashing + verification (security audit 2026-06-15, migration plan).
Target scheme: Argon2id over the plaintext, with NO inner sha1 layer and NO
application-managed salt (Argon2 carries its own per-hash random salt). New
and rehashed hashes store an EMPTY user.salt.
Legacy scheme (pre-migration): password_hash(sha1(salt . plaintext)) with a
non-empty user.salt. Both are supported transparently so existing users keep
logging in; verify() picks the scheme from whether salt is empty.
The user.salt column doubles as the scheme discriminator (the core user
table cannot take a new flag column):
- salt empty/NULL -> new scheme -> password_verify(plaintext, hash)
- salt non-empty -> legacy -> password_verify(sha1(salt.plaintext), hash)
Callers verify with verify(), and on a SUCCESSFUL login should rehash when needsUpgrade() is true (writes hash() back to the user row) — a transparent verify-on-login upgrade that needs no mass reset and no schema change.
Table of Contents
Methods
- algo() : string
- Preferred algorithm: Argon2id > Argon2i > bcrypt default.
- hash() : array{password_hash: string, salt: string}
- Hash a plaintext password with the target scheme.
- needsUpgrade() : bool
- Whether a stored credential should be upgraded on next successful login: legacy (non-empty salt) always, or a new-scheme hash whose cost/algo is now out of date.
- verify() : bool
- Verify a plaintext password against a stored hash, supporting BOTH schemes.
Methods
algo()
Preferred algorithm: Argon2id > Argon2i > bcrypt default.
public
static algo() : string
Return values
stringhash()
Hash a plaintext password with the target scheme.
public
static hash(string $plaintext) : array{password_hash: string, salt: string}
Parameters
- $plaintext : string
Return values
array{password_hash: string, salt: string} —ready to store on the user row
needsUpgrade()
Whether a stored credential should be upgraded on next successful login: legacy (non-empty salt) always, or a new-scheme hash whose cost/algo is now out of date.
public
static needsUpgrade(string $hash, string|null $salt) : bool
Parameters
- $hash : string
- $salt : string|null
Return values
boolverify()
Verify a plaintext password against a stored hash, supporting BOTH schemes.
public
static verify(string $plaintext, string $hash, string|null $salt) : bool
The scheme is chosen by whether the stored salt is empty (new) or not (legacy).
Parameters
- $plaintext : string
- $hash : string
- $salt : string|null