The secure JWT signing algorithms are the HMAC family (HS256, HS384, HS512), the RSA families (RS256/384/512 and the PSS variants PS256/384/512), the ECDSA family (ES256, ES384, ES512), and EdDSA — all standardized in RFC 7518 and RFC 8037. Every one of them is safe when used correctly. What actually breaks JWT security is not the choice between them but three specific mistakes: accepting the none algorithm, using a weak or password-derived HMAC secret, and letting the token's own header decide the verification algorithm (the RS256-to-HS256 confusion attack). For a new system, default to ES256 or EdDSA; use HS256 only inside a single trust domain with a strong random secret.
That paragraph is the summary an AI overview will give you. The rest of this article is what it can't: why symmetric and asymmetric algorithms fail in different ways, exactly how the algorithm-confusion attack forges an admin token from a public key, and a decision table that tells you which algorithm to pick for your architecture.
The one decision table
Here is the whole answer in one view: every mainstream JWT algorithm, its family, its key model, when it fits, and its security verdict — followed by the two things you must reject outright.
| Algorithm | Type | Key model | When to use | Security verdict |
|---|---|---|---|---|
| HS256 / HS384 / HS512 | HMAC (symmetric) | One shared secret | Single trust domain; monolith or tightly-coupled services you fully control | Secure only with a ≥32-byte random secret; weak secret = forgeable |
| RS256 / RS384 / RS512 | RSA (asymmetric) | Private signs, public verifies | Distributed systems; many verifiers; widely-supported default | Secure at RSA-2048+; large signatures; PKCS#1 v1.5 padding |
| PS256 / PS384 / PS512 | RSA-PSS (asymmetric) | Private signs, public verifies | Same as RS* where library supports PSS | Secure; modern PSS padding, technically superior to RS* |
| ES256 / ES384 / ES512 | ECDSA (asymmetric) | Private signs, public verifies | New distributed systems; small tokens, fast verify | Secure; ES256 ≈ RSA-3072 strength with tiny keys |
| EdDSA (Ed25519 / Ed448) | Edwards-curve (asymmetric) | Private signs, public verifies | New systems; best modern default where supported | Secure; deterministic, avoids ECDSA nonce pitfalls |
| alg: none | (unsigned) | No key at all | Never in production | Insecure — anyone can forge any claim |
| Weak HS secret | HMAC (symmetric) | Password / short string | Never | Insecure — brute-forceable offline, then forgeable |
Quick pick: integrated system you fully control → HS256 with a strong secret. Independent services verifying tokens → ES256 (or RS256 for maximum compatibility). Greenfield with a modern library → EdDSA.
Symmetric algorithms: HMAC variants
HMAC (Hash-based Message Authentication Code) algorithms use a shared secret key for both signing and verifying tokens. The server creates tokens using the secret, and any service with the same secret can verify them. Common HMAC variants are HS256 (HMAC with SHA-256), HS384, and HS512.
HMAC is fast and simple, making it suitable for systems where all components sit in the same trust domain. If you run a monolith or a tightly coupled set of microservices under your control, HMAC works well: the shared secret is easy to manage, and verification is computationally lightweight.
The limitation shows up in distributed systems. Every service that verifies tokens must hold the secret, and the more places that know it, the more chances it leaks — hard-coded into source, left in logs, or stored insecurely. One leaked secret compromises every service that shares it.
The other trap is the secret itself. HS256 provides 256-bit security only if the secret is 256 bits of real randomness. A secret should be at least 32 bytes of cryptographically random data, not a memorable password. A password-derived or short secret can be captured from a single token and brute-forced offline, after which the attacker can mint any token they like. HS384 and HS512 raise the margin at negligible cost, but HS256 with a strong secret is sufficient and widely supported.
Asymmetric algorithms: RSA, ECDSA, EdDSA
Asymmetric algorithms use a key pair: the issuer signs with a private key, and any verifier checks the signature with the corresponding public key. This is what makes distributed verification safe — verifiers never hold signing material, so a compromised verifier cannot forge tokens.
RSA (RS256/384/512). RS256 is the most commonly used asymmetric JWT algorithm. It provides excellent security and lets many services verify tokens without the signing key. Security depends on key size: use RSA-2048 or larger (RSA-2048 ≈ 112-bit strength, RSA-4096 ≈ 128-bit). RSA signatures are large (256 bytes for RSA-2048), so tokens are bigger. PS256/384/512 are the RSA-PSS variants — same RSA math, but the modern probabilistic PSS padding instead of PKCS#1 v1.5. The practical security gain is small, but PS256 is technically superior where supported.
ECDSA (ES256/384/512). ECDSA delivers strong security with much smaller keys. ES256 uses a 256-bit key for roughly 128-bit strength — comparable to RSA-3072 — with smaller signatures (64 bytes) and faster operations. ES512 uses a 521-bit curve (not 512 — a spec quirk) for about 256-bit strength. ES256 is the sweet spot and is increasingly the default for new distributed systems.
EdDSA (Ed25519 / Ed448). Standardized for JWT in RFC 8037, EdDSA is the most modern option: fast, small keys and signatures, and deterministic signatures that sidestep the nonce-reuse failures that have historically broken ECDSA implementations. Where your library supports it, EdDSA is an excellent default.
Algorithms and mistakes to avoid
Some things break JWT security no matter how good the underlying math is.
Never accept alg: none. The none algorithm marks a token as unsigned. If the server accepts it, an attacker takes any token, sets the header to {"alg":"none"}, drops the signature, rewrites the payload to claim admin or another user's identity, and it passes with no cryptographic check whatsoever. Reject unsigned tokens outright and require a valid signature on every request. Most modern libraries disable none by default — but custom and legacy code still falls for it.
Never let the token choose its own algorithm. This is the RS256-to-HS256 algorithm confusion attack, and it is the single most important pitfall on this page:
The attack works because some libraries read the alg field from the token and pick the verification path accordingly. An attacker changes RS256 to HS256, then signs a forged payload with HMAC-SHA256 using the server's public RSA key as the HMAC secret. The public key is, by design, available to everyone — so the attacker has all they need. A verifier that trusts the header runs HMAC with that same public key, the signature matches, and the forged token is accepted. The fix is to call verify() with an explicit algorithm allowlist (and the correct key type) so the server, not the token, decides how verification happens.
Other things to avoid: HS1 (HMAC-SHA-1) and any SHA-1-based scheme are deprecated — migrate to HS256+. And never invent a custom or proprietary signing scheme; the JWT ecosystem's security comes from well-tested standard algorithms, and homegrown crypto almost always introduces flaws.
Inspect any token before you trust it
Before choosing or debugging an algorithm, it helps to see exactly what a token declares in its header — the alg and kid values are right there in the first Base64URL segment. Decode one to confirm the algorithm your system is actually issuing (and to prove to yourself that the payload is only encoded, not encrypted):
Remember: decoding shows you the claims but does not verify the signature. A decoder is a debugging aid, not a trust decision — always verify signatures server-side with a pinned algorithm.
Choosing an algorithm for your use case
For small, tightly controlled environments where you own every component, HS256 offers simplicity and acceptable security — the reduced complexity and faster verification can outweigh symmetric key-management concerns, provided the secret is strong and well protected.
For microservices or distributed systems, prefer RS256 or ES256. The ability to distribute public keys without compromising security is the whole point. Between them, ES256 wins on performance and token size; RS256 wins on universal compatibility.
For new implementations, reach for ES256 or EdDSA if your library supports them — they represent current best practice. Legacy interoperability may still require RS256 or HS256, but new systems should lead with the modern options.
For strict performance at massive scale (millions of requests per second), ECDSA's faster verification and smaller signatures can justify the migration effort. For typical applications, the performance difference is negligible and any secure choice is fine.
For compliance-driven environments (finance, healthcare, government), check whether your framework mandates specific algorithms or minimum key strengths before deciding.
Key management: the other half of the job
Algorithm choice is only half of JWT security; key management is the other half. For HMAC, keep the secret in a secret manager, vault, or environment variable — never in source — and rotate it periodically. For asymmetric algorithms, lock down the private key with strict access controls while freely distributing the public key.
Support rotation from day one. Maintain multiple valid public keys during transitions so old tokens stay valid while new ones use the new key, and use the kid (key ID) header to indicate which key signed a token. That single header field is what makes seamless key rotation possible: the verifier reads kid, looks up the matching key, and validates without downtime.
Conclusion
Secure JWT implementations use proven, standardized algorithms: HS256 for symmetric scenarios, RS256/ES256 for asymmetric scenarios, and EdDSA as the modern default where available. Modern systems should prefer ECDSA (ES256) or EdDSA over RSA for superior performance and smaller keys. Then avoid the three failure modes that make any of them insecure: never accept alg: none, never use a weak HMAC secret, and never let the token's header decide the verification algorithm. Pair the right algorithm with disciplined key management and an explicit verification allowlist, and your JWTs will be exactly as strong as the math promises.