octave/password-bundle
A Symfony bundle for password handling: secure hashing, configurable strength and policy validation, and smooth migration of legacy hashes. Integrates with Symfony's security component to keep authentication modern and consistent across your application.
The package targets Symfony 4 and advertises itself as "user password utils" — in practice that means a small bundle of services around Symfony's UserPasswordEncoderInterface plus (typically) forgot/reset-password plumbing. Treat it as a thin utility layer, not a full auth system.
Minimal steps:
composer.json for the actual name field — it may differ from the path-style octave/password-bundle you see in the URL. Require that exact name:
composer require octave/password-bundle
config/bundles.php:
Octave\PasswordBundle\OctavePasswordBundle::class => ['all' => true],
(The class name is worth verifying in the bundle's root PHP file — it may be OctavePasswordBundle or PasswordBundle.)composer.json → required symfony/* versions and autoload path. This tells you immediately whether it will even boot on your Symfony version.src/Resources/config/ (or Resources/config/) → the service definitions. This is the authoritative list of what the bundle actually wires up. Everything else is decoration.DependencyInjection/*Extension.php → the config tree, i.e. what keys you can set under octave_password: in config/packages/.src/ → the real logic. With 0 stars and 0 dependents, read it before trusting it.bin/console debug:container --tag=… # if the bundle tags services
bin/console debug:container Octave # find the encoder service id
bin/console config:dump-reference octave_password
public function register(Request $request, UserPasswordEncoderInterface $encoder)
{
$user = new User();
$user->setPassword($encoder->encodePassword($user, $request->request->get('password')));
// persist…
}
If the bundle already decorates or aliases UserPasswordEncoderInterface, you may get its behaviour for free — check the extension file rather than assuming.Treat it as a decorator over Symfony's own encoder. The bundle is only useful if it adds something on top of Symfony's built-in hashing — typically salt handling, a configured algorithm, or migration-on-login (rehash when the cost/algorithm changed). Wire it behind the standard interface so your application code is not coupled to the bundle:
// config/services.yaml
App\Security\PasswordEncoder: ~ # or bind to the bundle's service id
If the bundle exposes a concrete class instead of an interface, define your own interface and adapt — this makes the eventual rip-out trivial.
Registration flow pattern:
User entity, set only the raw password temporarily.flush(), never store raw.PRE_PERSIST Doctrine listener if you want the encoding centralised rather than scattered across controllers.Reset-password workflow pattern. If the bundle ships token entities/controllers, the usual shape is:
POST /forgot-password → look up user by email, generate token, persist with expiry, send mail.GET /reset-password/{token} → validate token exists, expiresAt > now(), not already consumed.POST /reset-password/{token} → encode new password, invalidate token, optionally invalidate all sessions.If it does not ship this, the "password utils" is likely just the encoder and you are writing the rest yourself — which is fine and often preferable.
Migration-on-login pattern (the one genuinely valuable thing a password bundle can give you):
if ($encoder->isPasswordValid($user, $plain, $user->getSalt())
&& $encoder->needsRehash($user->getPassword())) {
$user->setPassword($encoder->encodePassword($user, $plain));
}
This lets you raise bcrypt cost or swap algorithms without forcing a reset. Check whether the bundle's service exposes needsRehash — if not, fall back to the framework's.
Integration tip — user provider contract. Symfony 4 expects your User class to implement UserInterface (and usually PasswordAuthenticatedUserInterface on 5.3+). The bundle's utilities assume a salt column exists (getSalt()), so keep it even if you use bcrypt/argon2 where it is unused.
Migration pattern when you outgrow it. Symfony 5.3+ renamed the contract to PasswordHasherInterface and dropped UserPasswordEncoderInterface. Plan the exit: alias the old interface to the new hasher, keep your own thin wrapper, and delete the bundle once your config/bundles.php no longer references it.
src/ end to end. Specifically look for md5, sha1, uniqid(), rand(), and mt_rand() — old password utilities frequently predate random_bytes() and will silently generate weak reset tokens.composer.json will likely pin symfony/*: ^4.0. On Symfony 5.3+ UserPasswordEncoderInterface and encodePassword() are deprecated and removed in 6.0; the bundle will either fail to install or emit deprecations on every request. Do not fight Composer with --ignore-platform-reqs — you will get a container that compiles and a runtime that doesn't.$user->getSalt(). If your User entity dropped the salt column (common in modern apps), every encode/verify call throws. Either keep the column returning null or add an adapter that ignores the argument.expiresAt field and a comparison in the consume path. A token with no expiry is a permanent backdoor if an email inbox is ever compromised.DELETE or used flag flip inside a transaction with the token read. Without that, a double-click on the reset link races and can double-apply.octave_password, octave, or something else) is not necessarily derivable from the package name. Run bin/console config:dump-reference <guess> and, failing that, read DependencyInjection/Configuration.php directly.bin/console debug:container --show-private | grep -i password will tell you whether the service actually made it into the compiled container — often the bundle registers nothing because it is not in bundles.php or the config key is wrong.symfony/mailer, expect an incompatible messenger/mailer bridge and plan to override the mailer service.Resources/config/services.xml, then redefine it in your own services.yaml under the same id to swap behaviour — no fork required.@OctavePassword/... is the likely namespace; override by registering the same path earlier in config/packages/twig.yaml rather than editing vendor files.PasswordHasherInterface.How can I help you explore Laravel packages today?