phptcloud/password-entropy-bundle
A Symfony bundle for measuring password strength with entropy-based scoring. Validate passwords against configurable entropy thresholds, integrate with Symfony's validator component, and help users choose genuinely secure credentials instead of relying on simple length or character rules.
Install the bundle with Composer:
composer require phptcloud/password-entropy-bundle
If you are on Symfony Flex, the bundle is auto-registered. If not, add it manually in config/bundles.php:
return [
// ...
PHPTCloud\PasswordEntropyBundle\PasswordEntropyBundle::class => ['all' => true],
];
The first useful use case is enforcing a minimum password strength on registration or password-change forms. Attach the constraint to the plaintext password field:
use PHPTCloud\PasswordEntropyBundle\Validator\Constraints\PasswordEntropy;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
$builder->add('plainPassword', PasswordType::class, [
'constraints' => [
new PasswordEntropy(['minEntropy' => 50]),
],
]);
Where to look first:
src/Validator/Constraints/ — this is where the entropy formula and supported options live.DependencyInjection/Configuration.php for any default threshold you can set globally.minEntropy, message, etc.), since the API surface is small and not heavily documented.A minimal end-to-end smoke test: submit a form with password (very low entropy) and confirm the violation fires, then submit a long passphrase and confirm it passes. That tells you the threshold semantics before you wire it into real forms.
Form-level constraint (most common). Add the constraint to every plaintext password field — registration, reset, change-password. Keep the threshold in one place (a config value or a small factory) so all forms agree:
new PasswordEntropy(['minEntropy' => $this->passwordPolicy->minEntropy()])
Entity-level constraint. If you already validate entities directly (API payloads, imported users), put the constraint on the mapped plainPassword property and validate the entity group. This keeps form and API validation consistent:
#[PasswordEntropy(minEntropy: 50)]
private ?string $plainPassword = null;
Password policy service. Wrap the constraint construction in a service so you can raise the threshold over time without touching every form:
final class PasswordPolicy
{
public function constraint(): PasswordEntropy
{
return new PasswordEntropy(['minEntropy' => $this->minEntropy]);
}
}
Pair with complementary constraints. Entropy alone does not catch breached passwords or minimum length. Combine with Length(min: 12) and, where available, NotCompromisedPassword. Entropy scoring rewards length, so the combination is coherent rather than redundant.
Apply only to new secrets. Never run entropy validation on login. On login you compare a submitted plaintext against a stored hash; the hash will fail any entropy check and lock users out. Validate only when a password is being set. This also means existing users with weak passwords keep working until they change them.
API and serializer flows. Symfony's validator runs on the plainPassword property during $validator->validate($dto). Map the request body to a DTO with a plainPassword field, validate, then hash. Do not expose the entropy score in responses unless you intend to.
Testing. Unit-test your policy service rather than the bundle internals. For form tests, assert the violation message appears for a low-entropy input and disappears for a long passphrase. Add a boundary test at exactly your threshold, since entropy is typically a float and comparisons can be off-by-a-fraction.
Entropy is not complexity. A 40-character passphrase can outscore P@ssw0rd! while containing no symbols. Set your threshold with that in mind and do not also demand character-class rules that fight the entropy model.
Tune the threshold per app. A minEntropy of 40–50 bits is a common starting range; 60+ gets strict fast for users. Measure against real submitted samples before shipping.
Validate plaintext only. The constraint compares the raw value; applying it to a hashed password field, or to a login form, produces false failures. Restrict it to plainPassword-style fields.
Empty/null values. Most constraints skip null/empty by default. Confirm your PasswordType field is required so an empty submission does not silently pass entropy validation.
Bundle registration. Without Flex the bundle must be added to config/bundles.php; a missing entry surfaces as "class not found" or an unregistered-constraint error, not a friendly message.
Option names drift. This is a small package with limited adoption (12 stars, no dependents), so verify the exact option keys (minEntropy vs min_score) against the constraint class in your installed version rather than trusting blog examples.
Pin the version. Last release was March 2024 and the dependency tree is thin; lock the version and check composer why-not if you upgrade Symfony, as supported framework versions may lag.
Messages and i18n. Customize the violation message through the constraint's message option and make sure it is translatable in your app's domain; default messages are often generic.
Debugging a surprising score. Dump the validator directly without the form to isolate whether the entropy calculation or the form wiring is responsible:
$violations = $validator->validate('correct horse battery staple', new PasswordEntropy(['minEntropy' => 50]));
Extension points are limited. The bundle is thin; if you need dictionary checks, breach lookups, or per-role thresholds, compose additional constraints or your own validator rather than expecting hooks inside this one.
How can I help you explore Laravel packages today?