From Install to JS Testing

Welcome to the magical world of Behat, my favorite library. No joke this thing is the best. Behat is about two things:

BDD, Functional Testing and... Planning a Feature???

First, functionally testing your application. Which means writing code that will open a browser, fill out a form, hit submit and verify text on the other side.

Why test your application? Well, imagine you are in charge of safety at Jurassic Park, your job is to make sure guests aren't eaten by dinosaurs. You need to be certain that the new pterodactyl exhibit that's being put in won't turn off the electric fence around the velociraptor pen. No tests? Good luck, they know how to open doors.

And second, designing your application. As developers we'll often just start coding without thinking about what we're building or how the feature will behave.

Using behavior driven development, which Behat helps you do, you'll actually plan things out beforehand.

Imagine a world where communication on your team is perfect, you always deliver exactly what your client wants, electricity on the raptor fence never goes down and chocolate ice cream is always free. Yep, that's where we're going.

Behat Docs

Over in the browser, let's surf to the Behat documentation. In this tutorial we're covering version 3, and for whatever reason when I recorded this the website still defaults to version 2.5. So double check that you are actually looking at version 3's documentation.

I've got our project, the raptor store, loaded here. This is where dinosaurs go for the newest iphone and other cool electronics. There's a homepage, an admin section and that's basically it. This store is built using a very small Symfony2 application -- but hey, don't panic if you're not using Symfony: everything here will translate to whatever you're using.

Cool, we've got a search box, let's look up some sweet Samsung products. And here are the two results we have. I want to start this whole Behat thing by testing this. Hold onto your butts, let's going to get this thing running!

Install and Configuration

Over in the terminal run composer require and instead of using behat/behat we'll grab: behat/mink-extension and behat/mink-goutte-driver:

composer require behat/mink-extension behat/mink-goutte-driver

These are plugins for Behat and another library called Mink and they require Behat and Mink. We see the Mink library downloaded here, and the Behat library downloaded down there. So life is good!

Once you've downloaded Behat you'll have access to an executable called ./vendor/bin/behat or just bin/behat for Symfony2 users. Running it now gives us a nice strong error:


That's ok because we need to run it with --init at the end just one time in our application:

vendor/bin/behat --init

This did an underwhelming amount of things for us. It created two directories and one file.

In PhpStorm we see a features directory, a bootstrap directory and a little FeatureContext.php file and that's all of it:

... lines 1 - 2
use Behat\Behat\Context\Context;
use Behat\Behat\Context\SnippetAcceptingContext;
... lines 5 - 6
... lines 8 - 10
class FeatureContext implements Context, SnippetAcceptingContext
... lines 13 - 19
public function __construct()

While we're here, I'll add a use statement for MinkContext and make it extend that. I'll explain that in a minute:

... lines 1 - 6
use Behat\MinkExtension\Context\MinkContext;
... lines 9 - 11
class FeatureContext extends MinkContext implements Context, SnippetAcceptingContext
... lines 13 - 25

One last bit of setup: at the root of your project create a behat.yml file. I'll paste in some content to get us started:

6 lines behat.yml
base_url: http://localhost:8000
goutte: ~

When we run Behat it will looks for a behat.yml file and this tells it:

Yo! Our application lives at localhost:8000, so look for it there.

Your First Feature and Scenario

Behat is installed, let's get to writing features! In the features directory create a new file called search.feature and we'll just start describing the search feature on the raptor store using a language called Gherkin which you're about to see here.

Feature: Search
In order to find products dinosaurs love
As a website user
I need to be able to search for products
... lines 5 - 11

Here I'm just using human readable language to describe the search feature in general. Within each feature we'll have many different scenarios or user flows. So let's start with Scenario: Searching for a product that exists. Now using very natural language I'll describe the flow.

... lines 1 - 5
Scenario: Search for a word that exists
Given I am on "/"
When I fill in "searchTerm" with "Samsung"
And I press "search_submit"
Then I should see "Samsung Galaxy S II"

Don't stress out about the formatting of this, we'll cover that in detail.

The only two things that should look weird to you are searchTerm and search_submit because they are weird. searchTerm is the name attribute of this box here, and search_submit is the id of this button. We'll talk more about this later: I'm actually breaking some rules. But I want to get this working as quickly as possible.

Running Behat

Ready for me to blow your mind? Just by writing this one scenario we now have a test for our app. In the terminal run ./vendor/bin/behat and boom! It just read that scenario and actually went to our homepage, filled in the search box, pressed the button and verified that "Samsung Galaxy" was rendering on the next page. Why don't we see this happen? By default, it runs things using invisible curl request instead of opening up a real browser.

Testing JavaScript

The downside to this is that if you have JavaScript on your page that this scenario depends on, it isn't going to work since this isn't actually opening up a real browser. So, how can we run this in a real browser? There are actually a bunch of different ways. The easiest is by using Selenium.

Grab another library with composer require behat/mink-selenium2-driver. You'll also need to download the selenium server which is really easy, it's just a jar file. Click this link here under downloads to get the Selenium Standalone Server. I already have this, so I'm not actually going to download it.

To run things in Selenium, open a new tab in your terminal, and run the jar file that you just downloaded. For me that's

java -jar ~/Downloads/selenium-server-standalone-2.45.0.jar


Firefox 47.0.0 and lower is not supported at all since Selenium 3.0.0 - update Firefox to the latest version and install the new geckodriver for it in order to use the latest Selenium server.

This will load and run as a daemon, so it should just hang there.

Our library is done downloading and we just need to activate it in our behat.yml with the line:

7 lines behat.yml
... lines 4 - 5
selenium2: ~

This gives me the option to use goutte to run the test using curl requests or Selenium to have things run in a browser. By default, this will just select goutte. So how do we make it use Selenium? I'm so glad you asked!

