Buy

To use Guard - no matter what crazy authentication system you have - the first step is always to create an authenticator class. Create a new directory called Security and inside, a new class: how about LoginFormAuthenticator:

32 lines src/AppBundle/Security/LoginFormAuthenticator.php
... lines 1 - 2
namespace AppBundle\Security;
... lines 4 - 7
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
... lines 12 - 30
}

The only rule about an authenticator is that it needs to extend AbstractGuardAuthenticator. Well, not totally true - if you're building some sort of login form, you can extend a different class instead: AbstractFormLoginAuthenticator - it extends that other class, but fills in some details for us.

Hit Command+N - or go to the "Code"->"Generate" menu - choose "Implement Methods" and select the first three:

32 lines src/AppBundle/Security/LoginFormAuthenticator.php
... lines 1 - 4
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
... lines 8 - 9
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
public function getCredentials(Request $request)
{
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
}
public function checkCredentials($credentials, UserInterface $user)
{
}
... lines 23 - 30
}

Then, do it again, and choose the other two:

32 lines src/AppBundle/Security/LoginFormAuthenticator.php
... lines 1 - 9
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
... lines 12 - 23
protected function getLoginUrl()
{
}
protected function getDefaultSuccessRedirectUrl()
{
}
}

Tip

Starting in Symfony 3.1, you won't see getDefaultSuccessRedirectUrl() in this list anymore. Don't worry! We'll tell you how to handle this later.

That was just my way to get these methods in the order I want, but it doesn't matter.

How Authenticators Work

When we're finished, Symfony will call our authenticator on every single request. Our job is to:

  1. See if the user is submitting the login form, or if this is just some random request for some random page.
  2. Read the username and password from the request.
  3. Load the User object from the database.

getCredentials()

That all starts in getCredentials(). Since this method is called on every request, we first need to see if the request is a login form submit. We setup our form so that it POSTs right back to /login. So if the URL is /login and the HTTP method is POST, our authenticator should spring into action. Otherwise, it should do nothing: this is just a normal page.

Create a new variable called $isLoginSubmit Set that to $request->getPathInfo() - that's the URL - == '/login' && $request->isMethod('POST'):

53 lines src/AppBundle/Security/LoginFormAuthenticator.php
... lines 1 - 11
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
... lines 14 - 20
public function getCredentials(Request $request)
{
$isLoginSubmit = $request->getPathInfo() == '/login' && $request->isMethod('POST');
... lines 24 - 34
}
... lines 36 - 51
}

Tip

Instead of hardcoding the /login URL, you could instead check for the current page's route name: if ($request->attributes->get('_route') === 'security_login' && $request->isMethod('POST'))

If both of those are true, the user has just submitted the login form.

So, if (!$isLoginSubmit), just return null:

53 lines src/AppBundle/Security/LoginFormAuthenticator.php
... lines 1 - 22
$isLoginSubmit = $request->getPathInfo() == '/login' && $request->isMethod('POST');
if (!$isLoginSubmit) {
// skip authentication
return;
}
... lines 28 - 53

If you return null from getCredentials(), Symfony skips trying to authenticate the user and the request continues on like normal.

getCredentials(): Build the Form

If the user is trying to login, our new task is to fetch the username & password and return them.

Since we built a form, let's let the form do the work for us.

Normally in a controller, we call $this->createForm() to build the form:

398 lines vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php
... lines 1 - 38
abstract class Controller implements ContainerAwareInterface
{
... lines 41 - 274
/**
* Creates and returns a Form instance from the type of the form.
*
* @param string|FormTypeInterface $type The built type of the form
* @param mixed $data The initial data for the form
* @param array $options Options for the form
*
* @return Form
*/
protected function createForm($type, $data = null, array $options = array())
{
return $this->container->get('form.factory')->create($type, $data, $options);
}
... lines 288 - 396
}

In reality, this grabs the form.factory service and calls create() on it.

Dependency Inject form.factory (FormFactory)

So how can we create a form in the authenticator? Use dependency injection to inject the form.factory service.

Add a __construct() method with a $formFactory argument:

53 lines src/AppBundle/Security/LoginFormAuthenticator.php
... lines 1 - 11
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
... lines 14 - 15
public function __construct(FormFactoryInterface $formFactory)
{
... line 18
}
... lines 20 - 51
}

