'Symfony 4, Login, how debug the error 'Invalid credentials'?

From symfony 4, I would like create a simple authentication form. I created a User class (the identifier is the email field, not the 'Username', I created a class controller and configured the security.yml file.

I created some users with this static method : (for tests, password by default is 'test')

class User implements \Serializable, UserInterface
{
// ...
  public static function new_alea($email, $isActive = false, $password="test"){
    $instance = new self();
    $instance->isActive = $isActive;
    $instance->email = $email;

    $brypt = new BCryptPasswordEncoder(4);
    $instance->password = $brypt->encodePassword($password, null);

    return $instance;
  }
// ...
}

Its work, there are some user in my database with encrypted passwords.

But when I go to the form page and try to login (fill email/password fields and click on the submit button), I get the error "Invalid credentials."

enter image description here

What this error means ? How/where do I debug my code for find why this error occurs ?

Below, mains part of my code, maybe you'll see an error I didn't see :

the security.yaml file :

security:
    encoders:
        App\Entity\User:
            algorithm: bcrypt
    providers:
        my_db_provider:
            entity:
                class: App\Entity\User
                property: email
    firewalls:
        main:
            provider: my_db_provider
            anonymous: ~
            form_login:
                login_path: login
                check_path: login
    role_hierarchy:
        # ...

the User Entity Class :

class User implements \Serializable, UserInterface
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=64)
     */
    private $password;

    /**
     * @ORM\Column(type="string", length=255, unique=true)
     */
    private $email;

    /**
     * @ORM\Column(name="is_active", type="boolean")
     */
    private $isActive;

    private $plainPassword;

    public static function new_alea($email, $isActive = false, $password="coucou"){
        $instance = new self();
        $instance->isActive = $isActive;
        $instance->email = $email;

        $brypt = new BCryptPasswordEncoder(4);
        $instance->password = $brypt->encodePassword($password, null);

        return $instance;
    }

    public function eraseCredentials() {
        $this->plainPassword = null;
    }

    public function serialize() {
        return serialize(array(
            $this->id,
            $this->email,
            $this->password,
        ));
    }

    public function unserialize($serialized) {
        list (
            $this->id,
            $this->email,
            $this->password,
            ) = unserialize($serialized);
    }

    public function getRoles() {
        return array('ROLE_ADMIN');
    }

    public function getPassword() {
        return $this->password;
    }

    public function setPassword($password) {
        $this->password = $password;
    }

    public function getUsername() {
        return $this->email;
    }

    public function setUsername($email) {
        $this->email = $email;
    }

    public function getPlainPassword() {
        return $this->plainPassword;
    }

    public function setPlainPassword($plainPassword): void {
        $this->plainPassword = $plainPassword;
    }

    // and others getters/setters

the login Controller :

class LoginController extends Controller
{
    /**
     * @Route("/login", name="login")
     */
    public function login(Request $request, AuthenticationUtils $authUtils)
    {
        // get the login error if there is one
        $error = $authUtils->getLastAuthenticationError();

        // last username entered by the user
        $email = $authUtils->getLastUsername();

        return $this->render('frontend/log/login.html.twig', array(
            'email' => $email,
            'error' => $error,
        ));
    }
}

And the template login.html.twig file :

{% extends 'base.html.twig' %}

{% block body %}

    {% if error %}
        <div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>
    {% endif %}

    <form action="{{ path('login') }}" method="post">
        <label for="email">Email:</label>
        <input type="text" id="email" name="_email" value="{{ email }}" />

        <label for="password">Password:</label>
        <input type="password" id="password" name="_password" />

        {#
            If you want to control the URL the user
            is redirected to on success (more details below)
            <input type="hidden" name="_target_path" value="/account" />
        #}

        <button type="submit">login</button>
    </form>

{% endblock body %}


Solution 1:[1]

Hi i get the same problem today, for me it was i put a restriction of the number of caracter in my string password. So the password was wrong because the encode took too many caracter. So i delete the limit of caracter and it works.

Solution 2:[2]

just output {{ error }} below the "frontend" error message to get the full stacktrace etc...

Solution 3:[3]

In your login template, add a {{ dump(error) }}. It includes the real error message (which will often suffice), and the whole stack trace if needed. And is more nicely formatted than just {{ error }} :

{% if error %}
    {{  dump(error) }}
    <div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}

Solution 4:[4]

I meet a similar problem, I solved by changing my passwords from plain text into encoded version.

# I create users by fixtures
$user->setEmail('admin@admin');
$user->setPassword('admin'); // Wrong

$user->setPassword($this->passwordEncoder->encodePassword(
    $user,
    'admin'
)); // Correct

Official Ref: https://symfony.com/doc/master/bundles/DoctrineFixturesBundle/index.html#accessing-services-from-the-fixtures

Solution 5:[5]

Use two router paths with the same function name and different label name so that it will moves to your login path when username and password is correct. It will moves to another path when you have invalid password or username.

EXAMPLE:

index:
 path: /
 controller: App\Controller\DefaultController::login

login:
  path: /login
  controller: App\Controller\DefaultController::login

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Sam
Solution 2 VVN
Solution 3 Pierre-Olivier Vares
Solution 4 jeffsama
Solution 5 emix