← tous les articles

.NET

JWT et Microsoft Identity : comment je comprends la différence

Je n'arrêtais pas de traiter JWT et Microsoft Identity comme des choix concurrents. Ce n'est pas le cas. L'un est le guichet qui confirme qui vous êtes, l'autre est le bracelet qui le prouve à chaque manège ensuite.

JWT et Microsoft Identity : comment je comprends la différence

Je n'arrêtais pas de traiter JWT et Microsoft Identity comme si c'étaient des choix concurrents, comme si la question était « devrais-je utiliser Identity ou devrais-je utiliser JWT ». C'est la mauvaise question. Ils font des travaux différents, et dans la plupart des API que je construis, ils travaillent ensemble plutôt que l'un contre l'autre.

La version parc d'attractions

La façon dont ça a finalement fait sens pour moi : pensez à construire un système pour un parc d'attractions.

Microsoft Identity, c'est le database et le guichet. Il gère qui vous êtes et ce que contient votre compte, les tables pour les utilisateurs, les mots de passe hashés, les roles, et les claims. C'est la pièce qui répond à « inscrire un nouvel utilisateur », « vérifier si ce mot de passe est correct », ou « verrouiller le compte après cinq tentatives de connexion ratées ».

Un JWT, c'est le bracelet. C'est juste un format pour un badge signé. Une fois que le guichet vérifie qui vous êtes, il imprime un bracelet signé cryptographiquement, la string du JWT, et vous le remet. Vous portez ce bracelet à chaque manège ensuite. L'opérateur du manège n'appelle pas le guichet à chaque fois, il vérifie juste que le bracelet a une signature valide et vous laisse passer.

Ce que ça donne dans le code

Un request de connexion va d'abord à Identity. Il trouve l'utilisateur, vérifie le hash du mot de passe, et c'est seulement après que le token est créé :

[HttpPost("login")]
public async Task<IActionResult> Login(LoginRequest request)
{
    // Microsoft Identity: the ticket booth
    var user = await _userManager.FindByEmailAsync(request.Email);

    if (user is null || !await _userManager.CheckPasswordAsync(user, request.Password))
    {
        return Unauthorized();
    }

    // JWT: the wristband
    var token = _tokenService.CreateToken(user);
    return Ok(new { accessToken = token });
}

_userManager, c'est Identity, qui parle au database. _tokenService se contente d'empaqueter les claims qu'Identity a déjà confirmées et de les signer.

Ce token revient au client, et chaque request ensuite le porte dans le header Authorization au lieu du nom d'utilisateur et du mot de passe. Le middleware qui le vérifie ne touche jamais à Identity :

builder.Services
    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(key),
            ValidateLifetime = true
        };
    });

Signature et expiration, c'est tout. Aucun appel au database sur chaque request qui suit.

D'où venait la confusion

Je pense que je les ai mélangés parce que les deux termes apparaissent dans les mêmes conversations sur l'authentication, donc c'est facile de supposer que ce sont deux options pour le même problème. Dès que je les ai vus comme deux couches différentes, le guichet qui confirme qui vous êtes, et le bracelet qui le prouve à chaque manège ensuite, la confusion s'est dissipée.