System.IdentityModel.Tokens.Jwt is safe for production .NET authentication as long as you stay on a patched version and configure token validation explicitly rather than trusting defaults. The security of System.IdentityModel.Tokens.Jwt comes down to two things: keeping the Microsoft.IdentityModel packages current to avoid the known DoS CVE, and setting TokenValidationParameters so that signatures, issuers, audiences, and lifetimes are all actually checked.
This library, part of Microsoft's IdentityModel family, is how most ASP.NET Core apps create and validate JSON Web Tokens. Because it sits directly on the authentication path, both its version and its configuration matter more than a typical dependency.
Keep the package patched: CVE-2024-21319
The notable advisory here is CVE-2024-21319, a denial-of-service issue in System.IdentityModel.Tokens.Jwt and Microsoft.IdentityModel.JsonWebTokens. Processing a JSON Web Encryption (JWE) token with a high compression ratio could cause excessive memory allocation during decompression, letting an attacker exhaust server memory.
Microsoft's guidance is to update the Microsoft.IdentityModel packages to a fixed release: 7.1.2 or later for the 7.x line, 6.34.0 or later for 6.x, and 5.7.0 or later for 5.x. Because these packages travel as a set, upgrade them together rather than bumping one in isolation:
dotnet add package System.IdentityModel.Tokens.Jwt
Check what actually resolved with dotnet list package --include-transitive, since these libraries are frequently pulled in transitively by ASP.NET Core authentication middleware.
Validate signatures: never accept "none"
The most dangerous JWT mistake predates any CVE: accepting a token without verifying its signature. A JWT's header names its signing algorithm, and historically some libraries would honor an attacker-supplied alg: none and skip verification entirely. Always require a signing key and reject unsigned tokens:
var validationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey, // your key or key set
RequireSignedTokens = true,
RequireExpirationTime = true,
};
RequireSignedTokens = true and a configured IssuerSigningKey mean the library will not accept a token it cannot cryptographically verify.
Check issuer, audience, and lifetime
A valid signature only proves the token was signed by a key you trust. You still have to confirm it was meant for you and is still current. Leaving any of these off is a common way tokens intended for one service get replayed against another:
var validationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "https://login.example.com/",
ValidateAudience = true,
ValidAudience = "api://my-service",
ValidateLifetime = true,
ClockSkew = TimeSpan.FromSeconds(30), // tighten the default 5 minutes
};
Two things are worth calling out. First, set ValidateAudience and ValidateIssuer explicitly; a permissive configuration that skips them will happily accept a token issued for a different application. Second, the default ClockSkew is five minutes, which quietly extends every token's usable lifetime by that much. Tightening it to a few seconds is reasonable for most APIs.
Prefer the newer JsonWebTokenHandler
Microsoft's newer JsonWebTokenHandler (in Microsoft.IdentityModel.JsonWebTokens) is the more modern, better-performing handler and is what recent ASP.NET Core versions use by default. If you are writing new validation code, prefer it over the older JwtSecurityTokenHandler. Either way, the same validation-parameter discipline applies; the handler choice does not change the need to verify signature, issuer, audience, and expiry.
Protect the signing key and rotate it
None of the validation above helps if the signing key leaks. Store keys in a secrets manager or key vault, never in source or config files committed to a repo. For symmetric keys, use a key long enough for the chosen algorithm; for asymmetric signing, keep the private key out of the client entirely and publish only the public key or JWKS endpoint. Plan for rotation so a compromised key can be retired without downtime, which usually means supporting multiple valid keys during a transition window.
Keep the whole IdentityModel set current
Because these packages update together and sit on the auth path, drift is a real risk: an app can end up on a patched System.IdentityModel.Tokens.Jwt while a transitive dependency drags an old Microsoft.IdentityModel.Tokens back in. Scan the resolved tree so a vulnerable version fails the build. An SCA tool can flag a stale IdentityModel package even when it arrives three layers deep through the authentication middleware.
FAQ
Is System.IdentityModel.Tokens.Jwt safe to use?
Yes, on a patched version with explicit validation configured. Keep the Microsoft.IdentityModel packages at 7.1.2+/6.34.0+/5.7.0+ to avoid CVE-2024-21319, and set TokenValidationParameters to verify signature, issuer, audience, and lifetime.
What is CVE-2024-21319?
It is a denial-of-service vulnerability in System.IdentityModel.Tokens.Jwt and Microsoft.IdentityModel.JsonWebTokens. A JWE token with a high compression ratio could trigger excessive memory allocation during decompression. Upgrading to the fixed package versions resolves it.
Should I use JwtSecurityTokenHandler or JsonWebTokenHandler?
For new code, prefer JsonWebTokenHandler, the newer and faster handler that recent ASP.NET Core defaults to. Either way you must configure the same validation parameters; the handler choice does not remove the need to validate the token.
Why should I change the default ClockSkew?
The default ClockSkew of five minutes silently extends every token's usable window by that amount, which weakens expiration. Tightening it to around 30 seconds keeps short-lived tokens actually short-lived while still tolerating minor clock differences.