.NET
JWT and Microsoft Identity: How I Understand the Difference
I kept treating JWT and Microsoft Identity as competing choices. They're not. One's the ticket booth confirming who you are, the other's the wristband proving it on every ride after that.
I kept treating JWT and Microsoft Identity as if they were competing choices, as if the question was "should I use Identity or should I use JWT." That's the wrong question. They do different jobs, and in most APIs I build, they work together instead of against each other.
The theme park version
The way this finally made sense to me: think of building a system for an amusement park.
Microsoft Identity is the database and the ticket booth. It handles who you are and what your account contains, the tables for users, hashed passwords, roles, and claims. It's the piece that answers "register a new user," "check if this password is correct," or "lock the account after five failed login attempts."
A JWT is the wristband. It's just a format for a signed badge. Once the ticket booth verifies who you are, it prints a cryptographically signed wristband, the JWT string, and hands it over. You wear that wristband on every ride after that. The ride operator doesn't call the ticket booth every time, they just check the wristband has a valid signature and let you through.
What that maps to in code
A login request goes to Identity first. It finds the user, verifies the password hash, and only then does the token get created:
[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 is Identity, talking to the database. _tokenService just packages up the claims Identity already confirmed and signs them.
That token comes back to the client, and every request after that carries it in the Authorization header instead of the username and password. The middleware that checks it never touches Identity at all:
builder.Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateLifetime = true
};
});
Signature and expiration, that's it. No database call on every request that follows.
Where the confusion came from
I think I mixed them up because both terms show up in the same authentication conversations, so it's easy to assume they're two options for the same problem. Once I saw them as two different layers instead, the ticket booth confirming who you are, and the wristband proving it on every ride after that, the confusion cleared up.