Now, I like to type-hint my arguments, so let's just guess at the service's class name and see if there's one called FormFactory. Yep, there's even a FormFactoryInterface!

53 lines src/AppBundle/Security/LoginFormAuthenticator.php
... lines 1 - 5
use Symfony\Component\Form\FormFactoryInterface;
... lines 7 - 11
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
... lines 14 - 15
public function __construct(FormFactoryInterface $formFactory)
{
... line 18
}
... lines 20 - 51
}

That's probably what we want. I'll press Option+Enter and select "Initialize Fields" to set that property for me:

53 lines src/AppBundle/Security/LoginFormAuthenticator.php
... lines 1 - 11
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
private $formFactory;
public function __construct(FormFactoryInterface $formFactory)
{
$this->formFactory = $formFactory;
}
... lines 20 - 51
}

If you're still getting used to dependency injection and that all happened too fast, don't worry. We know we want to inject the form.factory service, so I guessed its class for the type-hint, which is optional. You can always find your terminal and run:

./bin/console debug:container form.factory

to find out the exact class to use for the type-hint. We will also register this as a service in services.yml in a minute.

Return the Credentials

Back in getCredentials(), add $form = $this->formFactory->create() and pass it LoginForm::class:

53 lines src/AppBundle/Security/LoginFormAuthenticator.php
... lines 1 - 4
use AppBundle\Form\LoginForm;
... lines 6 - 11
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
... lines 14 - 20
public function getCredentials(Request $request)
{
$isLoginSubmit = $request->getPathInfo() == '/login' && $request->isMethod('POST');
if (!$isLoginSubmit) {
// skip authentication
return;
}
$form = $this->formFactory->create(LoginForm::class);
... lines 30 - 34
}
... lines 36 - 51
}

Then - just like always - use $form->handleRequest($request):

53 lines src/AppBundle/Security/LoginFormAuthenticator.php
... lines 1 - 22
$isLoginSubmit = $request->getPathInfo() == '/login' && $request->isMethod('POST');
if (!$isLoginSubmit) {
// skip authentication
return;
}
$form = $this->formFactory->create(LoginForm::class);
$form->handleRequest($request);
... lines 31 - 53

Normally, we would check if $form->isValid(), but we'll do any password checking or other validation manually in a moment. Instead, just skip to $data = $form->getData() and return $data:

53 lines src/AppBundle/Security/LoginFormAuthenticator.php
... lines 1 - 22
$isLoginSubmit = $request->getPathInfo() == '/login' && $request->isMethod('POST');
if (!$isLoginSubmit) {
// skip authentication
return;
}
$form = $this->formFactory->create(LoginForm::class);
$form->handleRequest($request);
$data = $form->getData();
return $data;
... lines 35 - 53

Since our form is not bound to a class, this returns an associative array with _username and _password. And that's it for getCredentials(). If you return any non-null value, authentication continues to the next step.

