I'm using Symfony 4.4 and have a weird problem with user authentication. Unfortunately, I myself cannot reproduce the problem, but I can see in the logs that it occurs with a small number of my users. The following error message occurs:
$user must be an instanceof UserInterface, an object implementing a __toString method, or a primitive string
Stacktrace:
{
"class": "InvalidArgumentException",
"message": "$user must be an instanceof UserInterface, an object implementing a __toString method, or a primitive string.",
"code": 0,
"file": "/var/www/vendor/symfony/security/Core/Authentication/Token/AbstractToken.php:95",
"trace": [
"/var/www/vendor/symfony/security/Http/Firewall/ContextListener.php:224",
"/var/www/vendor/symfony/security/Http/Firewall/ContextListener.php:140",
"/var/www/vendor/symfony/security/Http/Firewall/AbstractListener.php:27",
"/var/www/vendor/symfony/security/Http/Firewall.php:139",
"/var/www/vendor/symfony/security/Http/Firewall.php:129",
"/var/www/vendor/symfony/security/Http/Firewall.php:97",
"/var/www/vendor/symfony/event-dispatcher/EventDispatcher.php:304",
"/var/www/vendor/symfony/event-dispatcher/EventDispatcher.php:264",
"/var/www/vendor/symfony/event-dispatcher/EventDispatcher.php:239",
"/var/www/vendor/symfony/event-dispatcher/EventDispatcher.php:73",
"/var/www/vendor/symfony/http-kernel/HttpKernel.php:122",
"/var/www/vendor/symfony/http-kernel/HttpKernel.php:68",
"/var/www/vendor/symfony/http-kernel/Kernel.php:201",
"/var/www/public/index.php:34"
]
}
I suspect that the token may not be renewable, the message mostly appears in the internal area. Sometimes it also appeared when the website was first accessed, where the user was probably not yet logged in.
My firewalls look like this:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
anonymous: ~
form_login:
login_path: login
check_path: login_check
username_parameter: login[username]
password_parameter: login[password]
csrf_token_generator: security.csrf.token_manager
json_login:
check_path: json_login_check
provider: database
logout:
path: /logout
target: /
guard:
provider: open_id
authenticators:
- App\Path\To\OpenIdGuard
login_check is the default login action and json_login_check the login action via xhr. Additionally there are two user providers, the default one (database) and another one for open id (open_id).
The providers look like this:
providers:
database:
entity:
class: App\Entity\User
property: email
open_id:
id: App\Path\To\Provider
User entity (simplified):
class User implements \Serializable, UserInterface, EncoderAwareInterface
{
public function __toString(): string
{
return $this->getEmail();
}
public function __construct()
{
$this->salt = base_convert(sha1(uniqid(''.mt_rand(), true)), 16, 36);
$this->setEnabled(false);
$this->roles[] = 'ROLE_USER';
}
public function eraseCredentials(): void
{
}
public function serialize(): string
{
return serialize(array(
$this->id,
$this->email,
$this->password,
$this->salt,
));
}
public function unserialize($serialized): void
{
list(
$this->id,
$this->email,
$this->password,
$this->salt
) = unserialize($serialized);
}
}
Both providers (database and open_id) use the same User entity.
The problem occurs as I said only very rarely, in most cases, everything works fine.