hackzilla/password-generator-bundle
A Symfony bundle that integrates the Hackzilla Password Generator library, providing a convenient service to create secure, configurable passwords with selectable character sets and options for use in Symfony applications.
Install
composer require hackzilla/password-generator-bundle
With Symfony Flex the bundle is registered automatically (contrib recipe). If not, add it to config/bundles.php:
Hackzilla\PasswordGeneratorBundle\HackzillaPasswordGeneratorBundle::class => ['all' => true],
There is essentially no YAML configuration — the bundle's value is registering the underlying library classes as services and exposing Twig helpers. All behaviour is driven through the service API.
Where to look first
bin/console debug:container hackzilla # see registered generator services
bin/console debug:twig | grep -i password # confirm the Twig function names
You'll typically find two services (IDs vary by version): a random PasswordGenerator and a HumanPasswordGenerator, plus a Twig extension exposing helpers such as generatePassword() and generateHumanPassword().
First use case — issuing a temporary password when an admin creates a user:
public function __construct(
private PasswordGenerator $generator,
) {}
public function createUser(string $email): User
{
$this->generator->setLength(16);
$this->generator->setOptionValue(PasswordGenerator::OPTION_UPPERCASE, true);
$this->generator->setOptionValue(PasswordGenerator::OPTION_NUMBERS, true);
$this->generator->setOptionValue(PasswordGenerator::OPTION_SYMBOLS, true);
$plain = $this->generator->generatePassword();
$user = new User($email);
$user->setPassword($this->hasher->hash($plain));
$user->setMustChangePassword(true);
// deliver $plain out-of-band — never persist it
return $user;
}
If autowiring fails (older bundle versions don't ship autowire aliases), bind the service ID explicitly in config/services.yaml:
services:
Hackzilla\PasswordGenerator\Generator\PasswordGenerator:
alias: hackzilla_password_generator.generator
Random password with a policy — treat the generator as a primitive and wrap it in a domain service that enforces your rules:
final class PasswordPolicyService
{
public function __construct(private PasswordGenerator $generator) {}
public function generate(int $length = 16): string
{
$this->generator
->setLength($length)
->setOptionValue(PasswordGenerator::OPTION_UPPERCASE, true)
->setOptionValue(PasswordGenerator::OPTION_LOWERCASE, true)
->setOptionValue(PasswordGenerator::OPTION_NUMBERS, true)
->setOptionValue(PasswordGenerator::OPTION_SYMBOLS, true);
return $this->generator->generatePassword();
}
/** @return string[] */
public function generateBatch(int $count, int $length = 16): array
{
$this->generator->setLength($length);
return $this->generator->generatePasswords($count);
}
}
Human-readable passwords (onboarding, support handoff) — the human generator needs a word list file:
public function __construct(private HumanPasswordGenerator $human) {}
public function generatePassphrase(): string
{
$this->human->setWordList(__DIR__.'/../Resources/wordlist.txt');
$this->human->setMinWordLength(4);
$this->human->setMaxWordLength(8);
$this->human->setWordCount(3); // or setLength() depending on version
$this->human->setSeparator('-');
$this->human->setCapitalize(true);
return $this->human->generatePassword();
}
Use a curated, reasonably long wordlist (EFF-style) rather than /usr/share/dict/words, and raise the word count so entropy stays acceptable.
Twig usage — handy for demo pages, fixtures previews, or a "generate" button in a back-office form:
<input type="text" value="{{ generatePassword(12) }}">
{# or, if the human helper is exposed #}
{{ generateHumanPassword() }}
CLI commands and fixtures — generators are convenient for seed data:
foreach ($generator->generatePasswords(50) as $pw) {
$faker = ...; // combine with Faker for user fixtures
}
Integration tips
GeneratorInterface, but the option constants differ (character options vs. word options).bin2hex(random_bytes(32))) over this library — the generators are aimed at readable passwords, not opaque tokens.Services are stateful and shared. setLength(), setOptionValue(), and setWordList() mutate the singleton. In a long-running worker (Messenger, RoadRunner, Swoole) or a request that generates two passwords with different policies, the second call silently inherits the first call's settings. Fix: clone $this->generator before mutating, or define the generator as a non-shared service:
services:
Hackzilla\PasswordGenerator\Generator\PasswordGenerator:
shared: false
Wordlist is mandatory for the human generator. Without setWordList() pointing at an existing, readable file, generation throws (or produces degenerate output, depending on version). Ship the wordlist inside your bundle/app resources and resolve the path with __DIR__ — not a relative path that breaks under bin/console.
Entropy vs. readability. HumanPasswordGenerator with 2–3 short words from a small list is weak. If it protects anything real, use at least 4–5 words from a large list, and enforce a minimum effective entropy in your policy layer rather than relying on the generator's defaults.
Check Symfony compatibility before committing. The bundle has a low release cadence; its composer.json constraint on symfony/framework-bundle may stop at 4.x/5.x. Verify composer why-not if you're on 6/7, and be ready to consume hackzilla/password-generator directly with a three-line service definition instead of the bundle.
Twig helper names and arity vary by version. Run bin/console debug:twig and read the actual signature instead of trusting the README — some versions take only an optional length, others expose option arrays.
Debugging generation failures: bin/console debug:container --show-private hackzilla, then dump the resolved service's options in a test (var_dump($generator->getOptions())) to see what state leaked in.
Extension points. Rather than editing vendor code:
GeneratorInterface and tag/alias it in your app if you need a policy-specific implementation.PasswordPolicyService — this is the cleanest seam for tests and for swapping libraries later.Security hygiene. Never log the generated plaintext, never email it in cleartext alongside the account identifier, and always force a password change on first login for admin-issued credentials. Test that generated passwords satisfy your validator (length, character classes) in a unit test — don't assume the library's defaults match your Assert\Regex rules.
How can I help you explore Laravel packages today?