Asp.Net Core Security OAuth ( Open Authorization ) Created: 25 Jan 2026 Updated: 25 Jan 2026

JWT Signing Algorithms: A Comprehensive Guide

Introduction

When working with JSON Web Tokens (JWT) in .NET, one of the most critical decisions is choosing the right signing algorithm. The SecurityAlgorithms class in Microsoft.IdentityModel.Tokens provides various cryptographic algorithms for signing and verifying JWTs. This article explores the available algorithms, their differences, security implications, and best practices for selecting the right one for your use case.

Available Algorithm Families

1. HMAC Algorithms (Symmetric Key)

HMAC (Hash-based Message Authentication Code) algorithms use a shared secret for both signing and verification.

Available Algorithms:

  1. HS256 (SecurityAlgorithms.HmacSha256) - HMAC with SHA-256
  2. HS384 (SecurityAlgorithms.HmacSha384) - HMAC with SHA-384
  3. HS512 (SecurityAlgorithms.HmacSha512) - HMAC with SHA-512

Characteristics:

  1. Symmetric encryption: Same secret key for signing and verification
  2. Fast performance: Computationally efficient
  3. Simple implementation: Easy to set up and use
  4. Key distribution challenge: Both parties must securely share the secret

Example Usage:

var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your-256-bit-secret"));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

2. RSA Algorithms (Asymmetric Key)

RSA algorithms use public-key cryptography with a private key for signing and a public key for verification.

Available Algorithms:

  1. RS256 (SecurityAlgorithms.RsaSha256) - RSA with SHA-256
  2. RS384 (SecurityAlgorithms.RsaSha384) - RSA with SHA-384
  3. RS512 (SecurityAlgorithms.RsaSha512) - RSA with SHA-512

Characteristics:

  1. Asymmetric encryption: Private key signs, public key verifies
  2. Better key distribution: Public key can be freely shared
  3. Slower performance: More computationally intensive than HMAC
  4. Industry standard: Widely adopted in OAuth 2.0 and OpenID Connect

Example Usage:

var rsa = RSA.Create();
rsa.ImportFromPem(privateKeyPem);
var securityKey = new RsaSecurityKey(rsa);
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha256);

3. RSA-PSS Algorithms (Probabilistic Signature Scheme)

RSA-PSS provides enhanced security over traditional RSA PKCS#1 v1.5 padding.

Available Algorithms:

  1. PS256 (SecurityAlgorithms.RsaSsaPssSha256) - RSA-PSS with SHA-256
  2. PS384 (SecurityAlgorithms.RsaSsaPssSha384) - RSA-PSS with SHA-384
  3. PS512 (SecurityAlgorithms.RsaSsaPssSha512) - RSA-PSS with SHA-512

Characteristics:

  1. More secure padding: Probabilistic padding makes attacks harder
  2. Modern standard: Recommended by cryptographic experts
  3. Similar performance: Comparable to standard RSA
  4. Less compatibility: Not supported by all JWT libraries

Example Usage:

var rsa = RSA.Create();
rsa.ImportFromPem(privateKeyPem);
var securityKey = new RsaSecurityKey(rsa);
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSsaPssSha256);

4. ECDSA Algorithms (Elliptic Curve)

ECDSA (Elliptic Curve Digital Signature Algorithm) provides strong security with smaller key sizes.

Available Algorithms:

  1. ES256 (SecurityAlgorithms.EcdsaSha256) - ECDSA with P-256 curve and SHA-256
  2. ES384 (SecurityAlgorithms.EcdsaSha384) - ECDSA with P-384 curve and SHA-384
  3. ES512 (SecurityAlgorithms.EcdsaSha512) - ECDSA with P-521 curve and SHA-512

Characteristics:

  1. Smaller keys: 256-bit ECDSA ≈ 3072-bit RSA security
  2. Faster operations: Better performance than RSA
  3. Modern cryptography: Increasingly popular choice
  4. Battery-friendly: Ideal for mobile and IoT devices

Example Usage:

var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
var securityKey = new ECDsaSecurityKey(ecdsa);
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.EcdsaSha256);

Algorithm Comparison Table

AlgorithmTypeKey Size (bits)Security LevelPerformanceUse Case
HS256HMAC256GoodVery FastSingle application, microservices
HS384HMAC384BetterVery FastHigh-security internal systems
HS512HMAC512BestVery FastMaximum security internal systems
RS256RSA2048+GoodModerateMulti-party, OAuth 2.0, OpenID Connect
RS384RSA2048+BetterModerateHigh-security multi-party
RS512RSA2048+BestSlowerMaximum security multi-party
PS256RSA-PSS2048+BetterModerateModern secure applications
PS384RSA-PSS2048+BetterModerateModern high-security applications
PS512RSA-PSS2048+BestSlowerModern maximum security
ES256ECDSA256GoodFastMobile apps, IoT, modern APIs
ES384ECDSA384BetterFastHigh-security mobile/IoT
ES512ECDSA521BestFastMaximum security modern systems

Which Algorithm Should You Choose?

Use HMAC (HS256/HS384/HS512) When:

✅ Your application signs and verifies tokens itself (monolithic architecture)

✅ You need maximum performance

✅ Tokens are used only internally

✅ You have secure key management in place

✅ Building microservices within a trusted boundary

Avoid when:

  1. Third parties need to verify tokens
  2. Multiple independent services need verification
  3. Implementing OAuth 2.0 or OpenID Connect

Use RSA (RS256/RS384/RS512) When:

✅ Multiple independent parties verify tokens

✅ Implementing OAuth 2.0 / OpenID Connect

