This tutorial has a new version, check it out!

The UserProvider: Custom Logic to Load Security Users

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

The UserProvider: Custom Logic to Load Security Users

Hey there repository expert. So our actual goal was to let the user login using a username or email. If we could get the security system to use our shiny new findOneByUsernameOrEmail method to look up users at login, we’d be done. And back to our real job of crushing the rebel forces.

Open up security.yml and remove the property key from our entity provider:

# app/config/security.yml
    # ...

            entity: { class: UserBundle:User }

Try logging in now! Ah, a great error:

The Doctrine repository “Yoda\UserBundle\Entity\UserRepository” must implement UserProviderInterface.

The UserProviderInterface

Without the property, Doctrine has no idea how to look up the User. Instead it tries to call a method on our UserRepository. But for that to work, our UserRepository class must implement UserProviderInterface.

So let’s open up UserRepository and make this happen:

// src/Yoda/UserBundle/Entity/UserRepository.php
// ...

use Symfony\Component\Security\Core\User\UserProviderInterface;

class UserRepository extends EntityRepository implements UserProviderInterface
    // ...

As always, don’t forget your use statement! This interface requires 3 methods: refreshUser, supportsClass and loadUserByUsername. I’ll just paste these in:

// src/Yoda/UserBundle/Entity/UserRepository.php
// ...

use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;

