How to Use A Different Password Encoder Algorithm Per User

How to Use A Different Password Encoder Algorithm Per User

Usually, the same password encoder is used for all users by configuring it to apply to all instances of a specific class:

  • YAML

    1. # config/packages/security.yaml
    2. security:
    3. # ...
    4. encoders:
    5. App\Entity\User:
    6. algorithm: auto
    7. cost: 12
  • XML

    1. <!-- config/packages/security.xml -->
    2. <?xml version="1.0" encoding="UTF-8" ?>
    3. <srv:container xmlns="http://symfony.com/schema/dic/security"
    4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    5. xmlns:srv="http://symfony.com/schema/dic/services"
    6. xsi:schemaLocation="http://symfony.com/schema/dic/services
    7. https://symfony.com/schema/dic/services/services-1.0.xsd"
    8. >
    9. <config>
    10. <!-- ... -->
    11. <encoder class="App\Entity\User"
    12. algorithm="auto"
    13. cost="12"
    14. />
    15. </config>
    16. </srv:container>
  • PHP

    1. // config/packages/security.php
    2. use App\Entity\User;
    3. $container->loadFromExtension('security', [
    4. // ...
    5. 'encoders' => [
    6. User::class => [
    7. 'algorithm' => 'auto',
    8. 'cost' => 12,
    9. ],
    10. ],
    11. ]);

Another option is to use a “named” encoder and then select which encoder you want to use dynamically.

In the previous example, you’ve set the auto algorithm for App\Entity\User. This may be secure enough for a regular user, but what if you want your admins to have a stronger algorithm, for example auto with a higher cost. This can be done with named encoders:

  • YAML

    1. # config/packages/security.yaml
    2. security:
    3. # ...
    4. encoders:
    5. harsh:
    6. algorithm: auto
    7. cost: 15
  • XML

    1. <!-- config/packages/security.xml -->
    2. <?xml version="1.0" encoding="UTF-8" ?>
    3. <srv:container xmlns="http://symfony.com/schema/dic/security"
    4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    5. xmlns:srv="http://symfony.com/schema/dic/services"
    6. xsi:schemaLocation="http://symfony.com/schema/dic/services
    7. https://symfony.com/schema/dic/services/services-1.0.xsd"
    8. >
    9. <config>
    10. <!-- ... -->
    11. <encoder class="harsh"
    12. algorithm="auto"
    13. cost="15"/>
    14. </config>
    15. </srv:container>
  • PHP

    1. // config/packages/security.php
    2. $container->loadFromExtension('security', [
    3. // ...
    4. 'encoders' => [
    5. 'harsh' => [
    6. 'algorithm' => 'auto',
    7. 'cost' => '15',
    8. ],
    9. ],
    10. ]);

Note

If you are running PHP 7.2+ or have the libsodium extension installed, then the recommended hashing algorithm to use is Sodium.

This creates an encoder named harsh. In order for a User instance to use it, the class must implement Symfony\Component\Security\Core\Encoder\EncoderAwareInterface. The interface requires one method - getEncoderName() - which should return the name of the encoder to use:

  1. // src/Entity/User.php
  2. namespace App\Entity;
  3. use Symfony\Component\Security\Core\Encoder\EncoderAwareInterface;
  4. use Symfony\Component\Security\Core\User\UserInterface;
  5. class User implements UserInterface, EncoderAwareInterface
  6. {
  7. public function getEncoderName(): ?string
  8. {
  9. if ($this->isAdmin()) {
  10. return 'harsh';
  11. }
  12. return null; // use the default encoder
  13. }
  14. }

If you created your own password encoder implementing the Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface, you must register a service for it in order to use it as a named encoder:

  • YAML

    1. # config/packages/security.yaml
    2. security:
    3. # ...
    4. encoders:
    5. app_encoder:
    6. id: 'App\Security\Encoder\MyCustomPasswordEncoder'
  • XML

    1. <!-- config/packages/security.xml -->
    2. <?xml version="1.0" encoding="UTF-8" ?>
    3. <srv:container xmlns="http://symfony.com/schema/dic/security"
    4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    5. xmlns:srv="http://symfony.com/schema/dic/services"
    6. xsi:schemaLocation="http://symfony.com/schema/dic/services
    7. https://symfony.com/schema/dic/services/services-1.0.xsd"
    8. >
    9. <config>
    10. <!-- ... -->
    11. <encoder class="app_encoder"
    12. id="App\Security\Encoder\MyCustomPasswordEncoder"/>
    13. </config>
    14. </srv:container>
  • PHP

    1. // config/packages/security.php
    2. // ...
    3. use App\Security\Encoder\MyCustomPasswordEncoder;
    4. $container->loadFromExtension('security', [
    5. // ...
    6. 'encoders' => [
    7. 'app_encoder' => [
    8. 'id' => MyCustomPasswordEncoder::class,
    9. ],
    10. ],
    11. ]);

This creates an encoder named app_encoder from a service with the ID App\Security\Encoder\MyCustomPasswordEncoder.

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.