✅ Building public APIs with JWT authentication

✅ Need to distribute public keys for verification

✅ Industry standard compliance required

Avoid when:

  1. Performance is critical
  2. Working in resource-constrained environments
  3. Only internal token usage

Use RSA-PSS (PS256/PS384/PS512) When:

✅ Need maximum RSA security

✅ Modern infrastructure with recent library versions

✅ Security requirements mandate probabilistic padding

✅ Building new systems without legacy constraints

Avoid when:

  1. Need broad compatibility with older systems
  2. Integrating with legacy JWT consumers

Use ECDSA (ES256/ES384/ES512) When:

✅ Building mobile or IoT applications

✅ Performance and key size matter

✅ Need modern cryptography

✅ Battery consumption is a concern

✅ Future-proofing your security

Avoid when:

  1. Legacy system compatibility required
  2. FIPS 140-2 compliance needed (check implementation)

Security Recommendations

Minimum Key Sizes

  1. HMAC: At least 256 bits (32 bytes)
  2. RSA: At least 2048 bits (3072 bits recommended)
  3. ECDSA: Use named curves (P-256, P-384, P-521)

Hash Algorithm Selection

HashSecurity LevelRecommendation
SHA-256128-bit✅ Recommended minimum
SHA-384192-bit✅ High security applications
SHA-512256-bit✅ Maximum security (overkill for most)

Best Practices

  1. Default Recommendation: Use RS256 for most applications
  2. Industry standard
  3. Good security
  4. Wide compatibility
  5. Clear separation of signing and verification
  6. Modern Applications: Consider ES256
  7. Better performance than RSA
  8. Smaller key sizes
  9. Future-proof
  10. Mobile-friendly
  11. Internal Services: Use HS256 if appropriate
  12. Simpler key management
  13. Better performance
  14. Lower resource usage
  15. High Security: Use PS256 or ES384
  16. Enhanced security properties
  17. Suitable for sensitive data
  18. Modern cryptographic standards
  19. Never Use:
  20. None algorithm (no signature)
  21. ❌ Weak algorithms (if any legacy ones exist)
  22. ❌ Custom/untested algorithms

Common Pitfalls

1. Algorithm Confusion Attack

Always validate the algorithm in the JWT header matches your expected algorithm:

var validationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = securityKey,
ValidAlgorithms = new[] { SecurityAlgorithms.RsaSha256 }, // Specify allowed algorithms
ValidateIssuer = true,
ValidIssuer = "your-issuer",
ValidateAudience = true,
ValidAudience = "your-audience"
};

2. Weak Secret Keys (HMAC)

Don't use weak secrets:

// ❌ BAD: Weak secret
var weak = "secret123";

// ✅ GOOD: Strong random secret (at least 256 bits)
var strong = Convert.ToBase64String(RandomNumberGenerator.GetBytes(32));

3. Key Rotation

Implement key rotation strategy:

var validationParameters = new TokenValidationParameters
{
IssuerSigningKeyResolver = (token, securityToken, kid, parameters) =>
{
// Return appropriate key based on 'kid' (Key ID) from JWT header
return GetSigningKeys(kid);
}
};

Real-World Scenarios

Scenario 1: OAuth 2.0 Authorization Server

Recommended: RS256 or ES256

// Your current implementation (good choice!)
var rsa = RSA.Create();
rsa.ImportFromPem(_jwtOptions.PrivateKey);
var securityKey = new RsaSecurityKey(rsa);
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha256);

Why: OAuth clients need to verify tokens using your public key.

Scenario 2: Microservices Authentication

Recommended: HS256 with shared secret

var sharedSecret = Configuration["JWT:SharedSecret"];
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(sharedSecret));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

Why: All services trust each other and can share a secret securely.

Scenario 3: Mobile App Authentication

Recommended: ES256

var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
var securityKey = new ECDsaSecurityKey(ecdsa);
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.EcdsaSha256);

Why: Better performance on mobile devices, smaller tokens.

Scenario 4: High-Security Financial System

Recommended: PS384 or ES384

var rsa = RSA.Create(3072); // Larger key size
var securityKey = new RsaSecurityKey(rsa);
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSsaPssSha384);

Why: Enhanced security for sensitive financial data.

Migration Strategy

If you need to change algorithms:

  1. Add new algorithm support alongside the old
  2. Start signing with new algorithm
  3. Validate both algorithms during transition period
  4. Monitor old algorithm usage
  5. Remove old algorithm after all tokens expired
var validationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKeys = new[] { oldKey, newKey }, // Support both during migration
ValidAlgorithms = new[]
{
SecurityAlgorithms.RsaSha256, // Old
SecurityAlgorithms.EcdsaSha256 // New
}
};

Conclusion

The choice of JWT signing algorithm depends on your specific requirements:

  1. Most Common Choice: RS256 - Industry standard for multi-party scenarios
  2. Best Performance: HS256 - For trusted internal systems
  3. Modern & Efficient: ES256 - For mobile, IoT, and new applications
  4. Maximum Security: PS384 or ES384 - For high-security requirements

Your current implementation using RS256 is an excellent choice for an OAuth 2.0 client credentials flow with asymmetric keys. It provides:

  1. ✅ Strong security
  2. ✅ Industry standard compliance
  3. ✅ Public key distribution for verification
  4. ✅ Wide compatibility

Quick Decision Tree

Do multiple parties need to verify tokens?
├─ Yes → Use RSA (RS256) or ECDSA (ES256)
│ └─ Need maximum security? → Use PS256/PS384 or ES384
└─ No → Use HMAC (HS256)
└─ Need maximum security? → Use HS512
Share this lesson: