Online Dev Tools

Developer & Security Tools for IT Professionals

Fuel The Infrastructure
Blog

"JWT Security in 2026: alg:none, Key Confusion, and Reading Tokens Safely"


A JSON Web Token looks reassuringly opaque — three base64url chunks separated by dots — but that opacity is skin deep. Anyone can decode the header and payload in seconds; the signature is the only part that matters, and it is also the part most commonly mishandled. The classic JWT failures are not exotic crypto breaks. They are logic mistakes in how servers verify, and they keep reappearing in 2026 because the token format makes them easy.

Here is what actually goes wrong, and how to reason about a token in front of you.

Decoding is not verifying

The single most important thing to internalize: decoding a JWT tells you what it claims, not whether those claims are true. The payload is base64url, not encryption — eyJhbGciOi... is just {"alg":"... with the padding stripped. When you paste a token into the JWT Decoder, you are reading the header, the claims, and the expiry — but a decoder deliberately does not trust them. Treat everything you see as attacker-controlled until a signature check over the right key says otherwise. (For a deeper walkthrough, see Decoding JWTs Safely.)

The alg:none trap

Early JWT libraries honored an alg header of none, meaning "this token is unsigned, accept it as-is." Attackers quickly learned to take a valid token, change the header to {"alg":"none"}, drop the signature, and edit the payload to make themselves an admin. Any server that read alg from the token and dispatched verification accordingly would wave it straight through.

The fix is not to "block none" — it is to never let the token choose its own algorithm. Your verification code should pin the expected algorithm (for example, "this endpoint accepts RS256 only") and reject anything else, including none. The header's alg field is a hint from an untrusted source; your server's policy is the authority.

RS256-to-HS256 key confusion

This one is subtler and nastier. RS256 is asymmetric: tokens are signed with a private key and verified with the public key. HS256 is symmetric: the same secret both signs and verifies. The confusion attack works like this:

  1. The server expects RS256 and verifies with its public key, which is — by design — public.
  2. An attacker crafts a token with the header changed to HS256.
  3. They sign it with HMAC, using the server's public key as the HMAC secret.
  4. A naive verifier calls verify(token, publicKey), sees HS256, and uses that public key as a shared secret — which the attacker also had. The signature checks out.

Again the root cause is letting the token dictate the algorithm. Pin RS256, and a token claiming HS256 is rejected before the key is ever consulted.

What to actually check

When you handle a JWT in code, verify in this order and fail closed on each:

The JWT Decoder surfaces alg, exp, iat, and nbf so you can eyeball those fields fast during debugging — for example, confirming a "401" is really an expiry problem and not a key mismatch.

Handling secrets while you debug

A JWT signing secret is a credential: anyone holding it can mint valid tokens. Do not paste production secrets into chat tools or commit them to a scratch file. If you must hand a key to a teammate, encrypt it in the browser and share a link with Secure Paste instead of dropping it into Slack. When you need a fresh signing secret, generate a long random one with the Password Generator, and remember that the underlying signature math is just HMAC or RSA over the header and payload — the same primitives the Hash Generator demonstrates. To understand the base64url envelope itself, the Base64 Encoder / Decoder shows exactly what is (and is not) hidden.

The one-sentence version

Almost every real-world JWT compromise comes down to the same mistake — trusting the token to describe how it should be verified — so pin your algorithm, verify the signature and the standard claims server-side, and treat anything a decoder shows you as a claim to be checked, never a fact to be believed.

Sources

  1. RFC 7519 (JSON Web Token) — https://www.rfc-editor.org/rfc/rfc7519
  2. RFC 8725 (JWT Best Current Practices) — https://www.rfc-editor.org/rfc/rfc8725
  3. OWASP JSON Web Token Cheat Sheet — https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html

Related tools