class UserRepository extends EntityRepository implements UserProviderInterface
    // ...

    public function loadUserByUsername($username)
        // todo

    public function refreshUser(UserInterface $user)
        $class = get_class($user);
        if (!$this->supportsClass($class)) {
            throw new UnsupportedUserException(sprintf(
                'Instances of "%s" are not supported.',

        if (!$refreshedUser = $this->find($user->getId())) {
            throw new UsernameNotFoundException(sprintf('User with id %s not found', json_encode($user->getId())));

        return $refreshedUser;

    public function supportsClass($class)
        return $this->getEntityName() === $class
            || is_subclass_of($class, $this->getEntityName());


You can get this code from the resources directory of the code download.

Filling in loadUserByUsername

The really important method is loadUserByUsername because Symfony calls it when you login to get the User object for the given username. So we can use any logic we want to find or not find a user, like never returning User’s named “Jar Jar Binks”:

public function loadUserByUsername($username)
    if ($username == 'jarjarbinks') {
        // nope!

We can just re-use the findOneByUsernameOrEmail method we created earlier. If no user is found, this method should throw a special UsernameNotFoundException:

// src/Yoda/UserBundle/Entity/UserRepository.php
// ...

class UserRepository extends EntityRepository implements UserProviderInterface
    // ...

    public function loadUserByUsername($username)
        $user = $this->findOneByUsernameOrEmail($username);

        if (!$user) {
            throw new UsernameNotFoundException('No user found for username '.$username);

        return $user;

    // ... refreshUser and supportsClass from above...

Try logging in again using the email address. It works! Behind the scenes, Symfony calls the loadUserByUsername method and passes in the username we submitted. We return the right User object and then the authentication just keeps going like normal. We don’t have to worry about checking the password because Symfony still does that for us.

Ok, enough about security and Doctrine! But give yourself a high-five because you just learned some of the most powerful, but difficult stuff when using Symfony and Doctrine. You now have an elegant form login system that loads users from the database and that gives you a lot of control over exactly how those users are loaded.

Now for a registration page!

Leave a comment!

  • 2019-02-25 weaverryan

    Hey Mickel!

    Ok, we got it! Here is the long explanation, as you are far from the first person to be bit by this:

    The fix usually is just to remove the custom Serializable stuff from your entity - you almost never need this. That should fix the problem. There are some security implications with just returning true from isEqualTo(). The idea of that method is that Symfony passes you the User object stored in the session and the fresh User object from the database, and you're supposed to decide if they have changed enough to log the user out (return false to log the user out). The idea would be that, if you change your password, you might want all other systems that are currently logged in as you to be logged out. In that example, if you compared the hashed password field on the 2 users and they were not the same, you would return false from isEqualTo() to log them out. But again, just removing the serialization stuff (Serializable) solves the issue and you don't need to have an isEqualTo() method at all.

    By the way, this issue is not special to Guard - it's actually just that Guard sorta handles it "more properly" than form_login, so you're noticing much more easily that, currently, it appears that your user is alway changing.


  • 2019-02-20 Mickel

    Hi weaverryan, I think you DO know what the cause is.

    For some magical reason, implementing the EquatableInterface WORKED! Whaaaat! Yes whats up with that?

    FYI, currently using PHP 7.1.26 and Symfony 3.4.22. Also, have not changed the Serializer implementation (that wasn't it I guess).

    Well, thanks! Just as I was putting my eggs into the form_login basket, now have to put them back into the Guard basket. But now I know how to do it both ways, just have to read up more on Guard. ;-)

    Thanks for coming thru...

  • 2019-02-20 weaverryan

    Hey Mickel!

    Interesting! So, you had success with form_login... and you made NO other changes to your User (Account) class? That IS weird. What version of PHP are you using? If you're using 7.3, there's a small chance you're getting hit by a bug (which was fixed in Symfony 3.4.22). But let me know.

    One other thing to try - which would help rule out what is going on, would be to implement the EquatableInterface on your Account class. This will require you to have an isEqualTo(UserInterface $user) method. Just return true; from that. If that fixes your problem, then I'll know what the cause is. If not, then I'll know what the cause is NOT ;).


  • 2019-02-19 Mickel

    Hi weaverryan,

    I tried and removed the Serializer, and some other combination. But the Guardtoken kept losing it's user, or in some cases gets wiped out completely.

    So I went a bit backward, "sometimes you have to go backwards to go forwards" (Wolly Winka), and used the form_login instead (commented out guard), and created a simple PasswordEncoder. That seems to work fine, it's not as cool or flexible, but ok for now.

    I would still like to use Guard, but I am unsure why the GuardToken is not working for me.

    Thanks for you help, I will still try to get this to work, but this will get us passed one hurdle.

  • 2019-02-19 weaverryan

    Yo @Mickel!

    Super glad to hear you’re learning a lot :). Let’s see if we can figure this issue out!

    It certainly seems like a serialization issue. I noticed, at this moment, that your serialize and unserialize methods in Account are blank - I’m guessing just as part of debugging. Have you tried removing these and the Serializable interface? It’s usually not needed, and can mess things up.

    Also, for debugging, I’ll point you to a class at the core of Symfony - AbstractToken - it has a method called hasUserChanged(). This is called at the beginning of each request, once you’re authenticated. My guess is that this is returning false, and my guess is that a serialization problem is the issue.

    Let me know what you find out!

  • 2019-02-18 Mickel

    Yo SfCasts team,

    I have been learning a lot, and so far things have been going easy, but now i'm stuck/puzzled.

    I made a login form, made the authenticator, and after login, I am properly authenticated and authorized with a GuardToken.
    Then the redirect happens, and I still seem to be authorized, have roles, but Authenticated is "false".
    Any other action after that wipes out my login and redirects me to "/".

    To give to further details, the solution i'm trying to get to is a retrofit. Before Drupal did the authorization (their login form), but now we want to do it ourselves. We have a full-fledged User class, it's called 'Account', but implements UserInterface (also Serializable btw).
    And we already had an entity provider in security.yml.

    I'm not sure where it's going wrong, i'm thinking the serializer was not sending the correct stuff, but when removing the custom serialize (and un), after login I'm Authenticated, but my user is now unknown (blank)? Do I need a custom user provider?

    Hopefully you can help, before I figure it out myself ;-)


  • 2018-04-26 weaverryan

    Hey Patrick Vale!

    Hmm. So, it's not *exactly* possible, because always_remember_me is at the *firewall* level. You could of course create multiple firewalls, but that's taking a hammer to the situation :).

    But, the way that remember me NORMALLY knows that it should be activated, is by looking for a _remember_me checkbox in your form. So, you could add that to one form, but not the other. Or... you can even be a bit sneakier :). Even *without* that checkbox, I *think* (never tried before, but 99% sure) that you could *set* this value into the request, from inside your authenticator (could be anywhere):

    $request->attributes->set('_remember_me', true);

    That should activate it :).


  • 2018-04-26 Patrick Vale

    Hi Victor Bocharsky

    Thanks for the information - that's really helpful!

    I'd missed the "always_remember_me: true" option - that looks like just what I'm looking for!

    Is there a way to enable "always_remember_me: true" for just one (Guard) authenticator? So that, for example, you could have a FacebookAuthenticator which always set remember_me to true, but you had a GoogleAuthenticator which (for some reason) didn't set remember_me automatically?

    Thanks again!

  • 2018-04-26 Victor Bocharsky

    Hey Patrick,

    In case you're going to use a Symfony Guard authenticator - it has a fancy method to helps with it, see supportsRememberMe():

    Also, look at "always_remember_me: true" option:


  • 2018-04-24 Patrick Vale

    Hi weaverryan,
    Thanks for this awesome tutorial - I keep coming back to it when I want to extend our authentication system as a reference-guide!

    I have a question about enabling `remember me` functionality for a social oAuth login. What I want to be able to do is enable the same 'remember me' behaviour for users who have logged via the 'login with facebook' button, as those who have logged in via the login form, and checked the 'remember me' box.

    I had a look through the code, and followed it in xdebug step-by-step, but all the references to a `remember_me` setting seemed to be looking for a suitable value coming from a symfony form.

    Am I missing something or is there a way to tell a particular authenticator - 'I want to enable remember me all the time, please'?

    I'm using the fantastic KnpU oAuth Client Bundle (thanks!) to handle the social authentication, and my implementation is pretty much the same as the reference implementation in the readme of that repository.

    I thought I'd ask the question before I went back to xdebug again!

    Thanks for the great KnpU resource,


  • 2018-03-27 Vlad

    Thank you, Ryan!

  • 2018-01-17 weaverryan

    Hey Vlad!

    I'd definitely recommend using the Guard authentication system, but you can certainly do whatever you want :). But with JWT, there is no session: you're just validation the token on each request and decoding it to get some user information. You could honestly put this all into a service and then call that service from anywhere (e.g. a controller). You would then be completely avoiding Symfony's security system, for better or worse (i.e. you would not appear to be "authenticated" to Symfony). That service class would look something like this:

    class JWTAuthManager
    public function getUser()
    // inside, you would read the JWT from the Request object, verify it and decode it
    // you could then use the information from the JWT to fetch the User object from
    // the database and return it

    Again, I recommend using Guard. But ultimately, verifying a JWT, decoding it, and using the information on it is a pretty simple task. You could then make decisions based on the User. You could also move all of the verifying/decoding to a listener on kernel.request so that it happens automatically on each request. You would then set the User object on a service so that you could fetch it easily later. That would also make sending back error JSON responses (e.g. for an invalid JWT) easier.


  • 2018-01-15 Vlad

    Hello Ryan!
    If I want to do authentication myself (say, via JWT) and initiate a session the same way as you do here via Symfony's Authentication facility, what would I use for that?
    Thank you!

  • 2017-11-09 Victor Bocharsky

    Hm, probably it also depends on your PhpStorm / Symfony Plugin versions... but not all the yaml files could have autocomplete. It works mainly for app/config/config.yml. Go to PhpStorm preferences and find Symfony Plugin preferences - make sure you tick all the necessary checkboxes and enabled the plugin. Sometimes it may just stop working, especially after some internal PhpStorm errors, but after upgrade to the latest versions and PhpStorm restart it works again.


  • 2017-11-09 Mark Henriksen

    Have been running this the entire series, but cannot get yaml autocomplete to work :-( Tryed googling around a bit, but couldn't get an answer on how to "enable" really.

  • 2017-11-09 Victor Bocharsky

    Hey Mark,

    A lot of autocompletion for Symfony Framework comes from Symfony Plugin for PhpStorm, see where we show how to install and configure it.


  • 2017-11-09 Mark Henriksen

    How did you get Autocomplete in security.yml?

  • 2017-09-11 Diego Aguiar

    Hey deskema

    So you have an independent application in Drupal and another in Symfony, right? If so, the cleaner way to do it, would be to create a very basic API endpoint (In your Drupal app) for fetching your user's information (you may want to pass a secret key just to keep that endpoint secure). Going this way, you won't have to do a rework in the future when you scale those applications.

    Have a nice day :)

  • 2017-09-11 weaverryan

    Yo deskema!

    Ah yes, the famous user provider :). Can you tell us more about what you're trying to achieve? What do you mean by "use Drupal users inside a Symfony custom application"? Do you actually want to use the Drupal User class and code directly? Or do you mean that you want to just read from a Drupal application's User database and use that information inside Symfony?

    It's likely that the best solution will be to expose the Drupal user information via some sort of API inside Drupal, so that in Symfony, when the user logs in, your Symfony code can make an API request back to Drupal to say "Please check this password and tell me what permissions this user has". But a lot depends on what you need!


  • 2017-08-15 weaverryan

    Yo Mike!

    Very good! That *is* the correct way to handle it! We have a blog post about this stuff, if you want a bit more background: Either code will work in 3.2-3.4, but only the updated code will work in 4.0 and beyond.


  • 2017-08-14 Mike

    Everything works, but I get a deprecation error:

    Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. Try changing the type-hint for argument "$em" of method "AppBundle\Security\LoginFormAuthenticator::__construct()" to one of its parents: interface "Doctrine\ORM\EntityManagerInterface", or interface "Doctrine\Common\Persistence\ObjectManager".

    If I change:
    use Doctrine\ORM\EntityManager;
    public function __construct(FormFactoryInterface $formFactory, EntityManager $em,


    use Doctrine\ORM\EntityManagerInterface;
    public function __construct(FormFactoryInterface $formFactory, EntityManagerInterface $em,

    the deprecation message vanishes.
    Is this the correct way to do it?

  • 2017-07-17 weaverryan

    Hey Ahmedbhs!

    Yes, absolutely! In fact, it's very easy, but a little bit confusing :). Basically, Symfony forces you to use a "username" in a few places: in your User class, you must have a getUsername() method. And in your user provider, you must have a loadUserByUsername method.

    But.... if you want don't want a username, and instead just want an email, then simply make both of these methods work with an email instead. What I mean is, in User::getUsername(), return $this->email And in loadUserByUsername, query the database via your email field. Symfony is using the term "username"... but really, "username" is whatever unique thing you want - the "username", an email, a uuid or whatever.


  • 2017-07-16 Ahmedbhs

    How i can replace Loged in as "myusername" with "my emaill adresse" ?
    is it possible to made the authentification via email not via username?

  • 2017-05-18 Diego Aguiar

    hahaha that's funny ;)

  • 2017-05-17 Mike Ritter

    This is my picture every time Weaver says it.

    Good ol' Gene Wilder.

  • 2017-04-21 Diego Aguiar

    Hey Dominik!

    Sorry for the late response, I'm glad you could fix your problem without my help, you defenitely had a weird one ;)


  • 2017-04-20 Dominik

    It seems that i have solved the problem.

    I updated my PHP to 5.6.30
    I had to change the provider entity class name back to AppBundle/Entity/User for the login to work again.
    But i still got logged out again after a refresh.

    After that i run "composer update" to update the packages and dependencies.
    Now Symfony is running at version 3.1.10 and I finally stay logged in. Hooray!

    Setting my the course to "Logout" tutorial now .. lol :-)

  • 2017-04-19 Dominik

    Thanks for your help. Here we go:

    Symfony 3.1.4 - app - dev
    PHP 5.5.38 - no cache or APC
    i use the build in web server like in the tutorials.

    uhm .. perhaps this is the problem?
    PHP needs to be a minimum version of PHP 5.5.9
    The PHP versions seems to be little bit old on this machine *cought*

    or perhaps missing serialize functions in the authenticator?

    i needed the : notation for the entity to get the auth working at all.

    # To get started with security, check out the documentation:

    entity: { class: AppBundle:User, property: email }

    # disables authentication for assets and the profiler, adapt it according to your needs
    pattern: ^/(_(profiler|wdt)|css|images|js)/
    security: false

    anonymous: ~

    # activate different ways to authenticate

    # http_basic: ~

    # form_login: ~

    the different locale is not the problem

    - { resource: parameters.yml }
    - { resource: security.yml }
    - { resource: services.yml }

    # Put parameters here that don't need to change on each machine where the app is deployed
    locale: de
    cache_type: file_system

    #esi: ~
    translator: { fallbacks: ["%locale%"] }
    secret: "%secret%"
    resource: "%kernel.root_dir%/config/routing.yml"
    strict_requirements: ~
    form: ~
    csrf_protection: ~
    validation: { enable_annotations: true }
    #serializer: { enable_annotations: true }
    engines: ['twig']
    #assets_version: SomeVersionScheme
    default_locale: "%locale%"
    trusted_hosts: ~
    trusted_proxies: ~
    # handler_id set to null will use default session handler from php.ini
    handler_id: ~
    save_path: "%kernel.root_dir%/../var/sessions/%kernel.environment%"
    fragments: ~
    http_method_override: true
    assets: ~

    # Twig Configuration
    debug: "%kernel.debug%"
    strict_variables: "%kernel.debug%"
    thousands_separator: '.'
    - bootstrap_3_layout.html.twig

    # Doctrine Configuration
    driver: pdo_mysql
    host: "%database_host%"
    port: "%database_port%"
    dbname: "%database_name%"
    user: "%database_user%"
    password: "%database_password%"
    charset: UTF8
    # if using pdo_sqlite as your database driver:
    # 1. add the path in parameters.yml
    # e.g. database_path: "%kernel.root_dir%/data/data.db3"
    # 2. Uncomment database_path in parameters.yml.dist
    # 3. Uncomment next line:
    # path: "%database_path%"

    auto_generate_proxy_classes: "%kernel.debug%"
    naming_strategy: doctrine.orm.naming_strategy.underscore
    auto_mapping: true

    type: %cache_type%
    directory: %kernel.cache_dir%/markdown_cache

    and my LoginFormAuthenticator because i have to use the new onAuthenticationSuccess function

    formFactory = $formFactory;
    $this->em = $em;
    $this->router = $router;

    public function getCredentials(Request $request)
    $isLoginSubmit = $request->getPathInfo() == '/login' && $request->isMethod('POST');
    if (!$isLoginSubmit) {

    $form = $this->formFactory->create(LoginForm::class);
    $data = $form->getData();

    return $data;

    public function getUser($credentials, UserProviderInterface $userProvider)
    $username = $credentials['_username'];

    return $this->em->getRepository('AppBundle:User')
    ->findOneBy(['email' => $username]);

    public function checkCredentials($credentials, UserInterface $user)
    $password = $credentials['_password'];

    if ($password == 'iliketurtles') {
    return true;

    return false;

    protected function getLoginUrl()
    return $this->router->generate('security_login');

    use TargetPathTrait;

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    // if the user hits a secure page and start() was called, this was
    // the URL they were on, and probably where you want to redirect to
    $targetPath = $this->getTargetPath($request->getSession(), $providerKey);

    if (!$targetPath) {
    $targetPath = $this->router->generate('homepage');

    return new RedirectResponse($targetPath);

  • 2017-04-19 Diego Aguiar

    Hey Dominik!

    We are glad that you are liking our tutorials :)

    Could you show me how looks like your security.yml and config.yml files?
    Also what symfony version are you using ?

    Have a nice day!

  • 2017-04-19 Dominik

    Hey Ryan,

    the Symfony 3 Track is absolutely awesome!
    I followed the whole track without any problem .. until NOW ;-)

    Something seems to be wrong with my UserProvider setup.
    After the successful login and first redirect after the login the profiler shows my username correctly with token "PostAuthenticationGuardToken".
    but after a refresh of the page I am an anon user again with token "AnonymousToken".
    So it seems that i don't stay logged in.

    Dump after redirect:

    MainController.php on line 11:
    PostAuthenticationGuardToken {#129 ▼
    -providerKey: "main"
    -user: User {#38 ▼
    -id: 1
    -email: ""
    -roles: array:1 [▼
    0 => Role {#113 ▼
    -role: "ROLE_USER"
    -authenticated: true
    -attributes: []

    Dump after refresh:

    MainController.php on line 11:
    AnonymousToken {#113 ▼
    -secret: "58f76d7b47db04.57141949"
    -user: "anon."
    -roles: []
    -authenticated: true
    -attributes: []

    Strange: i don't get auto completion for the User entity in security.yml for the provider class property.

    Any idea what could cause this problem?


  • 2017-03-20 Victor Bocharsky

    Hey Simon,

    What's your OS? Windows? I had the same problem on Windows, opening a DB connection was always taking about 1s and I had response time over 1s (I used to use OpenServer). Btw, you can debug what exactly consumes a lot of this response time with Symfony's Web Debug Toolbar - just click on this time icon and you will see Performance section with a nice Execution timeline. Find your bottle neck there, I bet it's something like DB connection, etc. which is not related to PHP scripts execution.


  • 2017-03-18 Simon Carr

    I have followed almost all your tutorials on Symfony 3, but one thing I have noticed is that in the debug bar, you response time is more often than not around 50 to 100ms. Mine is constantly over 1000ms. I have a powerful modern PC I7 with 16GB and SSD drive. I have tried turning off virus checker but that does not make much difference. What could the difference be between your setup and mine?

  • 2017-03-02 weaverryan

    Hi Carlos!

    I have not actually used this bundle yet, but I think I can answer your question :). And, I can understand the confusion - it wasn't clear to me *why* this was needed in that bundle! So, It did a little bit of digging!

    It turns out, that the user provider is only needed by that bundle if you allow the "password" grant type (also called user credential grant type) to be used to get a token. In this model, your user sends their username and password directly to the server. IF you use this grant type, then the bundle calls the loadUserByUsername method on your user provider ( to fetch the user. So, you would only need a custom user provider if, for example, you allowed your users to send something other than a username (e.g. their "id") - you would then need a user provider whose loadUserByUsername() expects the $username to actually be an id, and then fetches the user by id.

    I hope that helps! If you don't set the user provider in the configuration for that bundle, I believe you won't have any problems, unless you try to use this grant type.


  • 2017-02-28 Carlos

    Hi Ryan, excuse me again ... =(

    I have a question with this subject.

    In my application I use the default Provider Entity of symfony, (I have not created a user provider).

    I want to use the bundle fos oauth server

    I imagine that you have used it sometime =)

    The documentation says:
    - If you're authenticating users, don't forget to set the user provider. Here's an example using the FOSUserBundle user provider:

    user_provider: fos_user.user_provider.username

    For this case, I enter the doubt written in my previous comments,
    In this case, I need to create my non-user provider?

    Regards Ryan, thank you very much

  • 2017-01-13 weaverryan

    Hey Carlos!

    Originally, people used the user provider inside of their authentication system in order to load their users. In fact, for many of the built-in authentication mechanisms, like form_login, http_basic, etc, this is still true: you submit a username + password form, and the form_login authentication mechanism uses your user provider (e.g. the entity provider) to know where to load that User. So, if you're using one of these mechanisms, and you need to load your users from a different location (perhaps your User information is stored across an API), you'll need a custom user provider.

    However, thanks to Guard, I recommend now that people use it to create their own authentication mechanisms whenever they have any non-standard situation (a login form that loads from the database is standard, so using form_login is fine). In Guard, *you* are in complete control of loading your User object however you want (in your getUser() method), and I recommend for clarity, *not* using your user provider to do this work. Instead, for example, if you need to load User information from some API, then just write the code in your authenticator and do it! In this situation, when would you need a custom user provider? Well, remember, a user provider does basically 2 things:

    A) It refreshes the User from the session (UserProviderInterface::refreshUser(UserInterface $user)
    B) It loads a user by username for remember_me and switch_user (UserProviderInterface::loadUserByUsername($username))

    So, you'll need a custom user provider basically if your User information is *not* stored in a database. If it is, just use "entity". If you *do* originally load User information from some other place (e.g. an API) but then save a new User database record for each user, then you should *still* use the entity provider. A custom provider is needed only if your User object can only be populated by loading data from some custom (i.e. non-database) source.

    So, in theory, it's not SO uncommon... but I rarely see it: almost always, people are loading users from a database. Even if they have some big central-authentication system, they often store a local User object in their database so that they can store application-specific information about that User. And as I mentioned, if this is the case, you should still use the entity provider.

    I hope this helps! The user provider is unfortunately confusing in Symfony, which is why I try to minimize how much people worry about it. In 99% of the use-cases, you should configure the "entity" provider in security.yml and never think of it again :).


  • 2017-01-12 Carlos

    Ah, I understood.
    We use the Symfony default user provider. Indicated in security.yml.

    Could you tell me a case where a custom user provider really needs it?
    Thanks Ryan

  • 2017-01-12 weaverryan

    Hey Carlos!

    Oh boy, the user provider is very confusing. First, you don't implement UserProviderInterface in the User entity - the User entity implements UserInterface. So, the User and your "user provider" are 2 separate things. But, what you said about the UserProvider is true: it allows you to use remember me functionality, save user to the session and do impersonation. And, in practice, all authentication systems *must* have a User Provider. So, it's a necessary part of your system, but many people don't even realize it exists or what it does. If you're using Doctrine and your User class is an entity, then you've probably configured the "entity" user provider in security.yml under the "providers" key ( Doing that is enough to configure a user provider that does all of the things you mentioned. I think it should be quite rare that you need a custom user provider.

    I hope this helps! It *is* confusing!

  • 2017-01-10 Carlos

    Hello, I have a question about the user provider.

    Is it mandatory to implement the UserProviderInterface class?

    As I understand it, if we implement UserProviderInterface in User Entity, we can make use of remember me functionality, save user in session, (this part, currently in the application does not perform it?) And perform impersonation users (currently, we do it and not We implemented UserProviderInterface and we use this).

    I have a little of trouble with this ...

    Thanks for your job

  • 2016-12-21 weaverryan

    Woohoo! You just tackled what I think is the hardest part of Symfony's security component (and maybe the most confusing part of Symfony in general). Congrats - and thanks for following up :)

  • 2016-12-21 Paul-André Duchesne

    Hi Ryan,

    First, sorry for my late answer.
    A great thanks for what you suggested, it's working fine...

    After having tried what you suggested, I've just chosen, at least, to keep the injection of the LdapUserProvider in my constructor to be able to use it in the instanciation of a new LdapBindAuthentication in the constructor self (used later on for ldapBindAuth->verifyAuthentication()). That facilitates also the call later on to the loadByUsername method (instead of copying it inside the authenticator and trying to get the necessary parameters used inside that method).

    I understand now correctly the distingo between the role of the "User Provider" for refreshing and passing the user at the beginning of each request and the effective injection of an other "ldap user provider" used for convenience later on...
    Without the ChainProvider existence, the things are cleaner and more understandable.

    Thanks again a lot, your courses and explanations are awesome !

    Kind regards,


  • 2016-12-14 weaverryan

    Hey Paul-André!

    Awesome! This is exactly the deep description I wanted! So, let me repeat your setup, in a slightly different way. No matter *how* the user is found or their password is checked, ultimately, all users are stored in the database. This means that you only have one User class (this is good) and that User class is an entity. This also means that, once a user is logged in, I can say with 100% certainty that I can find this user in our database, by using their username.

    So, this makes life GREAT for your UserProvider. Here's what I'd like you to do:

    A) Read / watch this page again ( just to really focus on the job of these user providers.

    B) Delete the ldap_users user provider and corresponding service entirely. I know you're injecting the LdapUserProvider into your authenticator to help with your work there, but to simplify things, stop doing that. Instead, implement the LDAP lookup logic yourself in the authenticator. This could mean copying this method into your authenticator: So, you'll now inject the Ldap class/service into your authenticator instead. Technically, you *could* still use the LdapUserProvider once we're done... but stop using it for now - I want to simplify what these "user provider" things are and aren't for.

    C) At this point, you will not be using *any* user provider inside of your authenticator. You'll simply be using the Ldap and EntityManager objects directly. Nice and simple.

    D) You will now only want *one* user provider in security.yml, and it will be your entity user provider. So, keep only that - and remove all the chain stuff.
    That should do it. Summary of this is:

    1) In your authenticator, forget that these "user provider" things exist. Just use Ldap and EntityManager to do your job. I can tell by your comments that you already understand the logic that should live in this class well.

    2) The *only* purpose of the "user provider" will be to "refresh" the user at the beginning of each request. Your User object is stored in the session. Then, on the next page, it's deserialized. The "entity" user provider will then use the primary key that User to re-query for a fresh one (to make sure its data is not stale). Since all our users are stored in the database, that's perfect! Ldap will not be involved in this part of the process at all.

    Let me know how it goes!

  • 2016-12-13 Paul-André Duchesne

    Hi Ryan,

    First, Great, Great thanks for having me lead in the right direction... with the LdapBindAuthenticationProvider. I've extended that class in one of my own and adapted the things a bit to mimic the checkAuthentication method.
    The main difficulties I encountered were at last with our AD authentication itself ;)

    So, to help you helping me with the chain provider, here are answers to the list of questions:
    * All the users of the application are stored in the database - our AD has got only the people who are still considered in activity in our institution - the AD has got thus only a subset of what is stored in the database. So, in the getUser method of my authenticator, I used only the EntityManager to get the corresponding user out of database.
    * As the AD is responsible of authenticating the "active" users and as the users can modify their password through their windows desktop, my intention (and what I've done) was:
    * if a user is authenticated against the AD, that meant his/her password was recognized... and that's ok... so in the checkCredentials method of my authenticator, I putted the call to the adapted checkAuthentication method in a try (as you suggested), and if it succeed, I return true.
    * if a user is not authenticated against the AD, I try to find him/her in the AD with the loadUserByUsername method of the ldap client. If (s)he's found, I return false meaning the username was right but password not and if (s)he's not found, I check if password is valid against the database. If yes, the user is logged in, otherwise, it sends back false (and thus invalid credentials)

    Concerning the update of password in the database, if the user succeed to login against the AD, I update (and encrypt) the password field of the user in the database.

    So the moment I'm extending the LdapBindAuthenticatorProvider who needs a UserProviderInterface and the moment I'm playing with a user coming from database, I guess I need both of them in a ChainProvider... Am I right ?

    Thanks again a hundred time for the help provided Ryan,

    Kind regards,


  • 2016-12-10 weaverryan

    Hi Paul-André!

    Unfortunately, I don't know a lot personally about LDAP. But, I do know a lot about Guard, so I'll do my best to help :).

    1) Since you're using Guard, obviously you need to do a little bit more work yourself in the authenticator (which is ok, because you also get a lot more flexibility). But, we can use the built-in LDAP authentication classes as inspiration for what we do. For example, the form_login_ldap authentication listener, is actually this class: So, how should you check the users password? Mimic was it's doing here: Specifically, the $this->ldap library is your service. So this is what you should inject into your authenticator.

    2) And yes, I noticed your "chain" user provider. User providers can be complex to understand, and we definitely have a problem here. First, make sure you review this: - it tries to explain the purpose of the user provider. Your exact correct setup depends on your needs. So, I'm going to ask a *bunch* of questions:

    As I understand it, your users should be able to login via their LDAP credentials or by logging in with their username/password that is stored in the database. Is this correct? Do you also have 2 different user classes? And, will you need to store application information about all users, or is the purpose for the users ONLY to be able to login? Will some users *only* exist in the database, but not in LDAP? And will some where *only* exist in LDAP and not in our local database? If a user exists in the database, but not in LDAP, will they thus manage their password in your system (instead of LDAP)? And if they exist in LDAP and not in your local database, I assume they will thus manage their password in LDAP and not your system? Or asked differently, is it true that some users will be logging in with their password in LDAP and other users will be logging in with their password that's manage by your system?

    Pass me some more information and I should be able to help your get your providers worked out correctly! But remember this point about providers:

    A) The point of a user provider is *only* to reload the user (e.g. from the database) at the beginning of each request. So, if ultimately - once the user has logged in - you have a local "user" record in your database for every user, then you *only* need the entity provider. Otherwise, yes, you'll need a chain provider like you have.

    B) When the user is originally logging in, you are in 100% full control of how that works - via your getUser() method. You could absolutely first look for the user in LDAP (you'll need a try-catch around loadUserByUsername, since this throws a UsernameNotFoundException) and if it's not found, look for it in your database.


  • 2016-12-09 Paul-André Duchesne

    Hello Ryan,

    I come towards you because I'm stuck with the implementation of authenticating against an ldap server with guard.
    I've followed a bit of this: - adapted a bit due to a bit outdated version of the documentation and I've got this:
    In services.yml:
    class: Symfony\Component\Ldap\Adapter\ExtLdap\Adapter
    - host: "%ldap_server%"
    autowire: true
    class: Symfony\Component\Ldap\Ldap
    arguments: [ "" ]
    autowire: true
    class: AppBundle\Security\LoginFormLdapAuthenticator
    autowire: true

    In security.yml:


    AppBundle\Entity\Person: bcrypt

    - ldap_users
    - db_users
    entity: { class: AppBundle\Entity\Person, property: uid }
    base_dn: cn=Users,dc=rbins,dc=be
    search_dn: "cn=%ldap_user%,ou=%ldap_ou%,dc=rbins,dc=be"
    search_password: "%ldap_pwd%"
    default_roles: [ROLE_USER]
    filter: (&(ObjectClass=Person)({uid_key}={username}))
    # disables authentication for assets and the profiler, adapt it according to your needs
    pattern: ^/(_(profiler|wdt)|css|images|js)/
    security: false

    pattern: ^/rest/
    anonymous: true
    stateless: true
    security: false

    anonymous: ~

    In the AppBundle\Security\LoginFormLdapAuthenticator in the constructor, I've been well defined a Symfony\Component\Security\Core\User\LdapUserProvider that I set in a $this->ldapUser variable that I use in the getUser method to check existence of the username in the Ldap...
    'Till that point everything's fine...
    But in the checkCredentials, I don't know what (and how) to call (and to inject in my constructor) to authenticate the user against the ldap server...

    Could you suggest me any direction that could help me going further ?

    Kind regards,


    PS.: You've certainly seen that I've defined a chain provider and two authenticators. My expectations were that if the first fails, it tries to fallback on the second one... But it didn't appeared to act so. For instance, if the user wasn't found in the ldap, it stopped and I got back to the login screen with the corresponding 'user unknown' exception displayed... and I've seen that the UserProvider parameter in the getUser was a ChainProvider containing the two others... What could I do to expect fall back on the second provider ? Should I only make one authenticator and handle the fallback in each methods ?

  • 2016-08-18 weaverryan

    Sweet! Catching your own errors? No better way to learn something :). Cheers!

  • 2016-08-18 james

    Yes found it just a few minutes ago, I forgot some private fields in LoginFormAuthenticator... My bad!

    Thanks anyway for the lightning fast answer!

  • 2016-08-18 weaverryan

    Hi James!

    That's really interesting! It *appears* that you logged in... but somehow are missing your User class. There's probably some tiny issue somewhere. Let's check out a few things:

    1) What does the getUsername() method look like in your User class? If there is some bug in this, and it's returning a blank string, then I *think* it might cause this problem :).

    2) If you hover over the icon in the web debug toolbar, what does it say for "Token class"? What about "Logged in as" - is that just blank?

    3) If you turn intercept_redirects temporarily back to *true* and login, does the web debug toolbar look any different before you actually redirect?

    4) After logging in, go into your favorite controller and run this code:


    Basically, you're getting logged in, but *something* is wrong with the User class, which is inside of this "Token" class. The above dump would tell us more info about what's going on.

    Let me know what you find out!

  • 2016-08-18 james

    Following everything and I have just something different as a result, the user username does not appear in the dev bar like you. It is just n/a; the authentification went through and I am logged in. What could be the cause?


  • 2016-06-29 weaverryan

    Nice job! It's actually quite different than the *old* "User Provider" chapter we had for Symfony2. Not a lot of has technically changed, but the way I like to explain it has :).


  • 2016-06-29 JLChafardet

    isnt this a recycled vid!! lol well i caught up! hope the next batch of vids comes soon

  • 2016-04-05 Diego Aguiar

    No problem, I hope someone find this useful

  • 2016-04-01 weaverryan

    Yes, good find! We changed that in Symfony 2.8 - the new interface is a little bit easier than the old one. DX improvement... as long as you know it exists :). Thanks for posting your solution!

  • 2016-03-31 Diego Aguiar

    I found it, in symfony3 no longer requires to implement "UserProviderInterface" instead it needs to implement "UserLoaderInterface"

  • 2016-03-30 Diego Aguiar

    Hi Ryan,
    looks like something has changed in symfony3, I've done everything thru this course and I'm always getting this error **Authentication request could not be processed due to a system problem.** when I try to login after doing the user provider change
    I just can't figure it out how to fix it, any help would be very appreciated

  • 2015-11-03 Medoune

    Hello, I works! It was due to the isAccountNonLocked() which was set to false!


  • 2015-11-02 weaverryan

    Hi there!

    This message can only be displayed because of 1 reason: your User class implements AdvancedUserInterface and the isAccountNonLocked() method returns false. Make sure this returns *true* for the User. I know, it has a confusing name "non-locked" is kind of a double negative. Anyways, here's the spot in the core that calls this method and gives you that error:


  • 2015-11-01 Medoune

    I have done everything for this lesson, and everything works well but when I try to log in with a username who is active, I get "Account is locked"! And I can't found what that issues is from?

    Sorry for my bad English

  • 2015-10-12 weaverryan

    Hey Léo!

    Ah, I missed this message! And it's a really good question. The reason is because of this "hide_user_not_found" option under security: This makes it so that when we throw a UsernameNotFoundException, it turns it into a different exception. Here's the code for that:

    There's a bit more behind the scenes to controlling the exception messages in Symfony, and it's something that's been improved in Symfony 2.8 so that you have more control via a class called CustomUserMessageAuthenticationException:


  • 2015-09-16 Léo Li

    Hello again,

    For this lesson, I've done everything, and it works well for login by username or by email. But, when I enter a username that doesn't exist, I still get an error "Wrong password bro!". But I think it should be "No user found for XXXX", right?