Search code examples
phpsymfonysymfony-3.4password-hash

Manually hash (i.e. encode) a string value in Symfony 3.4


Is there a way in Symfony 3.4 to use the password encoder without an entity that implements UserInterface?


Details

I want to hash a random string value in Symfony 3.4. I can always use password_hash, but I'm trying to do this the Symfony way and take advantage of the framework. Here's where I'm getting stuck:

The Symfony Documentation has an example, but it's using the UserPasswordEncoder which assumes you have an entity implementing UserInterface to pass as the first argument to encodePassword($user, $plainPassword).

In this case, I don't have a user entity because I'm generating a token for an email link. I do have an entity, but it feels wrong to have it implement UserInterface when it's not a user.

I dug into the code for UserPasswordEncoder and thought I could just inject the PasswordEncoderInterface which has a generic encodePassword($plainPassword, $salt) method, but I get this exception when I try to autowire it:

Cannot autowire service "SriBundle\Service\PubMatch\PublicationMatchLogService":
argument "$passwordEncoder" of method "__construct()" references interface
"Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface" but no such service exists.
It cannot be auto-registered because it is from a different root namespace.

It seems Symfony doesn't have a default service that implements PasswordEncoder and can be autowired. Am I missing something here, or does Symfony assume you only want to hash passwords for user entities and doesn't support encoding a hash for a random string value without passing in an associated user?


Solution

  • There is no PasswordEncoderInterface implementation service defined by default in Symfony. They are used internally with UserPasswordEncoderInterface.

    I found this thanks to the debug:container command.

    But you can easily define them yourself! Here is an example using SodiumPasswordEncoder in config/services.yaml file:

    services:
    
        # ... Your other definitions
    
        # Define an alias to allow autowiring on the interface
        Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface: '@password_encoder.sodium'
    
        # Define the concrete service
        # You can add the arguments entry if needed
        password_encoder.sodium:
            class: Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder