title: Symfony: A Token was not found in the SecurityContext for route behind firewall
body: <p>In my Symfony2 application, I built an exception listener which lets me know about unhandled errors.</p>
  
  <p>I receive messages about the following error when bots are visiting my page, which is behind a firewall :</p>
  
  <pre><code>A Token was not found in the SecurityContext.
  </code></pre>
  
  <p>I also retrieve the following data:</p>
  
  <pre><code>User agent  Mozilla/5.0 (compatible; AhrefsBot/5.0; +http://ahrefs.com/robot/)
  Trace as string #0 /home/foodmeup.net/production/releases/20150527141710/app/cache/prod/classes.php(2951): Symfony\Component\Security\Http\Firewall\AccessListener-&gt;handle(Object(Symfony\Component\HttpKernel\Event\GetResponseEvent))
  #1 [internal function]: Symfony\Component\Security\Http\Firewall-&gt;onKernelRequest(Object(Symfony\Component\HttpKernel\Event\GetResponseEvent), 'kernel.request', Object(Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher))
  #2 /home/foodmeup.net/production/releases/20150527141710/app/cache/prod/classes.php(2205): call_user_func(Array, Object(Symfony\Component\HttpKernel\Event\GetResponseEvent), 'kernel.request', Object(Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher))
  #3 /home/foodmeup.net/production/releases/20150527141710/app/cache/prod/classes.php(2138): Symfony\Component\EventDispatcher\EventDispatcher-&gt;doDispatch(Array, 'kernel.request', Object(Symfony\Component\HttpKernel\Event\GetResponseEvent))
  #4 /home/foodmeup.net/production/releases/20150527141710/app/cache/prod/classes.php(2299): Symfony\Component\EventDispatcher\EventDispatcher-&gt;dispatch('kernel.request', Object(Symfony\Component\HttpKernel\Event\GetResponseEvent))
  #5 /home/foodmeup.net/production/releases/20150527141710/app/bootstrap.php.cache(3017): Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher-&gt;dispatch('kernel.request', Object(Symfony\Component\HttpKernel\Event\GetResponseEvent))
  #6 /home/foodmeup.net/production/releases/20150527141710/app/bootstrap.php.cache(2990): Symfony\Component\HttpKernel\HttpKernel-&gt;handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1)
  #7 /home/foodmeup.net/production/releases/20150527141710/app/bootstrap.php.cache(3139): Symfony\Component\HttpKernel\HttpKernel-&gt;handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
  #8 /home/foodmeup.net/production/releases/20150527141710/app/bootstrap.php.cache(2383): Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel-&gt;handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
  #9 /home/foodmeup.net/production/releases/20150527141710/web/app.php(28): Symfony\Component\HttpKernel\Kernel-&gt;handle(Object(Symfony\Component\HttpFoundation\Request))
  #10 {main}
  </code></pre>
  
  <p>This happens on about all my website pages since my last update but I can't figure out what the issue is.
  If I visit the page myself, there is no problem, no exception is raised.</p>
  
  <p>My understanding of the firewall I set up was that in case somebody tries to access a protected resource, he is redirected to the login page without any error being thrown. Here, I fear that some users may land on an error page instead of being redirected to the login page. And when I want to replicate the error by visiting the referer from when the error is thrown, I am correctly redirected so I don't understand what are the cases when the error is thrown versus the user is redirected.</p>
  
  <p>EDIT :</p>
  
  <p>My exception listener service :</p>
  
  <pre><code>exception_listener:
      class: %exception_listener.class%
      arguments: [@router, @session, @security.token_storage, @email_manager, @doctrine, "@=service('kernel').getEnvironment()", @security.authorization_checker]
      tags:
          - { name: kernel.event_listener, event: kernel.exception, method: onKernelException, priority: 250 }
  </code></pre>
  
  <p>My exception listener code:</p>
  
  <pre><code>&lt;?php
  
  namespace AppBundle\EventListener;
  
  use AppBundle\Application\Core\EmailManager;
  use AppBundle\Application\Core\JournalManager;
  use AppBundle\Entity\User\User;
  use AppBundle\Security\Voter\SubscriptionVoter;
  use Doctrine\Bundle\DoctrineBundle\Registry;
  use Symfony\Bundle\FrameworkBundle\Routing\Router;
  use Symfony\Component\HttpFoundation\RedirectResponse;
  use Symfony\Component\HttpFoundation\Request;
  use Symfony\Component\HttpFoundation\Session\Session;
  use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
  use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
  use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
  
  
  class ExceptionListener
  {
      /**
       * @var Router
       */
      private $router;
  
      /**
       * @var Session
       */
      private $session;
  
      /**
       * @var TokenStorage
       */
      private $tokenStorage;
  
      /**
       * @var EmailManager
       */
      private $emailManager;
  
      /**
       * @var null
       */
      private $environment;
  
      /**
       * @var AuthorizationChecker
       */
      private $authorizationChecker;
      /**
       * @var Registry
       */
      private $doctrine;
  
      public function __construct(Router $router, Session $session, TokenStorage $tokenStorage, EmailManager $emailManager, Registry $doctrine ,$environment=null, AuthorizationChecker $authorizationChecker)
      {
          $this-&gt;router = $router;
          $this-&gt;session = $session;
          $this-&gt;tokenStorage = $tokenStorage;
          $this-&gt;emailManager = $emailManager;
          $this-&gt;environment = $environment;
          $this-&gt;authorizationChecker = $authorizationChecker;
          $this-&gt;doctrine = $doctrine;
      }
  
      public function onKernelException(GetResponseForExceptionEvent $event)
      {
          try {
              /** @var $exception */
              $exception = $event-&gt;getException();
              $request = $event-&gt;getRequest();
              $referer = $request-&gt;headers-&gt;get('referer');
  
              $manager = $this-&gt;doctrine-&gt;getManager('logging');
              $journalManager = new JournalManager($manager);
  
              if($exception-&gt;getCode() == 403)
              {
                  if ($this-&gt;authorizationChecker-&gt;isGranted(SubscriptionVoter::HAS_SUBSCRIPTION) &amp;&amp; !$this-&gt;authorizationChecker-&gt;isGranted(SubscriptionVoter::SUBSCRIPTION_VALID))
                  {
                      $this-&gt;session-&gt;getFlashBag()-&gt;add('warning',"La page précédente n'est pas accessible avec ce portfolio car le paiement n'est pas à jour. Vous devez actualiser votre paiement.");
                      $response = new RedirectResponse($this-&gt;router-&gt;generate('renew_subscription'));
                  }
                  else
                  {
                      $this-&gt;session-&gt;getFlashBag()-&gt;add('warning',"La page précédente n'est pas accessible avec vos droits d'accès et vous avez été redirigé vers l'accueil du site.");
                      $response = new RedirectResponse($this-&gt;router-&gt;generate('home'));
                  }
  
                  $event-&gt;setResponse($response);
              }
              elseif ($exception-&gt;getMessage() == "Couldn't connect to host, Elasticsearch down?" || $exception-&gt;getCode() == 52)
              {
                  $this-&gt;session-&gt;getFlashBag()-&gt;add('warning', "La service de recherche du site a arrêté de fonctionner. Renouvellez votre dernière action si celle si n'a pas été suivie d'effet d'ici 2 minutes.");
                  $event-&gt;setResponse(new RedirectResponse($request-&gt;headers-&gt;get('referer') ?: $this-&gt;router-&gt;generate('home')));
              }
              elseif (
                  !($exception-&gt;getCode() == 404 &amp;&amp; !$referer) &amp;&amp;
                  !($this-&gt;contains($exception-&gt;getMessage(), array('object not found', 'A Token was not found in the SecurityContext', 'No route found for')) &amp;&amp; !strpos($referer, 'foodmeup')) &amp;&amp;
                  !in_array($this-&gt;environment, array('dev', 'test')) &amp;&amp;
                  !$journalManager-&gt;errorExists($exception, $request-&gt;getUri(), 1)
              )
              {
                  $user = is_object($this-&gt;tokenStorage-&gt;getToken()) ? $this-&gt;tokenStorage-&gt;getToken()-&gt;getUser() : null;
                  $user = $user instanceOf User ? $user : null;
                  $code = $exception-&gt;getCode();
  
                  $this-&gt;emailManager-&gt;sendEmail(
                      'error@foodmeup.net',
                      'foodmeup@foodmeup.net',
                      ':Core/Email:error.html.twig',
                      "Une erreur $code s'est produite sur le site",
                      array(
                          'date' =&gt; new \DateTime(),
                          'user' =&gt; $user,
                          'exception' =&gt; $exception,
                          'referer' =&gt; $request-&gt;headers-&gt;get('referer'),
                          'current' =&gt; $request-&gt;getUri(),
                          'user_agent' =&gt; $_SERVER['HTTP_USER_AGENT']
                      )
                  );
  
                  $journalManager-&gt;addErrorLog($exception, $request-&gt;getUri());
              }
          } catch (\Exception $e)
          {
          }
  
      }
  
      private function contains($str, array $arr)
      {
          foreach($arr as $a) {
              if (stripos($str,$a) !== false) return true;
          }
          return false;
      }
  }
  </code></pre>
  
  <p>My firewalls:</p>
  
  <pre><code>firewalls:
      dev:
          pattern:  ^/(_(profiler|wdt)|css|images|js)/
          security: false
      guest:
          pattern:        /(public/|$|genemu-captcha-refresh|media/cache/)
          anonymous:      true
          context:        main_auth
      main:
          pattern:        ^/
          anonymous:      false
          provider:       main
          context:        main_auth
          switch_user: { role: ROLE_ADMIN, parameter: _switch_user_parameter }
          form_login:
              login_path: fos_user_security_login
              check_path: fos_user_security_check
              success_handler: authentication_site_handler
          logout:
              path:       fos_user_security_logout
              target:     /
          remember_me:
              key:      "%secret%"
              lifetime: 86400 #en secondes
              path:     /
              domain:   ~ # Prend la valeur par défaut du domaine courant depuis $_SERVER
          oauth:
              remember_me: true
              resource_owners:
                  facebook:           "/loginhwi/check-facebook"
                  github:             "/loginhwi/check-github"
                  google:             "/loginhwi/check-google"
                  twitter:            "/loginhwi/check-twitter"
                  linkedin:           "/loginhwi/check-linkedin"
                  flickr:             "/loginhwi/check-flickr"
              login_path:        fos_user_security_login
              check_path:        fos_user_security_check
              failure_path:      fos_user_security_login
              success_handler:  authentication_site_handler
              oauth_user_provider:
                  service: fosubuser.provider
  </code></pre>
  
  <p>Precision : </p>
  
  <ul>
  <li>The emailManager just sends an email with from the given parameters.
  it works fine</li>
  <li>The journalManager just logs the error and helps me
  filter out errors already logged</li>
  </ul>