Skip to content

Commit a7df8a2

Browse files
committed
Update custom authenticator docs to include identifier normalization
Improve the documentation for custom authenticators by detailing the concept of user identifier normalization. Introduced the `NormalizedUserBadge` example to demonstrate how to simplify and standardize identifiers. Clarified how normalization avoids duplicates and ensures consistent user recognition.
1 parent 0b180d5 commit a7df8a2

File tree

1 file changed

+93
-3
lines changed

1 file changed

+93
-3
lines changed

Diff for: security/custom_authenticator.rst

+93-3
Original file line numberDiff line numberDiff line change
@@ -209,13 +209,20 @@ requires a user and some sort of "credentials" (e.g. a password).
209209
Use the
210210
:class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\UserBadge`
211211
to 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,89 @@ 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+
279+
// src/Security/NormalizedUserBadge.php
280+
namespace App\Security;
281+
282+
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
283+
use Symfony\Component\String\UnicodeString;
284+
use function Symfony\Component\String\u;
285+
286+
final class NormalizedUserBadge extends UserBadge
287+
{
288+
public function __construct(string $identifier)
289+
{
290+
$callback = static fn (string $identifier) => u($identifier)->normalize(UnicodeString::NFKC)->ascii()->lower()->toString();
291+
292+
parent::__construct($identifier, null, $callback);
293+
}
294+
}
295+
296+
// src/Security/PasswordAuthenticator.php
297+
namespace App\Security;
298+
299+
final class PasswordAuthenticator extends AbstractLoginFormAuthenticator
300+
{
301+
// Simplified for brievety
302+
public function authenticate(Request $request): Passport
303+
{
304+
$username = (string) $request->request->get('username', '');
305+
$password = (string) $request->request->get('password', '');
306+
307+
$request->getSession()
308+
->set(SecurityRequestAttributes::LAST_USERNAME, $username);
309+
310+
return new Passport(
311+
new NormalizedUserBadge($username),
312+
new PasswordCredentials($password),
313+
[
314+
//All other useful badges
315+
]
316+
);
317+
}
318+
}
319+
320+
.. note::
321+
322+
Similarly, Google normalizes email addresses so that "john.doe", "j.hon.d.oe",
323+
and "johndoe" all correspond to the same account.
324+
This involves removing dots and converting the email address to lowercase
325+
(though normalization specifics depend on your use case).
326+
327+
.. note::
328+
329+
In enterprise applications, a user may need to use their identifier in multiple formats,
330+
such as:
331+
332+
- ``acme.com\jdoe``
333+
- ``https://acme.com/+jdoe``
334+
- ``acct:[email protected]``
335+
336+
Normalizing these identifiers (e.g., converting to lowercase, trimming spaces,
337+
or unifying formats) simplifies searches and ensures that the same user identity
338+
is consistently recognized.
339+
This is particularly useful to avoid duplicates caused by format variations.
340+
341+
User Credential
342+
~~~~~~~~~~~~~~~
343+
344+
The user credential is used to authenticate the user i.e. to verify
345+
the validity of the provided information (such as a password, an API token,
346+
or other custom credentials).
347+
258348
The following credential classes are supported by default:
259349

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

0 commit comments

Comments
 (0)