@@ -209,13 +209,20 @@ requires a user and some sort of "credentials" (e.g. a password).
209209Use the
210210:class: `Symfony\\ Component\\ Security\\ Http\\ Authenticator\\ Passport\\ Badge\\ UserBadge `
211211to attach the user to the passport. The ``UserBadge `` requires a user
212- identifier (e.g. the username or email), which is used to load the user
213- using :ref: `the user provider <security-user-providers >`::
212+ identifier (e.g. the username or email)::
214213
215214 use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
216215
217216 // ...
218- $passport = new Passport(new UserBadge($email), $credentials);
217+ $passport = new Passport(new UserBadge($userIdentifier), $credentials);
218+
219+ User Identifier
220+ ~~~~~~~~~~~~~~~
221+
222+ The user identifier is a unique string that identifies the user. It is used
223+ to load the user using :ref: `the user provider <security-user-providers >`.
224+ This identifier is often something like the user's email address or username,
225+ but it could be any unique value associated with the user.
219226
220227.. note ::
221228
@@ -255,6 +262,91 @@ using :ref:`the user provider <security-user-providers>`::
255262 }
256263 }
257264
265+ It is a good practice to normalize the user identifier before using it.
266+ For example, this ensures that variations such as "john.doe", "John.Doe",
267+ or "JOHN.DOE" refer to the same user.
268+ Normalization can include converting the identifier to lowercase
269+ and trimming unnecessary spaces.
270+ You can optionally pass a user identifier normalizer as third argument to the
271+ ``UserBadge ``. This callable receives the ``$userIdentifier ``
272+ and must return a normalized user identifier as a string.
273+
274+ .. versionadded :: 7.3
275+
276+ The support of the user identifier normalizer was introduced in Symfony 7.3.
277+
278+ For instance, the example below uses a normalizer that converts usernames to a normalized, ASCII-only, lowercase format,
279+ suitable for consistent comparison and storage.
280+
281+ // src/Security/NormalizedUserBadge.php
282+ namespace App\S ecurity;
283+
284+ use Symfony\C omponent\S ecurity\H ttp\A uthenticator\P assport\B adge\U serBadge;
285+ use Symfony\C omponent\S tring\U nicodeString;
286+ use function Symfony\C omponent\S tring\u ;
287+
288+ final class NormalizedUserBadge extends UserBadge
289+ {
290+ public function __construct(string $identifier)
291+ {
292+ $callback = static fn (string $identifier) => u($identifier)->normalize(UnicodeString::NFKC)->ascii()->lower()->toString();
293+
294+ parent::__construct($identifier, null, $callback);
295+ }
296+ }
297+
298+ // src/Security/PasswordAuthenticator.php
299+ namespace App\S ecurity;
300+
301+ final class PasswordAuthenticator extends AbstractLoginFormAuthenticator
302+ {
303+ // Simplified for brievety
304+ public function authenticate(Request $request): Passport
305+ {
306+ $username = (string) $request->request->get('username', '');
307+ $password = (string) $request->request->get('password', '');
308+
309+ $request->getSession()
310+ ->set(SecurityRequestAttributes::LAST_USERNAME, $username);
311+
312+ return new Passport(
313+ new NormalizedUserBadge($username),
314+ new PasswordCredentials($password),
315+ [
316+ //All other useful badges
317+ ]
318+ );
319+ }
320+ }
321+
322+ .. note ::
323+
324+ For example, Google treats the following email addresses as equivalent:
325+ ``john.doe@gmail.com ``, ``j.hon.d.oe@gmail.com ``, and ``johndoe@gmail.com ``.
326+ This is because Google applies normalization rules that remove dots
327+ and convert the address to lowercase (though behavior varies across services).
328+
329+ .. note ::
330+
331+ In enterprise environments, a user may authenticate using different formats
332+ of their identifier, such as:
333+
334+ - ``john.doe@acme.com ``
335+ - ``acme.com\jdoe ``
336+ - ``https://acme.com/+jdoe ``
337+ - ``acct:jdoe@acme.com ``
338+
339+ Applying normalization (e.g., trimming, lowercasing, or format unification)
340+ helps ensure consistent identity recognition across systems and prevents
341+ duplicates caused by format variations.
342+
343+ User Credential
344+ ~~~~~~~~~~~~~~~
345+
346+ The user credential is used to authenticate the user i.e. to verify
347+ the validity of the provided information (such as a password, an API token,
348+ or other custom credentials).
349+
258350The following credential classes are supported by default:
259351
260352:class: `Symfony\\ Component\\ Security\\ Http\\ Authenticator\\ Passport\\ Credentials\\ PasswordCredentials `
0 commit comments