Leave a comment!

  • 2017-11-16 Mark Ernst

    Gotcha, thanks for feedback! Cruising along with my own Guard with full control instead of the default form_login. NICE.

  • 2017-11-15 Victor Bocharsky

    Hey Mark,

    I'm glad you got it working! As always, the most tricky errors to reveal are errors due to simple misprints :)

    Yes, good catch, each yaml file should have its own "_defaults", IIRC it's just to prevent BC breaks.

    Cheers!

  • 2017-11-15 Mark Ernst

    Alright. I am that guy that honestly posts after 1,5 hour of searching and after hitting enter finds out that he corrupted the AbstractFormLoginAuthenticator class @trigger_error portion by reading up and removing the semicolon.

    Eventually I also found out that declaring _defaults in the services.yml doesn't work globally. I'm also using AppBundle specific Resources which also include a set of services (in the .yml file). Upon copying those defaults introduced in 3.3 it all worked like a charm.

  • 2017-11-15 Mark Ernst

    I must be missing something. I've been following the course with 3.3.12 and up until the autowiring, which I skipped (since 3.3.12 does that for me). Now I'm getting the error "Class Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator not found" for some reason. If I add 'Security' to my exclude pattern, the service cannot be found ("exclude: '../../src/AppBundle/{Entity,Repository,Tests,Security}'"). I'm currently at a loss as how this is occurring...

  • 2017-10-02 weaverryan

    Yo maxii123!

    Hmm... you might be right... I'm not sure yet :). What do you mean by:

    > that the firewall does not automatically pass

    Are you talking about access_control entries... i.e. the request NOT hitting one of those? Or are you talking about requests that don't go through any firewall? Really, your authenticator should be called on EVERY request (that matches a firewall... which in our app is every request) - it should be independent of access_control. Let me know what you meant by that, and what you're seeing. We may be able to clarify for others :).

    Thanks!

  • 2017-10-02 Victor Bocharsky

    Hey @mamaxii123 ,

    I haven't used JSMi18N bundle personally, but it looks good. Anyway, using route name instead of its path is much simplier and reliable solution. Thanks for sharing it with others!

    P.S. I tweaked your message a bit to have nice styles for code blocks ;)

    Cheers!

  • 2017-10-01 maxii123

    A small question regarding the use of the JSMi18N routing bundle. Does this seem like a reasonable solution to having login work with this bundle ( eg /login becomes /de/login when not using the default locale)?


    public function getCredentials(Request $request)
    {
    $path = $request->getPathInfo();

    $isLoginSubmit = $request->isMethod('POST') &&
    (
    ($path == '/login')||
    ($path == "/" . $request->getLocale() . '/login')
    );

    if (!$isLoginSubmit) {
    // no login form and a post so
    // skip authentication
    return null;
    }

    *POST EDIT* : switching to using the route eg


    if (!($request->attributes->get('_route') === 'security_login' && $request->isMethod('POST'))){
    // no login form and a post so
    // skip authentication
    return null;
    }

    Fixes this "properly". Cheers. I'll leave this here anyway as I see in google others have had similar issues.

  • 2017-10-01 maxii123

    Similar to a comment on the previous video (and I think it is important because security is the first real "meat" people need to get to grips with) . Change "When we're finished, Symfony will call our authenticator on every single request" to "When we're finished, Symfony will call our authenticator on every single request that the firewall does not automatically pass". If I'm wrong then I have misunderstood something and that wouldn't surprise me at all.

  • 2017-07-05 Victor Bocharsky

    Hey maxii123 ,

    Thanks for your opinion! Yes, I agree it's better to use router to generate an actual path... but it's not a huge deal. Really, if you test login form in your application - this problem will be caught by tests.

    Cheers!

  • 2017-07-03 maxii123

    Just to reiterate what terry said, despite you moving onto "injection" later in the course I think it would be much better for you to show how not to hardcode the login URL at this stage and instead somehow use the security_login route tag. It might not seem much but it certainly had me scratching my head and wondering why on earth it IS hard coded after so many warnings against exactly that.

  • 2017-06-14 weaverryan

    Yo JSThePatriot!

    Ah, interesting! That was a line that I didn't originally add to AbstractFormLoginAuthenticator, but I see it! In the framework (unless you're doing something crazy), you shouldn't need this. In theory, you could configure things to not have a Session object at all - so getSession() would return null (I'm not sure why they did it as an instanceof check, but they're basically checking to see if the Session exists). Feel free to keep it in, but you won't need it.

    Good question man! Cheers!

  • 2017-06-09 JSThePatriot

    weaverryan In the original implementation that is now deprecated you had the following lines that you no longer have... should we still have them, or do like the above and leave them out?


    $targetPath = null;

    // This comment wasn't in there, but the contents of this if is your $targetPath = line.
    if ($request->getSession() instanceof SessionInterface) {}
  • 2017-06-05 Clement Samuel

    Thank you, setting up the web_profiler did it.

  • 2017-06-05 Diego Aguiar

    Hey Clement Samuel

    I believe you forgot to inject them in the arguments key of the definition of your LoginFormAuthenticator, or use "autowiring" as shown in the next video.

    Cheers!

  • 2017-06-05 Clement Samuel

    Hello!!
    I get this ,
    Type error: Too few arguments to function AppBundle\Security\LoginFormAuthenticator::__construct(), 0 passed in C:\xampp\htdocs\blog\var\cache\dev\appDevDebugProjectContainer.php on line 345 and exactly 3 expected

  • 2017-06-01 weaverryan

    Hey Attila László!

    It's still a mystery to me! You're rendering your form correctly and handling the request in the authenticator just fine. From everything I can see, it *should* be properly processing the data through the form! So, I'm sorry I can't give you an answer! As I mentioned earlier, the way that does *not* use the form in the getCredentials() method is a little simpler/nicer anyways in my opinion (and I'll use that way personally on the future). So, stick with that :).

    Cheers!

  • 2017-06-01 Attila László
  • 2017-05-31 weaverryan

    Hey!

    Can you post your login.html.twig and LoginFrom.php file also?

    Cheers!

  • 2017-05-30 Attila László

    Thx for the reply!

    These are the files in question:

    - https://pastebin.com/BTaQAEtX
    - https://pastebin.com/CG1ET7CH
    - https://pastebin.com/FWxzcz1m
    - https://pastebin.com/TKfFzQhW

    Hope we can figure it out, because I really want know these things.

  • 2017-05-26 weaverryan

    Hey Attila László!

    Ah, awesome! Usually, when you submit and see *nothing* it's either because your authenticator is not being called (i.e. it's not configured correctly in security.yml) or you have a bug in your getCredentials() method, so that it is not returning the credentials when it should.

    In this case, it looks like you basically added some code to skip the form framework and instead grab the POST information directly from the request. That's a great way to do it, and actually, I wish I had done it this way - it's a bit simpler with no downside. You should be able to simplify your code:


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

    if ($isLoginSubmit) {

    $req = $request->request->get('login_form');

    return [
    '_username' => $req['_username'],
    '_password' => $req['_password'],
    ];
    }

    // just return null: do no processing on this request
    return;
    }

    I'm not sure what the problem was in your case... the form *should* have been processing the data just fine. But, I like your approach better anyways :).

    Cheers!

  • 2017-05-25 Attila László

    Hey Ryan!

    I coded everything by the new updated way. So I'm on the login page and after I hit submit, it does nothing and always redirects back to the login page. It doesn't matter if using the correct password or a wrong one.

    In the profiler the POST values are there, but in the form section it shows null.

    UPDATE: After some extensive google search I got it working.


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

    if ($isLoginSubmit) {

    $req = $request->request->get('login_form');

    return [
    '_username' => $req['_username'],
    '_password' => $req['_password'],
    ];
    }

    $form = $this->formFactory->create(LoginForm::class);
    $form->handleRequest($request);

    $data = $form->getData();

    dump($data);

    return $data;
    }
  • 2017-05-06 Hermen

    Sjeeez, it was waaay more basic... forgot the 'return' in getUsername()...

    Thanks anyway!

  • 2017-05-05 weaverryan

    Hey Hermen!

    Ah, fascinating! The toolbar shows n/a? Hmm, what does your firewall look like? Usually, that toolbar only either shows (A) your username or (B) anon, if you're not logged in. n/a almost makes me think that the URL you're visiting isn't covered by your firewall. But that's just a first guess!

    Cheers!

  • 2017-05-04 Hermen

    Hey Ryan,

    I was a little bit to early with my conclusion. It works, but the toolbar does not show my username. That's why I thought something went horribly wrong...

    Now trying to figure out why the toolbar shows n/a instead of my username...

  • 2017-05-04 weaverryan

    Hey Hermen!

    Hmm. So if you're on Symfony 3.1, then you *should* have onAuthenticationSuccess, but having it is technically optional until Symfony 4 (if you don't have it, you'll just receive a warning). But in either case, that method should have nothing to do with whether or not authentication is required for some endpoint - that's very strange. Let's debug!

    A) If you don't have onAuthenticationSuccess, what is the error?
    B) When you are taken to the page where no authentication is required, what do you see in the web debug toolbar for security? Does it say "anon"? And what code *should* be forcing authentication on that page? Do you have an access_control or a denyAccessUnlessGranted in a controller?

    Let me know - we'll figure it out!

    Cheers!

  • 2017-05-03 Hermen

    Hey Ryan,

    It all works until... onAuthenticationSuccess has to be called. If it isn't there, explosion. If it is there, no authentication required and I get taken to the page I requested, behind the firewall...

  • 2017-04-04 Victor Bocharsky

    Hey Terry,

    I think you're right. This place can be error prone in future if the login URL changes. In the next chapter we inject a router into the authenticator, so you can easily reuse it to generate the URL.

    Cheers!

  • 2017-04-03 Terry Caliendo

    At about the 2 minute mark, you hard code "/login". It would be better to somehow call the path "security_login" created in the routing of the controller, correct? In case "/login" later changes to something else.

  • 2017-03-30 weaverryan

    Hey Hermen!

    Apologies for my slow reply! I was talking with Victor internally here, and he had the same question as you! And the reason is... you're right! I think I over-complicated things here :). In hindsight, I probably would have:

    A) Used the Form object to render the form (as I'm doing now), but overridden getBlockPrefix() to return an empty string (this is optional, but nice, because now the submitted values won't be "hidden" in the request on submit under a "namespace" key)

    B) Then just fetched those values out without the form in the authenticator - e.g. $request->request->get('_username')

    So great question! I wanted to use the form to make rendering easier... but I really didn't need it (and probably shouldn't have gone to all the trouble of using it) in the authenticator.

    Cheers!

  • 2017-03-26 Hermen

    Hey Ryan, why are you doing all the stuff with form.factory in getCredentials() when the username and password are also in the Request?

  • 2017-03-14 weaverryan

    Haha, you nailed it - every time Symfony makes a change, I rejoice... and I cringe :D. I just added an issue internally to add a note to this chapter and the next (next chapter is where we actually code up this method).

    Cheers!

  • 2017-03-14 Tony C

    Well that's good to know! Thank you!

    Backwards compatibility... a blessing and a curse all rolled up in one idea.

  • 2017-03-14 weaverryan

    Yo Tony C!

    It's not an accident :). Thanks to Symfony's backwards-compatibility promise, the way that's shown in the screencast still works, and will continue to work until Symfony 4.0. I'm actually the one who made this change to Symfony, so I'm well aware of it! We update the screencasts once a new major version of Symfony comes out - it's our way of balancing keeping things up to date, but not constantly re-recording things for tiny changes. It's not a perfect system :). Symfony's backwards compatibility promise helps us (and developers) out a lot with this!

    But, in hindsight, I do think a note is in order - if you code with the tutorial perfectly, there's no problems. But if you use the PHPStorm shortcuts for "implement methods", then you won't see all the methods that we get in the recording - and that can be confusing indeed!

    Cheers!

  • 2017-03-14 Tony C

    Why haven't you updated the course yet?

  • 2017-02-13 weaverryan

    And actually, I had some misleading code in my comment above! You should *not* need to call getDefaultSuccessRedirectUrl at all anymore in the new way - my misleading code is what confused you on this! I've just updated the original code in my comment above with the not-misleading, proper way.

    Cheers!

  • 2017-02-13 weaverryan

    Peter Tsiampas Ah, you're right! I mis-spoke in my previous message! Basically, the solution in the video works, but we made some changes in Symfony, so the new "non-deprecated" version is available above in my comment: https://knpuniversity.com/s...

    Basically, you should now implement onAuthenticationSuccess yourself, and inside, you'll make use of getTargetPath(). If you do this, then you don't need the getDefaultSuccessRedirectUrl at all :). But, I can see now that my code-block above is mis-leading on this! So, Peter, you did the right thing by adding getDefaultScucesRedirectUrl yourself, but it's actually not needed. Check (in about 2 minutes) my updated code above the comment I linked to :).

    Cheers!

  • 2017-02-13 Peter Tsiampas

    I just looked at the TargetPathTrait and it only has 3 functions, Save, Get and Remove. The getDefaultSucessRedirectUrl has been removed - v3.2.3.
    Am I looking at the wrong spot? or should I just do the redirect myself (Figured what the hell, just create it until I get a response :P )?

  • 2017-02-10 weaverryan

    Hey Hermen!

    The getTargetPath function comes from the TargetPathTrait. Make sure you're "using" this in your class. And you're right that getTargetPath is private! But that's ok - it's legal to use a private method from a trait (effectively, when you "use" a trait, its methods are copied into your class - so you CAN access private methods).

    Let me know if that helps!

  • 2017-02-10 Hermen

    Well, that's one question answered. This method should definitly be public (Symfony says so ;-) ), but than the shit hits the fan. The method getTargetPath is private (big explosion) and getDefaultSuccessRedirectUrl is not found... So, the stuff from the video is out of date and the stuff in the comment is incomplete. Bummer...

  • 2017-02-10 Hermen

    And is this a public or protected function? Since getDefaultSuccessRedirectUrl was protected...

  • 2016-12-11 Eddy de Boer

    Thx for the question, I had the same problem.

  • 2016-10-20 Matt-You

    Oh that makes sense now! I have just started the section on Authorization; what a coincidence then ;)

    Thank you very much for your clear answer!

  • 2016-10-19 weaverryan

    Hey Matt!

    That is normal! But it's a bit tricky. What I mean by "every single request" is this:

    Your authenticator will be executed on every single request, which means that it will look to see if authentication information is present on every single request. If it is, the user will be authenticated. If there is no authentication information on a request, the request will continue into the system as an "anonymous" request.

    So, the authenticator's job is just to *try* to authenticate the user. But if there is not authentication information (e.g. username/password) on the request, it just let's the request continue anonymously. Its job is *not* to actually deny access or require login for any of your pages (that's called "authorization") - that's done elsewhere. The only time that the authenticator sort of "blocks" an incoming request is when there *is* authentication information on the request, but it's invalid (e.g. invalid password).

    To actually require login on an endpoint, you can either use the access_control section of security.yml or use deny access in the controller. If you do this, then when an anonymous request enters the system, the authenticator *will* allow it to continue, but then it will be blocked when it hits your controller.

    Does that makes sense? Someone else had this exact question very recently - it's a good one :).

    Cheers!

  • 2016-10-18 Matt-You

    Hello there,

    I have a question. You write that Symfony will call the authenticator on "every single request". I followed the tutorial step by step but I still can access pages directly without logging in (for example, "/index"). Is it normal? Will itbe discussed later in the tutorial?

    Cheers,
    Matt

  • 2016-07-06 weaverryan

    Cheers back! Thanks for bringing this to our attention - I'm sure this conversation will help others with the same question :)

  • 2016-07-06 Dominik

    Thank you guys for reply!

    I'm using symfony 3.1 but for this tutorial i will use the getDefaultSuccessRedirectUrl() method.

    As you said it is still few years to symfony 4 ;)

    Cheers!

  • 2016-07-01 weaverryan

    Ah yes, I think you're right about 3.1 Victor.

    So, in 3.1, you *can* still override getDefaultSuccessRedirectUrl(), but you'll need to add the method to your authenticator yourself (if you go to Code -> Generate in PHPstorm, it won't be added for you anymore).

    But more long-term, we removed this method (actually, I did it - it's my fault! https://github.com/symfony/..., and instead we want you to add a different method - called onAuthenticationSuccess(). If you're in Symfony 3.1, you should be able to do this:


    use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
    use Symfony\Component\Security\Http\Util\TargetPathTrait;
    use Symfony\Component\HttpFoundation\RedirectResponse;

    class LoginFormAuthentication extends AbstractFormLoginAuthenticator
    {
    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);
    }
    }

    Basically, onAuthenticationSuccess() is *really* the method in charge of things. Previously (and it still works, but is deprecated in 3.1), you could just implement getDefaultSuccessRedirectUrl(), and this method would be taken care of for you. Feel free to do either (use getDefaultSuccessRedirectUrl() or the above code) - both will work, but the above code will be the way forward when Symfony 4 is released in a few years.

    Cheers!

  • 2016-07-01 Victor Bocharsky

    Hey, Dominik!

    Thanks for let us know, I've fixed wrong authenticator name right now in 1f26635.

    Ah, looks like Symfony had some changes due to deprecations in AbstractFormLoginAuthenticator since Symfony 3.1. Did you upgrade to 3.1? What Symfony version do you use?

    Cheers!

  • 2016-07-01 Dominik

    Hello!
    First things first:
    In script it is: FormLoginAuthenticator and in code's script: LoginFormAuthenticator

    The second problem is with Code->generate:
    I don't have getDefaultSuccessRedirectUrl(); It's weird. Is it some kind of bug?