Above the scenario that you want to run in Selenium add @javascript:

... lines 1 - 5
Scenario: Search for a word that exists
... lines 8 - 12

And that's it. Go back to the terminal and let's rerun this test. It actually opens the browser, it's quick but you can see it clicking around to complete the scenario. Cool!


FireFox is buggy with the new Selenium 3 server that's why it's preferable to use Google Chrome. You can explicitly specify the browser in the behat.yml config file:

# behat.yml
      browser_name: chrome

We write human readable instructions and they turn into functional tests, and this just barely scratches the surface of how this will change your development. Let's keep going and figure out what's really going on here.

Leave a comment!

  • 2018-09-17 Diego Aguiar

    Ohh, so that was the problem, I'm glad to hear that you could fix your problem :)

  • 2018-09-16 Leora Wenger

    I installed the last version of chromedriver - then it worked. (I also had to install homebrew and follow those instructions as well). Finally passed!

  • 2018-09-16 Leora Wenger

    No, I copied the search.feature straight from the text on the course page. When I specify Chrome as the browser in behat.yml, I get a slightly different error message:
    When I fill in "searchTerm" with "Samsung" # FeatureContext::fillField()
    unknown error: call function result missing 'value'
    (Session info: chrome=69.0.3497.92)
    (Driver info: chromedriver=2.31.488774 (7e15618d1bf16df8bf0ecf2914ed1964a387ba0b),platform=Mac OS X 10.13.6 x86_64) (WebDriver\Exception\UnknownError)

  • 2018-09-14 Diego Aguiar

    Hey Leora Wenger sorry for the late response. Hmm, so you are actually hitting your homepage, try to find any other element on that page, just to be sure that everything is working correctly.
    What I believe is that you don't have any form field named "searchTerm" (remember that IT is case sensitive)

  • 2018-09-13 Leora Wenger

    Wow, that was a long response (still get the error under) - there is more, but it won't let me post all, too long:

    │ http://localhost:8000/

    │ <html><head>
    │ <meta charset="UTF-8">
    │ <title>KnpUniversity: The Raptor Store!</title>

    │ <link rel="stylesheet" href="/bootstrap/css/bootstrap.min.css">
    │ <link rel="stylesheet" href="/css/main.css">
    │ <link rel="stylesheet" href="/css/font-awesome.min.css">
    │ </head>
    │ <body>

    │ <div class="container">
    │ <div class="header clearfix">
    │ <nav class="navigation-margin">
    │ <ul class="nav nav-pills pull-right">
    │ <li>
    │ </li>
    │ <li>Admin</li>
    │ <li>Login</li>
    │ <li>Reset DB</li>
    │ </ul>
    │ </nav>
    │ <h1>The Raptor Store</h1>
    │ </div>
    │ <hr>

    Fence security activated

    │ <div class="row">
    │ <div class="col-sm-12">

    │ <section>
    │ <h1 class="text-center">Welcome to the Raptor Store</h1>

    │ <div class="row">
    │ <div class="col-sm-8 col-sm-offset-2">
    │ <h2>
    │ Today's sweet products:
    │ </h2>
    │ <table class="table table-striped">
    │ <thead>
    │ <tr>
    │ <th>Name</th>
    │ <th>Price</th>
    │ </tr>
    │ </thead>
    │ <tbody>
    │ <tr>
    │ <td>Kindle Fire HD 7</td>
    │ <td>$199.99</td>
    │ </tr>
    │ <tr>
    │ <td>Samsung Galaxy S II</td>
    │ <td>$434.99</td>
    │ </tr>
    │ <tr>
    │ <td>Samsung 3D Slim LED</td>
    │ <td>$2,497.99</td>
    │ </tr>
    │ </tbody>
    │ </table>
    │ </div>
    │ </div>
    │ </section>
    │ </div>
    │ </div>
    │ </div>

  • 2018-09-13 Diego Aguiar

    Hmm I think it should just work. Add the step And print last response after step "Given I am on "/" "
    let's see what's returning

  • 2018-09-13 Leora Wenger

    (formatting got removed when I posted the behat.yml file)

  • 2018-09-13 Leora Wenger

    base_url: http://localhost:8000
    goutte: ~
    selenium2: ~
  • 2018-09-13 Diego Aguiar

    Interesting... so probably your configuration is not correct. Can you show me your behat.yml file please

  • 2018-09-13 Leora Wenger

    Diego, I have both Selenium server running as well as Chrome, and I still get that error message.

  • 2018-09-13 Diego Aguiar

    Hey Leora Wenger

    In order to use "@javascript tag" you need to start your selenium server first and probably a browser as well, it depends on your local environment.


  • 2018-09-13 Leora Wenger

    Hi, I am getting an error on the "searchTerm" section when using Selenium. I did not get this error when @javascript is not in the search.feature file:
    Feature: Search
    In order to find products dinosaurs love
    As a web user
    I need to be able to search for products

    Scenario: Searching for a product that exists # features/bootstrap/search.feature:7
    Given I am on "/" # FeatureContext::visit()
    When I fill in "searchTerm" with "Samsung" # FeatureContext::fillField()
    Form field with id|name|label|value|placeholder "searchTerm" not found. (Behat\Mink\Exception\ElementNotFoundException)
    And I press "search_submit" # FeatureContext::pressButton()
    Then I should see "Samsung Galaxy" # FeatureContext::assertPageContainsText()

    --- Failed scenarios:


    1 scenario (1 failed)
    4 steps (1 passed,

  • 2018-03-28 Victor Bocharsky

    Hey Mr. ß ,

    Have you installed that geckodriver as we mentioned in this chapter? Also, are you trying to use Firefox? Could you try to use Google Chrome instead? I really had a bad experience using Selenium with Firefox lately.


  • 2018-03-25 Mr. ß


    Whenever I tried to run behat, I get this error. My search.feature looks like:

    `Feature: Search
    In order to find products dinosaurs love
    As a website user
    I need to be able to search for products
    Scenario: Search for a word that exists
    Given I am on "/"
    When I fill in "searchTerm" with "Samsung"
    And I press "search_submit"
    Then I should see "Samsung Galaxy S II"`

    ```Could not open connection: Unable to create new service: GeckoDriverService
    Build info: version: '3.11.0', revision: 'e59cfb3', time: '2018-03-11T20:33:15.31Z'
    System info: host: 'Babaganas-MacBook-Pro.local', ip: 'fe80:0:0:0:1c14:2aa5:e04f:a9a7%en0', 'Mac OS X', os.arch: 'x86_64', os.version: '10.13.3', java.version: '10'
    Driver info: driver.version: unknown (Behat\Mink\Exception\DriverException)```

    Can you please help me?

  • 2017-12-18 Diego Aguiar

    Hey Daka
    When you create a step automatically via Behat console, it adds you a "pending" check line code, what it does is to throw a custom exception which you haven't added the import. You can just remove it, or add the import by yourself

    Have a nice day

  • 2017-12-18 Daka

    running behat
    it gives me error:
    Scenario: checking all urls to see if they are all have access denied # features/accessDenied.feature:6
    Given I am on "/" # FeatureContext::iAmOn()
    Fatal error: Class 'PendingException' not found (Behat\Testwork\Call\Exception\FatalThrowableError)
    When I fill in "searchTerm" with "Samsung" # FeatureContext::iFillInWith()
    And I press "search_submit" # FeatureContext::iPress()
    Then I should see "Samsung Galaxy S II"

    this is my composer
    "require": {
    "php": ">=5.5.9",
    "symfony/symfony": "3.1.*",
    "doctrine/orm": "^2.5",
    "doctrine/doctrine-bundle": "^1.6",
    "doctrine/doctrine-cache-bundle": "^1.2",
    "symfony/swiftmailer-bundle": "^2.3",
    "symfony/monolog-bundle": "^2.8",
    "symfony/polyfill-apcu": "^1.0",
    "sensio/distribution-bundle": "^5.0",
    "sensio/framework-extra-bundle": "^3.0.2",
    "incenteev/composer-parameter-handler": "^2.0",
    "knplabs/knp-markdown-bundle": "^1.4",
    "doctrine/doctrine-migrations-bundle": "^1.1",
    "ramsey/uuid": "^3.7",
    "behat/mink-extension": "^2.3",
    "behat/mink-goutte-driver": "^1.2"
    "require-dev": {
    "sensio/generator-bundle": "^3.0",
    "symfony/phpunit-bridge": "^3.0",
    "nelmio/alice": "^2.1",
    "doctrine/doctrine-fixtures-bundle": "^2.3"

  • 2017-11-10 Victor Bocharsky

    Great! Feel free to contact us again if you still have some troubles with it. We'd be glad to help you to fix it ;)


  • 2017-11-09 Simon Carr

    Thank you Victor, I will give that a go

  • 2017-11-09 Victor Bocharsky

    Hm, I was experienced a few weird things with Firefox. Could you try to use Google Chrome instead? I bet it'll fix your problem. IIRC, Firefox is just not ready to the latest Behat / Selenium server. The other things: your deps and version of selenium server - look good for me.


  • 2017-11-09 Simon Carr

    Browser if Firefox,
    Here is a snippet from my composer.json

    "behat/behat": "^3.4",
    "behat/mink-extension": "^2.2",
    "behat/mink-goutte-driver": "^1.2",
    "behat/mink-selenium2-driver": "^1.3",

    I am using selenium-server-standalone-3.7.1.jar

    Then I should see "Suppliers" comes from the video You can see it at 4:43


  • 2017-11-09 Victor Bocharsky

    Hey Simon,

    Your scenario looks fine, which browser you run this scenario in? Google Chrome or Firefox? What's your version of Behat and what's your version of Selenium server? I think you just have some problems with compatibility, probably simple upgrade of selenium server could fix the problem.

    Also, where's the "I should see..." step definition comes from? Is it from Behat core?


  • 2017-11-08 Simon Carr

    Using Windows 10 and Symfony 3.3. I have the following scenario

    Feature: Supplier
    In order to be able to work with suppliers
    As a web user
    I need to be able to see a list of suppliers

    Scenario: Listing all suppliers
    Given I am on "/suppliers"
    Then I should see "Suppliers"

    When I run Behat, The browser opens and I quickly see the page before it closes, then I get the following error

    Scenario: Listing all suppliers # features\suppliers.feature:6
    Given I am on "/suppliers" # FeatureContext::visit()
    Then I should see "Suppliers" # FeatureContext::assertPageContainsText()
    Element not found with xpath, //html

    --- Failed scenarios:


    1 scenario (1 failed)
    2 steps (1 passed, 1 failed)
    0m2.70s (11.65Mb)
  • 2017-08-21 Victor Bocharsky

    Hey Thierno,

    Hm, "getId() === getId()" is a bad thing to do. Do you implement \Serializable interface, i.e. do you have serialize()/unserialize() methods in your User entity or parent classes which this entity extends? Could you make sure you serialize/unserialize fields correctly, i.e. you have the same fields number and its order in both methods? Probably you could debug where exactly it fails in default Symfony\Component\Security\Core\User\UserChecker (if you do not override it)?


  • 2017-08-17 Thierno Diop

    Hi weaver i am using guard but when a user logged in he is automatically log out here is the message in the log : The security token was removed due to an AccountStatusException.
    But it works when i implement the Symfony\Component\Security\Core\User\EquatableInterface like this :
    public function isEqualTo(UserInterface $user)


    return $user->getId() === $this->getId();


    but i don't think this is normal.
    Help please.

  • 2017-07-23 weaverryan

    Yo Pawel!

    Hmm. It looks like an issue with Selenium: This happens from time-to-time: as browsers make updates, Selenium needs to be updated to work with those browser changes. So, unfortunately, you will see issues like this occasionally - they're often fixed in the next version of Selenium. I would try a different browser for now, to see if you have better luck.


  • 2017-07-21 Paweł

    I put `selenium-server-standalone-3.4.0.jar` and `geckodriver` in my root project dir. I got error: `Exception thrown
    org.openqa.selenium.UnsupportedCommandException: mouseMoveTo`.
    I am using:
    Geckodriver v0.18.0
    Firefox 54
    Linux Mint 18.2

  • 2017-07-03 Victor Bocharsky

    Hey Evgeniy,

    Hm, are we talking about "BDD, Behat, Mink and other Wonderful Things" course? Probably if you did not have SQLite extension - you would have a huge error about it. I think the same is for permissions problem, so that's weird. Are you sure you do not see any errors in your terminal after "php app/console doctrine:database:create" command execution? What is your output? You should see something like:

    > ~/Downloads/behat/finish: $ app/console doctrine:database:create
    > Created database ~/Downloads/behat/finish/app/app.db for connection named default.

    Is it the same for you? Could you paste it here?

    Anyway, I just double checked it: Downloaded the course code, went to the finish/ directory. installed Composer dependencies and run "php app/console doctrine:database:create" - and it works for me fine.


  • 2017-06-30 Евгений Явгель

    Thanks for answer. But after command: php app/console doctrine:database:create no misstake but DB does not creating (( And "app/app.db" database file doesn"t create .... Why?

  • 2017-06-30 Victor Bocharsky

    Hey Евгений,

    That's not a full Symfony Standard Edition, just some kind of micro app based on Symfony components. This project doesn't have any parameters.yml and parameters.yml.dist files. For simplicity, all the configuration happens in app/config.yml - you can see:

    driver: pdo_sqlite
    path: %kernel.root_dir%/app.db

    So as you can see we use SQLite DB for this course, and after you run that commands from README file you will have "app/app.db" database file. So try to run those commands and make sure the app.db file is created. Of course, feel free to change driver to "pdo_mysql" if you want to use MySQL instead, but then you also need to set up its credentials under the "doctrine.dbal" key in config.yml.


  • 2017-06-30 Евгений Явгель

    Hi! I'm having trouble trying to load up DB. In README file after step 2 (composer install) I try to load DB by running stack of command: php app/console doctrine:database:create
    php app/console doctrine:schema:update --force
    php app/console doctrine:fixtures:load But in app/config I have no parameters,yml or parameters.yml.dist .... how can DB loading in this case ? README file says after running stack of commands above I must receive `app/app.db` file. But I havn"t app.db file. I cant run php app/console doctrine:database:create command Can you help me or explain what i miss?

  • 2017-05-15 weaverryan

    You already answered this for yourself in another thread, but I want to answer it here in case for others :). This tutorial is currently about an old bundle - in version 2.8 Guard was accepted into core (yay!) and now works a bit differently. You can find a screencast about this in our Symfony security tutorial:


  • 2017-05-15 Sergio Valije Guiadanes

    Hi everyone!

    I'm having this problem Viral had before, but I'm with this fancy Symfony 3.2.8 and I tried to follow the steps.

    Here is the output I got when I try to run my application

    InvalidConfigurationException in ArrayNode.php line 317:
    Unrecognized option "knpu_guard" under "security.firewalls.main"

    I'm missing something ?

    Thanks in advance!

  • 2017-03-27 Victor Bocharsky

    Hey UnkRec,

    No, you don't have - Guard component installed out-of-the-box, so just you can start using it. This tutorial is still current, but in some places we have notes if something was changed/renamed - just skip installation section if you're on Symfony 2.8 or higher.


  • 2017-03-26 UnkRec

    Do we have to install Guard via composer if using the latest version of Symfony 3 (to date)?
    How much of this " KnpUGuard: Symfony Authentication with a Smile Tutorial" is current?

  • 2017-02-27 weaverryan

    That's a great idea - I've gotten this question several times! I'll add it to our idea list :). In short, one approach would be have 2 authenticators. When the first (e.g. something that checks username/password) is successful, instead of *actually* being successful, set something on the session, and then fail authentication (e.g. by returning false in getCredentials()). In onAuthenticationError, if that session value exists, instead of sending them back to the login page, redirect to some other URL (where the 2nd factor is checked). On that URL, add the form for the 2nd authentication. Have a 2nd authenticator handle the submit: it would check that the session value from the first is present (to make sure someone didn't skip to this step) and then process as normal. You might also need a listener that redirects to the 2nd factor page for for ALL other URLs once that session token is set (i.e. once the first factor has been successful).

    It's honestly not something I've ever tried. It's one of those problems that's not technically *that* hard to solve (after all, it's just 2 different forms), but I'm not convinced that the above method is all that smooth, or the smoothest possible.


  • 2017-02-27 AwesomeDeveloper

    Be nice to see an article on how to add two factor authentication using guard. I'm trying to play around with it but nothing concrete yet.

  • 2016-12-17 weaverryan

    Thanks for sharing the link! And yea, I know what you mean - Behat docs are a bit light on some setup details... which is a shame, because it's SO rewarding to work with afterwards :). Happy you got there!

  • 2016-12-17 James D

    FYI, I found this article on Gecko webdrivers super handy:

    Also also, thanks so much for this course. I've been meaning to get round to learning Behat properly for months and I've always had set up problems. This is the first place I've found that explains how to get started properly.

  • 2016-12-09 weaverryan

    Sweet! So happy that worked - and thank you for the follow-up! Awesome!

  • 2016-12-07 James D

    Bingo! Worked a treat, thanks Ryan. I downloaded the Mac archive from, unzipped it, put the executable in my project root (though I guess it could have gone anywhere, and might more sensibly be kept somewhere like /usr/local/share or something.

    As you described, I added the path to the executable to my path, and now I can run tests with Selenium.

    Thanks again for your help!

  • 2016-12-05 weaverryan

    Hey James!

    Yea, Selenium is temporarily in a weird place right now as they've recently released their 3.0 version of the server, which has some differences with how the old one works. As I understand it, you need to also download the gecko-driver in order to use Firefox ( or the Chrome driver to use Chrome ( I *think* that you just need to make sure these are in your path (i.e. that you can just say chromedriver from the command line) - I don't *think* that you actually need to run them manually. I'm doing a lot of "think" because, while I have the new Selenium 3 server running on my machine, I had the chrome-driver installed a long time ago, so I'm not 100% positive what I might have done with my setup way back then.

    Anyways, let me know if downloading gecko-driver helps. Otherwise, we'll find the solution. I think we may need a note on this tutorial about the new setup steps with Selenium.

    Cheers and apologies for the inconvenience with Selenium!

  • 2016-12-04 James D

    Hey - I'm having a little bit of trouble with the Selenium part of this tutorial. I can run the scenario without Selenium, but when I try to do it using the @javascript option, Selenium opens up a Firefox window then just hangs. After a while I get a message saying:

    Could not open connection: Unable to connect to host on port 7055 after 45000 ms.

    ...followed by a load of console output from Firefox that I don't really understand.

    Any suggestions for what to do next would be much appreciated.

  • 2016-09-29 Tom NotMyRealSurname

    Yes, that helped a lot and I have it up and running now.

  • 2016-09-28 Victor Bocharsky

    Hey Tom,

    Ah, yes, this course have not been completely released yet. Take a look at "knpuniversity/oauth2-client-bundle" bundle, it helps a lot with OAuth2. BTW, it has some examples how to integrate this bundle with Symfony Guard: . Let us know if you have any questions about integration.


  • 2016-09-27 Tom NotMyRealSurname

    Anyone figured out how to do Facebook / Google / OAuth with this bundle? It's my main reason to come here and then it says "coming soon" ... :-/

  • 2016-09-25 weaverryan

    Ah, great news!

  • 2016-09-23 Thierno Diop

    I notify the owner of the server about the problem and he fixed it buy setting varnish Thx a lot

  • 2016-09-23 weaverryan

    Yea, I agree that it sounds like a session-saving issue. But since you say that you *can* see session files created, and that they are created on each request, then it makes me wonder if Varnish is stripping the cookies so that each request (to Symfony) looks like a fresh request (i.e. one that has no cookie). I would remove Varnish, at least to test, and see if that fixes the problem.


  • 2016-09-22 Thierno Diop

    No i did that dump to verify if the session was working i asked to the owner of the server he tell me that he installed varnish and since i juste replaced a project who was on the server with mine i mean its the same domain i think that is the problem

  • 2016-09-22 Victor Bocharsky

    The PHPSESSID does not store in cookies for this domain. You can see it in Google Chrome Developer Tool. I think it's because you have a dump statement in DefaultController.php on line 17. Please, remove it and check again.

  • 2016-09-22 Thierno Diop

    My hostname is so i think thats not the problem

  • 2016-09-22 Victor Bocharsky

    One possible cause for this is having a host name without a domain part (.com, .org, etc.), e.g. http://example/ instead of

  • 2016-09-22 Thierno Diop

    Thx for your response
    Session are saved in the folder var/sessions but the problem is that for every request it create one file in the session folder

  • 2016-09-22 Victor Bocharsky

    Hey Thierno,

    You should configure session properly - most likely session can't be stored on your server. Where do you store session? If it stores in files - look at save_path option and ensure you setup permissions for it correctly on the server. Let me know if it helps.


  • 2016-09-21 Thierno Diop

    Hi Ryan i have a probleme with the guard authentication I use symfony 3.1 in my project the guard authentication work fine in my local machine but when i deploy to the server if the authentication succed i am redirecting to the home page but i loose the authentication and become anonymous again.
    I set a session variable to show it in another page but it turn that the variable was deleted .
    So i think that the session is deleted every request but i dont know why.
    Really need help Thx

  • 2016-07-25 Victor Bocharsky

    Hey ciudadano82 ,

    You don't have to install GuardBundle for Symfony 3.1 because Guard Component provides with Symfony out of the box since Symfony 2.8, so just start using it without installation! :)

    Check this blog post page for more information: .


  • 2016-07-21 ciudadano82

    Hi! I'm having trouble trying to download the guardBundle with composer, i've installed symfony 3.1.2 (currently the last version available), but i get the following error:
    Your requirements could not be resolved to an installable set of packages.

    Problem 1
    - Conclusion: remove symfony/symfony v3.1.2
    - Conclusion: don't install symfony/symfony v3.1.2
    - don't install symfony/security-bundle v2.8.8|don't install symfony/symfony v3.1.2
    - Installation request for symfony/symfony == -> satisfiable by symfony/symfony[v3.1.2].
    - Installation request for knpuniversity/guard-bundle ~0.1@dev -> satisfiable by knpuniversity/guard-bundle[0.2, 0.3, v0.1].

    Any help, please?

  • 2016-06-28 Viral Champanery

    yes, right .. that was the one of the concern about this. to update the version . i just tring to do the same as i got document in following link

    In above link it shows in symfony 2.3 so that i was trying to do that .... thats fine..thanks to supporting .... its very to chat with you.. .. keep in contact ...

  • 2016-06-28 Victor Bocharsky

    Hm, I think you need to update your Symfony application first, at least to the ^2.6 as we can see from dependencies, but it would be better upgrade to the 2.7 as this is a LTS (Long Term Support) version. Looks like this bundle can't be correctly installed on Symfony 2.3.

  • 2016-06-28 Viral Champanery

    sorry bro, i have tried in that also but it will give the same error ... may be the reason my symfony 2.3.* version .. but i am not sure about it

  • 2016-06-28 Victor Bocharsky

    That's because your symfony/security-bundle has unsatisfiable version. Could you try to update it to "symfony/security-bundle": "^2.6" in your composer.json file?

  • 2016-06-28 Viral Champanery

    When i put this " "require" : { "knpuniversity/guard-bundle": "0.1" " in my composer.jsno file and try to composer update following error shows :

    Your requirements could not be resolved to an installable set of packages.

    Problem 1

    - Installation request for knpuniversity/guard-bundle 0.1 -> satisfiable by knpuniversity/guard-bundle[v0.1].

    - Conclusion: remove symfony/symfony v2.3.23

    - knpuniversity/guard-bundle v0.1 requires symfony/security-bundle ~2.6 -> satisfiable by symfony/security-bundle[v2.6.0, v2.6.1, v2.6.10, v2.6.11, v2.6.12, v2.6.13, v2.6.2, v2.6.3, v2.6.4, v2.6.5, v2.6.6, v2.6.7, v2.6.8, v2.6.9, v2.7.0, v2.7.1, v2.7.10, v2.7.11, v2.7.12, v2.7.13, v2.7.14, v2.7.2, v2.7.3, v2.7.4, v2.7.5, v2.7.6, v2.7.7, v2.7.8, v2.7.9, v2.8.0, v2.8.1, v2.8.2, v2.8.3, v2.8.4, v2.8.5, v2.8.6, v2.8.7].

    - don't install symfony/security-bundle v2.6.0|don't install symfony/symfony v2.3.23

    - don't install symfony/security-bundle v2.6.1|don't install symfony/symfony v2.3.23

  • 2016-06-28 Victor Bocharsky

    Hm, if you already installed guard library - that's not so bad. What error do you have during the GuardBundle installation?

  • 2016-06-28 Viral Champanery

    Hi victor,

    Thanks for giving me valuable time ,
    I have the my code in 2.3.23 symfony version and it allows me to add only guard but not guardBundle .so can you help me out with this. that i can make user login, changes password. functionality useing guardBundle in current version .. Is it possible to have with Fos.use bundle as well .. both in a one system ....

  • 2016-06-28 Victor Bocharsky

    Hey, Viral!

    There's the KnpUGuardBundle which you need to install first, because out-of-the-box Guard component available since Symfony ^2.8. only. But keep in mind that some dependencies should be updated to "^2.6". Check composer.json file of KnpUGuardBundle bundle to get more information about versions of dependencies.


  • 2016-06-28 Viral Champanery

    Hi, i have my application in symfony 2.3 so can i integrate it with this . because when i put composer update i got error like this " Unrecognized options "knpu_guard" under "security.firewalls.main" " in my security.yml it is like " knpu_guard:
    - app.form_login_authenticator "

  • 2016-05-11 weaverryan

    I can't tell you that exactly, but I might be able to help. Support for Guard in Silex was just merged: Unfortunately, it was merged into Silex 1.0 only, and it hasn't been released yet, so you would need to use the unreleased Silex 2 to use it.

    If you're using Silex 1, you'll need to create a custom authentication provider ( - and basically try to "mimic" the above pull request. Once Silex 2 is released, it'll be very easy - but it's not *quite* there yet!


  • 2016-05-10 Russell Seymour

    Hello, this looks great and exactly what I am looking for. However I am using Silex, do you know when the chapter on using Guard Authentication in Silex will be written?

  • 2016-03-29 weaverryan

    Hi there!

    I think I understand :). Yes, you can use FosUserBundle and *not* have a UserBundle (only have an AppBundle). Anything that you might normally put into UserBundle, just put into AppBundle. If you need to override templates, you can do that by putting the templates in app/Resources/views...

    The *only* limitation is that - with just one AppBundle - you probably won't be able to use "bundle inheritance" to override things in FOSUserBundle: But, that's not necessary - you can override everything in other ways. The only thing you will not be able to override are the controllers from FOSUserBundle. But, that's *also* ok - you should not override its controllers, you should hook into its event system to customize behavior:

    Phew! I hope that helps!

  • 2016-03-28 elh

    hello ,
    Thank u for this tutoriel
    Can u tell me if its possible to use FosUserBundle without the UserBundle that 's meen having just nth AppBundle ?

  • 2016-03-13 Eduard Pleh

    Hey Ryan.

    Thank you for guard auth extension that you wrote!
    Symfony 2 auth system always was the 'pain' point for our team of developers.(I think not only for our team)
    Now it works like a charm. Thank you again.

  • 2016-02-15 ShaunDychko

    Setting up the DB after downloading the course code was quite tricky, solved by trial and error, and really needs to be documented. From within ../start/
    1) php app/console doctrine:database:create
    2) php app/console doctrine:schema:update --force
    3) php app/console doctrine:fixtures:load

    Hopefully Ryan can review the steps above and check whether that's the best approach.

    (I just finished the Drupal 8 series by the way, and totally loved it. I just had to say that).

  • 2016-02-15 Daniel

    Thanks it worked, I all set with symphony 3 as well. Cheers!

  • 2016-02-11 weaverryan

    Hey Daniel!

    I have not totally set it up yet on Symfony 3, but I know at least that behat/mink is not compatible with Symfony 3 yet. Well, actually, it IS compatible - on its master branch, but there has not (yet) been a release with these compatibility changes. So, at the very least, you'll need to require behat/mink at the version dev-master. For Behat, you will need version 3.1 their of *their* library, which is not released fully yet. Try using ^3.1@dev in composer.json - or dev-master, that should do it.

    Some bundles/libraries have been slow to tag releases of their Symfony-3 compatible versions. It's made using some libs with Symfony 3 a pain. It should get better :).


  • 2016-02-10 Daniel

    Hi Ryan! What about having this setup for BDD in symfony3? Have you tried it? I got a myriad of composer conflicts, too long to be put here

  • 2015-12-20 B Roeser

    Hey Ryan,

    My blog post is online. I hope its correct. *g*:

  • 2015-12-18 B Roeser

    Thank you very much! The information about the factory class is very helpful.

    When I'm done and it works I'll share my findings e.g. in a blog post. :)

  • 2015-12-18 weaverryan

    Hey there!

    Wow, I'm impressed by what you're doing :). To your question: the hardest part of getting this all setup will actually be just getting the security system bootstrapped correctly (which you already have code for - I can't say for sure if it's correct, but it certainly looks good). As you probably already know, Guard is just an authentication provider system, much like how "form_login" activates a listener+provider. Obviously, this is all pre-configured in the DI for you in the framework.

    Here's a class that might help: These "factory" classes are weird, but basically they're wiring up the DI container for the services necessary for Guard. You can translate that into the direct object equivalents.

    Also, providerKey == your firewall name - in the framework, that's the key in security.yml for your firewall (e.g. "main"). It's not important, except that if you have multiple firewalls, you can configure different classes for different firewalls based on this key. But to be honest, I'm not sure exactly where you actually setup this key in the first place. If I were you and got stuck on this, I'd grab the code from this repository (or build a simple Symfony SE project using Guard) and then look at the dumped container to see how the objects are wired together. And the UserChecker should be this: It's totally not important, and in theory, would be made optional.

    I hope that helps and good luck!

  • 2015-12-18 B Roeser

    Hey Ryan,

    Guard looks very interesting!
    I'm just getting started with Symfony and I'm interested in using the Symfony components (not a whole AppBundle) to refactor an existing system. I used this manual to do that:
    and I could already replace homespun solutions of routing, i18n, caching, ... with Symfony components that are working much better and are more felxible.

    My next logical step is to replace the existing authentication system (form based) with Guard. I already wrote the FormLoginAuthenticator and UserProvider, as you described in the chapter "How to Create a Login Form". I currently neither use the Symfony DI nor the Symfony YAML-configuration, because I wanted to keep the existing solutions in place. Is it even possible to use Guard without the Symfony DI component? Also, do you know if there's a manual somewhere on using Guard without the whole Symfony framework?

    I added some code to my "Framework"-class that looks basically like that:

    $firewallMap = new Http\FirewallMap('^/');
    $requestMatcher = new HttpFoundation\RequestMatcher();
    $this->tokenStorage = new \Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage();
    $firewallListeners = array();
    $guardHandler = new \Symfony\Component\Security\Guard\GuardAuthenticatorHandler($this->tokenStorage, $this->dispatcher);
    $guardAuthenticators = array(new FormLoginAuthenticator());
    $providers = array(new \Symfony\Component\Security\Guard\Provider\GuardAuthenticationProvider($guardAuthenticators, $userProvider, ??????????
    $firewallMap->add($requestMatcher, $firewallListeners);
    $this->firewall = new Http\Firewall($firewallMap, $dispatcher);
    $this->dispatcher->addListener(\Symfony\Component\HttpKernel\KernelEvents::REQUEST, array($this->firewall, 'onKernelRequest'));

    Now I am stumped. Am I on the right track so far?
    The Guard AuthenticationProvider requires a providerKey and an UserChecker, I don't quite get, what that means. Would you mind explaining?

  • 2015-12-15 tomhv

    Awesome, thanks! That makes a lot of sense.

  • 2015-12-15 weaverryan

    This is a *great* question... so I talked to some of the guys at KnpLabs about it. I'll make a few points:

    1) The first important thing is communication. If *you* know that you will ultimately need features and scenarios, then when planning with your client, you should sit down and communicate (ask questions, etc) in a way that will ultimately allow you to easily write those features/scenarios. Using BDD clarifies your planning process, and you can use that to help your client plan.

    2) Regardless of whether you ultimately write the features/scenario or your client does (see my next point), you should validate the features/scenarios with your client. That will get them invested in the Gherkin process and avoid those ugly miscommunications about features :).

    3) I don't think it will always work, but you may be able to get your client invested enough in Gherkin that *they* start to write the scenarios. During our discussion about this, we basically agreed that you will always need to "translate" their scenarios a little bit (Gherkin is natural language, but it still has structure). Really, even my point (1) above was about translating your conversation with them into written scenarios. There will always be a translation step, but the smaller you can make that translation, the less translation "cost" you will have (time to translate, mistakes in not translating what they mean perfectly, etc).

    Thanks to these guys for our conversation about your cool question: and


  • 2015-12-15 tomhv

    Where does Behat fit into the requirements-gathering process? Do you sit and write the features with the client?

  • 2015-12-14 weaverryan

    Hey Paul!

    Yea, it *is* now part of Symfony 2.8 and 3.0 :). So, the Guard library (and bundle) are being deprecated: you should switch to the core version of the feature once you upgrade to Symfony 2.8. We have some details here:

    Then, we'll update this tutorial soon to be for the core version of the library.


  • 2015-12-14 Paul Okeke

    Hi, Any word on this becoming a core part of Symfony??

  • 2015-11-13 AJ


  • 2015-11-13 weaverryan

    Got it fixed now thanks to your comment!

  • 2015-11-13 AJ

    This video is different from the script. Was that intentional?

  • 2015-10-28 weaverryan

    Yes, I wish I had time to fill this in, but not yet!

    But here's the tip: you need the knpuniversity/guard library (or Symfony 2.8, where it is in core) and then you need to re-recreate the GuardAuthenticationFactory ( in this format:

    Honestly, that may be really easy! ... or it may be tricky. I'll take a look at it soon, but it could be a few weeks - it's a busy time before Symfony3! If you have any luck - let me know!


  • 2015-10-27 Diego Agulló

    Really interested in that! Is there any resource for implementing Guard with Silex?

  • 2015-09-16 weaverryan

    Good tip! That's a classic thing to watch out for - it's not a problem unless you, for example, have an access_control that requires login on every URL (e.g. ^/). An alternative (but not better than yours) solution is to put an access_control allowing ^/login$ above the access_control that requires login for everything else - something like

    # only the first matching access_control entry is used on any request
    # allow anonymous access to /login and /login_check
    - { path: ^/login_check$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    # for all non /login or /login_check URLs, require ROLE_USER
    - { path: ^/, roles: ROLE_USER }


  • 2015-09-16 Mathew Peterson

    I was getting redirect loops but I was able to fix it by creating a separate firewall for ^/login$.

  • 2015-09-07 Neandher Carlos

    \o/ I'm glad to help you.

  • 2015-09-07 weaverryan

    You're awesome for prepping that! And yes, it was a bug in the code from the library (and your fix above is correct). I've fixed this and just tagged a new release, which you should be able to use immediately.


  • 2015-09-04 Neandher Carlos

    Take a look:

    For this works, i have to comment this lines in file GuardAuthenticationProvider.php:

    throw new \LogicException(sprintf(
    'The correct GuardAuthenticator could not be found for unique key "%s".
    The listener and provider should be passed the same list of authenticators.',
  • 2015-09-03 weaverryan


    Don't worry about your English, it seems very good to me, and it's certainly better than my Portuguese!

    Would it be possible to post some of your code to a repository online? You should NEVER see the error that you see - it should basically be impossible, no matter what your setup looks like. So, it makes me wonder if there is a bug in the core library itself. If you're able to post a small repository with enough code to see the error, that would be a HUGE help.


  • 2015-09-03 weaverryan

    Hey Mathew!

    It could be several weeks, so perhaps I can help here sooner :). What issues are you running into? For the most part, FOSUserBundle is nothing more than a User entity, a User provider, and a bunch of routes/controllers (for things like logging in, registering, etc). So, if you're using Guard to have some new authentication method, in theory, you'd simply create and save your User entity... and that should be it - FOSUserBundle shouldn't get much in the way. So, what are you seeing?


  • 2015-09-03 Mathew Peterson

    Do you know when the FOSUserBundle chapter will be released? I'm trying to integrate FOSUserBundle into an app that already has Guard configured but I am running into issues.

  • 2015-09-02 Neandher Carlos

    Hey again. I tried to implement this, but without success. In "Gestor" secured area is ok, but in "Admin" return a error.

    anonymous: ~
    pattern: ^/gestor
    - app.gestor_form_login_authenticator
    path: gestor_security_logout
    target: gestor_security_login

    anonymous: ~
    pattern: ^/admin
    - app.admin_form_login_authenticator
    path: admin_security_logout
    target: admin_security_login

    Message error:

    The correct GuardAuthenticator could not be found for unique key "admin_0". The listener and provider should be passed the same list of authenticators


  • 2015-08-27 Neandher Carlos

    Hey! Thanks for answering :)

    No no no! I have 2 firewalls and one UserInterface: AppBundle/Entity/User, where i have the login and password attributes and other things. In AdminUser Table and CustomerUser Table I have FirstName and LastName and other things, and do a join with the User Table to inherit their attributes. So when I go to log in "admin" or "customer" I have this in UserRepository (UserInterface):

    public function findAdminUserByEmail($emailCononical)
    return $this->createQueryBuilder('u')
    ->innerJoin('u.adminUser','g') // <= <= <=
    ->andWhere('u.emailCanonical = :emailCanonical')->setParameter('emailCanonical', $emailCononical)
    ->andWhere('u.roles like :role')->setParameter(':role', '%ROLE_ADMIN_USER%') // <= <= <=

    public function findCustomerUserByEmail($emailCononical)
    return $this->createQueryBuilder('u')
    ->innerJoin('u.customerUser','g') // <= <= <=
    ->andWhere('u.emailCanonical = :emailCanonical')->setParameter('emailCanonical', $emailCononical)
    ->andWhere('u.roles like :role')->setParameter(':role', '%ROLE_CUSTOMER_USER%') // <= <= <=

    In this way I have One (User) To One (AdminUser or CustomerUser), then AdminUser can not log in CustomerUser.

    PS: Sorry for my english, i am brazilian.

  • 2015-08-27 weaverryan


    I think this setup makes sense. By multiple authenticators, I'm technically talking about using 2 authenticators on the same firewall, but whether you should have 1 firewall or 2 firewalls depends on your setup. Often, even if you have multiple ways to authenticate, it's convenient to always have the *same* one User object, no matter how you login. In your case, if I login under the customer firewall, will the User object be CustomerUser? And then if I login via "admin", it will be AdminUser? In that case, you just need to be careful - if you have code (e.g. a base template) that is used by pages under both firewalls, then "app.user" could sometimes be a CustomerUser and sometimes be an AdminUser. That's that reason why I typically like to always have the same User object in all cases. But if you really have 2 separate sections of your site, having 2 firewalls and 2 different UserInterface objects makes more sense. If you go down this road, you'll need a user provider for each user type - because when the user is loaded from the session, the UserProvider is used to re-query for the user. User providers are still kind of a complicated part of all of this.

    Or maybe I've not understood your situation entirely. But anyways - it depends on your setup, but what you have hear largely makes sense.