UserChecker Symfony.6.0.15
Tags: php, webdev, tutorial
Published: 2022-11-27 17:14:44

sometimes we need authenticate a user on symfony with other field or property after the password verification, for example, a field or column with name verificated or expired ( in case that the column is a DateTime ).

we can use The Security Events and the flow is how follow:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mx391m73pqctsgfm8n1b.png)

We have 5 types of Events that are triggered when the user put the password in the input field and push the submit button. The events are:

 - CheckPassportEvent
 - AuthenticationTokenCreatedEvent
 - AuthenticationSuccessEvent
 - LoginSuccessEvent
 - LoginFailureEvent
 
The first event, **CheckPassportEvent**, allow see the information of User Object before the auth, and we can, in this case, throw an exception. 

Even better, **Symfony** have a cool tool called , UserChecker, that implement the **UserCheckerInterface** interface and you can access to the User Object before the **auth**.

For example:

```php
namespace App\Security;

use App\Entity\User as AppUser;
use Symfony\Component\Security\Core\Exception\AccountExpiredException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAccountStatusException;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
use Symfony\Component\Security\Core\User\UserInterface;

class UserChecker implements UserCheckerInterface
{
    public function checkPreAuth(UserInterface $user): void
    {
        if (!$user instanceof AppUser) {
            return;
        }

        if ($user->isDeleted()) {
            // the message passed to this exception is meant to be displayed to the user
            throw new CustomUserMessageAccountStatusException('Your user account no longer exists.');
        }
    }

    public function checkPostAuth(UserInterface $user): void
    {
        if (!$user instanceof AppUser) {
            return;
        }

        // user account is expired, the user may be notified
        if ($user->isExpired()) {
            throw new AccountExpiredException('...');
        }
    }
}
```
The interface have two methods, **checkPreAuth** and **checkPostAuth**, and allow catch, the information of User Entity before the access token is created. A good place for put our conditions.

In this example, we can throw an exception, if the user is deleted or the user is not verified yet ( when we send a email to user for activate an user's account ) :

```php
 if ($user->isDeleted()) {
            // the message passed to this exception is meant to be displayed to the user
            throw new CustomUserMessageAccountStatusException('Your user account no longer exists.');
    }
    
```
and show the exception on a Twig template:

```twig
{% if error %}
<div class="alert alert-danger">
   {{ error.messageKey|trans(error.messageData, 'security') }}
</div>
{% endif %}
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a6i64hkhkons916onimr.png)

[@see SecurityEvents](https://symfony.com/doc/current/security.html#security-events)

[@see How to Create and Enable Custom User Checkers](https://symfony.com/doc/current/security/user_checkers.html)

[Tutorial](https://youtu.be/erIhuDrSnFA)