Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Security] Update custom authenticator docs to include identifier normalization #20636

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: 7.3
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 95 additions & 3 deletions security/custom_authenticator.rst
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,20 @@ requires a user and some sort of "credentials" (e.g. a password).
Use the
:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\UserBadge`
to attach the user to the passport. The ``UserBadge`` requires a user
identifier (e.g. the username or email), which is used to load the user
using :ref:`the user provider <security-user-providers>`::
identifier (e.g. the username or email)::

use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;

// ...
$passport = new Passport(new UserBadge($email), $credentials);
$passport = new Passport(new UserBadge($userIdentifier), $credentials);

User Identifier
~~~~~~~~~~~~~~~

The user identifier is a unique string that identifies the user. It is used
to load the user using :ref:`the user provider <security-user-providers>`.
This identifier is often something like the user's email address or username,
but it could be any unique value associated with the user.

.. note::

Expand Down Expand Up @@ -255,6 +262,91 @@ using :ref:`the user provider <security-user-providers>`::
}
}

It is a good practice to normalize the user identifier before using it.
For example, this ensures that variations such as "john.doe", "John.Doe",
or "JOHN.DOE" refer to the same user.
Normalization can include converting the identifier to lowercase
and trimming unnecessary spaces.
You can optionally pass a user identifier normalizer as third argument to the
``UserBadge``. This callable receives the ``$userIdentifier``
and must return a normalized user identifier as a string.

.. versionadded:: 7.3
Comment on lines +270 to +274

This comment was marked as outdated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many thanks.
I will take time to update this section.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be fixed with the last commit


The support of the user identifier normalizer was introduced in Symfony 7.3.

For instance, the example below uses a normalizer that converts usernames to a normalized, ASCII-only, lowercase format,
suitable for consistent comparison and storage.

// src/Security/NormalizedUserBadge.php
namespace App\Security;

use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\String\UnicodeString;
use function Symfony\Component\String\u;

final class NormalizedUserBadge extends UserBadge
{
public function __construct(string $identifier)
{
$callback = static fn (string $identifier) => u($identifier)->normalize(UnicodeString::NFKC)->ascii()->lower()->toString();

parent::__construct($identifier, null, $callback);
}
}

// src/Security/PasswordAuthenticator.php
namespace App\Security;

final class PasswordAuthenticator extends AbstractLoginFormAuthenticator
{
// Simplified for brievety
public function authenticate(Request $request): Passport
{
$username = (string) $request->request->get('username', '');
$password = (string) $request->request->get('password', '');

$request->getSession()
->set(SecurityRequestAttributes::LAST_USERNAME, $username);

return new Passport(
new NormalizedUserBadge($username),
new PasswordCredentials($password),
[
//All other useful badges
]
);
}
}

.. note::
Comment on lines +278 to +322
Copy link
Contributor

@alamirault alamirault May 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Php code was not rendered. I added :: and .. code-block:: php (Not 100% sure it's the best way)
  • I replace (string) $request->request->get() by $request->request->getString
Suggested change
For instance, the example below uses a normalizer that converts usernames to a normalized, ASCII-only, lowercase format,
suitable for consistent comparison and storage.
// src/Security/NormalizedUserBadge.php
namespace App\Security;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\String\UnicodeString;
use function Symfony\Component\String\u;
final class NormalizedUserBadge extends UserBadge
{
public function __construct(string $identifier)
{
$callback = static fn (string $identifier) => u($identifier)->normalize(UnicodeString::NFKC)->ascii()->lower()->toString();
parent::__construct($identifier, null, $callback);
}
}
// src/Security/PasswordAuthenticator.php
namespace App\Security;
final class PasswordAuthenticator extends AbstractLoginFormAuthenticator
{
// Simplified for brievety
public function authenticate(Request $request): Passport
{
$username = (string) $request->request->get('username', '');
$password = (string) $request->request->get('password', '');
$request->getSession()
->set(SecurityRequestAttributes::LAST_USERNAME, $username);
return new Passport(
new NormalizedUserBadge($username),
new PasswordCredentials($password),
[
//All other useful badges
]
);
}
}
.. note::
For instance, the example below uses a normalizer that converts usernames to a normalized, ASCII-only, lowercase format,
suitable for consistent comparison and storage::
// src/Security/NormalizedUserBadge.php
namespace App\Security;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\String\UnicodeString;
use function Symfony\Component\String\u;
final class NormalizedUserBadge extends UserBadge
{
public function __construct(string $identifier)
{
$callback = static fn (string $identifier) => u($identifier)->normalize(UnicodeString::NFKC)->ascii()->lower()->toString();
parent::__construct($identifier, null, $callback);
}
}
.. code-block:: php
// src/Security/PasswordAuthenticator.php
namespace App\Security;
final class PasswordAuthenticator extends AbstractLoginFormAuthenticator
{
// Simplified for brievety
public function authenticate(Request $request): Passport
{
$username = $request->request->getString('username');
$password = $request->request->getString('password');
$request->getSession()
->set(SecurityRequestAttributes::LAST_USERNAME, $username);
return new Passport(
new NormalizedUserBadge($username),
new PasswordCredentials($password),
[
//All other useful badges
]
);
}
}
.. note::


For example, Google treats the following email addresses as equivalent:
``[email protected]``, ``[email protected]``, and ``[email protected]``.
This is because Google applies normalization rules that remove dots
and convert the address to lowercase (though behavior varies across services).

.. note::

In enterprise environments, a user may authenticate using different formats
of their identifier, such as:

- ``[email protected]``
- ``acme.com\jdoe``
- ``https://acme.com/+jdoe``
- ``acct:[email protected]``

Applying normalization (e.g., trimming, lowercasing, or format unification)
helps ensure consistent identity recognition across systems and prevents
duplicates caused by format variations.

User Credential
~~~~~~~~~~~~~~~

The user credential is used to authenticate the user i.e. to verify
the validity of the provided information (such as a password, an API token,
or other custom credentials).

The following credential classes are supported by default:

:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Credentials\\PasswordCredentials`
Expand Down