diff --git a/cookbook/security/index.rst b/cookbook/security/index.rst
index c9a478c927a..3efdd455016 100644
--- a/cookbook/security/index.rst
+++ b/cookbook/security/index.rst
@@ -23,6 +23,7 @@ Authentication (Identifying/Logging in the User)
multiple_user_providers
firewall_restriction
host_restriction
+ user_checkers
Authorization (Denying Access)
------------------------------
diff --git a/cookbook/security/user_checkers.rst b/cookbook/security/user_checkers.rst
new file mode 100644
index 00000000000..83ef18e63c3
--- /dev/null
+++ b/cookbook/security/user_checkers.rst
@@ -0,0 +1,215 @@
+.. index::
+ single: Security; Creating and Enabling Custom User Checkers
+
+How to Create and Enable Custom User Checkers
+=============================================
+
+During the authentication of a user, additional checks might be required to verify
+if the identified user is allowed to log in. By defining a custom user checker, you
+can define per firewall which checker should be used.
+
+.. versionadded:: 2.8
+ Defining a custom user checker was introduced in Symfony 2.8.
+
+
+Creating a Custom User Checker
+------------------------------
+
+User checkers are defined in PHP classes that must implement the
+:class:`UserCheckerInterface Symfony\\Component\\Security\\Core\\UserCheckerInterface`.
+This interface defines two methods called ``checkPreAuth()`` and ``checkPostAuth()``
+to perform checks before and after user authentication. If one or more
+conditions are not met, an exception should be thrown which extends the
+:class:`AccountStatusException Symfony\\Component\\Security\\Core\\Exception\\AccountStatusException`
+
+.. code-block:: php
+
+ namespace App\Security;
+
+ use Symfony\Component\Security\Core\User\UserCheckInterface;
+
+ class UserChecker implements UserCheckerInterface
+ {
+ public function checkPreAuth(UserInterface $user)
+ {
+ if (!$user instanceof AppUser) {
+ return;
+ }
+
+ // user is deleted, show a generic Account Not Found message.
+ if ($user->isDeleted()) {
+ throw new AccountDeletedException('...');
+ }
+ }
+
+ public function checkPostAuth(UserInterface $user)
+ {
+ if (!$user instanceof AppUser) {
+ return;
+ }
+
+ // user account is expired, the user may be notified
+ if ($user->isExpired()) {
+ throw new AccountExpiredException('...');
+ }
+ }
+ }
+
+Enabling the Custom User Checker
+--------------------------------
+
+All that's left to be done is creating a service definition and configuring
+this in the firewall configuration. Configuring the service is done like any
+other service:
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # app/config/services.yml
+ services:
+ app.user_checker:
+ class: App\Security\UserChecker
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+ .. code-block:: php
+
+ // app/config/services.php
+ use Symfony\Component\DependencyInjection\Definition;
+
+ $userChecker = new Definition('App\Security\UserChecker');
+ $container->setDefinition('app.user_checker', $userChecker);
+
+All that's left to do is add the checker to the desired firewall where the value
+is the service id of your user checker:
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # app/config/security.yml
+
+ # ...
+ security:
+ firewalls:
+ secured_area:
+ pattern: ^/
+ user_checker: app.user_checker
+ # ...
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+ app.user_checker
+
+
+
+
+
+ .. code-block:: php
+
+ // app/config/security.php
+
+ // ...
+ $container->loadFromExtension('security', array(
+ 'firewalls' => array(
+ 'secured_area' => array(
+ 'pattern' => '^/',
+ 'user_checker' => 'app.user_checker',
+ // ...
+ ),
+ ),
+ ));
+
+
+Additional Configurations
+-------------------------
+
+It's possible to have a different user checker per firewall.
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # app/config/security.yml
+
+ # ...
+ security:
+ firewalls:
+ admin:
+ pattern: ^/admin
+ user_checker: app.admin_user_checker
+ # ...
+ secured_area:
+ pattern: ^/
+ user_checker: app.user_checker
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+ app.admin_user_checker
+
+
+
+ app.user_checker
+
+
+
+
+
+ .. code-block:: php
+
+ // app/config/security.php
+
+ // ...
+ $container->loadFromExtension('security', array(
+ 'firewalls' => array(
+ 'admin' => array(
+ 'pattern' => '^/admin',
+ 'user_checkers' => 'app.admin_user_checker'
+ // ...
+ ),
+ 'secured_area' => array(
+ 'pattern' => '^/',
+ 'user_checker' => 'app.user_checker',
+ // ...
+ ),
+ ),
+ ));
+
+.. note::
+
+ Internally the user checkers are aliased per firewall. For `secured_area` the alias
+ `security.user_checker.secured_area` would point to `app.user_checker`.