October 28, 2026
JWT Authentication: Structure, Attacks, and Why Weak Signature Validation Gets You Pwned
JSON Web Tokens (JWT) are the backbone of authentication in modern APIs, single page applications, and microservice architectures. They are…

By Muhammad Kashif
6 min read
JSON Web Tokens (JWT) are the backbone of authentication in modern APIs, single page applications, and microservice architectures. They are compact, stateless, and easy to implement, which is exactly why they are also one of the most frequently misconfigured components in production web applications. This article breaks down how JWT works internally, walks through the main attack classes used against it, and covers the server side defenses that actually stop them.
1. What a JWT Actually Is
A JWT is a token format designed to carry information between a client and a server. It serves two core purposes:
- Authentication: verifying that a user is who they claim to be, based on credentials they submitted earlier.
- Authorization: determining what an already verified user is permitted to access.
A JWT is a single string made of three Base64Url encoded segments separated by dots:
header.payload.signatureheader.payload.signatureHeader: metadata about the token, typically the token type (JWT) and the signing algorithm (HS256, RS256, etc).
Payload: the actual claims being transmitted, such as user ID, username, role, issuer, and expiration time. Nothing here is encrypted by default. It is only encoded, meaning anyone who intercepts the token can decode and read it in plaintext.
Signature: generated by signing the header and payload using a secret key (HMAC algorithms) or a private key (RSA/ECDSA algorithms). The signature is the only mechanism that proves the token has not been altered since it was issued.
2. The Authentication Flow
- The user submits valid credentials to the server.
- The server verifies the credentials against its records.
- On success, the server issues a signed JWT in the response.
- The client attaches this JWT to subsequent requests, typically in the
Authorization: Bearer <token>header. - On every request, the server must validate the signature before trusting any claim inside the token.
That final step is where most real world vulnerabilities originate. If signature validation is weak, missing, or improperly enforced, the token stops being proof of identity and becomes nothing more than attacker controlled input.
3. Common JWT Attack Classes
3.1 Algorithm None Attack
Some JWT libraries historically supported alg: none, meaning the token carries no signature at all. If the server does not explicitly reject unsigned tokens, an attacker can:
- Decode the token.
- Modify the payload (for example, change
sub: wienertosub: administrator, or set aroleclaim toadmin). - Rewrite the header to:
{"typ": "JWT", "alg": "none"}{"typ": "JWT", "alg": "none"}- Strip the signature segment entirely, leaving only
header.payload. - Resend the token.
If the server still accepts this token as valid, authentication is fully bypassed with no cryptographic work required. Most modern libraries patched this issue after it was publicly disclosed in 2015, but it still surfaces in legacy systems and custom JWT implementations that do not pin an expected algorithm list.
3.2 Weak Secret Brute Forcing
For HMAC based algorithms like HS256, the signature depends entirely on a shared secret string. If that secret is weak (a short word, a default value such as secret, or something derivable from public information), it can be recovered through offline brute forcing.
hashcat -m 16500 token.txt wordlist.txthashcat -m 16500 token.txt wordlist.txtTools such as hashcat, jwt_tool, and c-jwt-cracker are built specifically for this. Once the secret is recovered, an attacker can forge arbitrarily signed tokens with any claims, including elevated roles or impersonated user IDs, and the server will accept them as legitimate because the signature will validate correctly.
3.3 Algorithm Confusion (RS256 to HS256)
This is the most technically significant and still actively exploited JWT vulnerability class. It targets applications that use asymmetric signing (RS256) where the server holds a private key for signing and exposes a public key for verification.
The vulnerability arises in poorly written verification logic that trusts the alg field inside the token itself to decide how to validate it:
function verify(token, secretOrPublicKey) {
algorithm = token.getAlgHeader();
if (algorithm == "RS256") {
// treat the key as an RSA public key
} else if (algorithm == "HS256") {
// treat the same key as an HMAC secret
}
}function verify(token, secretOrPublicKey) {
algorithm = token.getAlgHeader();
if (algorithm == "RS256") {
// treat the key as an RSA public key
} else if (algorithm == "HS256") {
// treat the same key as an HMAC secret
}
}If this function is exposed to attacker controlled tokens, the exploitation path is:
- Obtain the server's RSA public key. This is often published at a
/.well-known/jwks.jsonendpoint or embedded in client side code. - Craft a new JWT with modified claims (for example, changing the subject to an admin account).
- Change the header's
algfield fromRS256toHS256. - Sign the new token using HS256, with the raw bytes of the RSA public key used as the HMAC secret.
- Submit the forged token.
Since the server's verify() function switches to HMAC mode based on the attacker supplied alg value, it ends up using the public key (which is, by definition, not secret) as the HMAC signing key. The signature matches, and the forged token is accepted as authentic. In cases where the public key is not directly exposed, it can sometimes be mathematically derived from two valid RS256 tokens using tools such as PortSwigger's sig2n.
This single flaw is capable of producing a complete authentication bypass with full control over token claims.
4. Practical Demonstration Context
In a controlled lab environment (such as PortSwigger's JWT labs), this flow is typically demonstrated as follows:
- Authenticate normally with valid low privilege credentials and intercept the response containing the issued JWT.
- Decode the token using a JWT debugger or a tool such as the JWT Editor extension in Burp Suite.
- Identify the signing algorithm declared in the header.
- Modify the payload to escalate privileges, for example changing the
subclaim to an administrator account. - Depending on the vulnerability present, either strip the signature and set
algtonone, or perform the RS256 to HS256 key confusion attack described above. - Forward the modified token and observe whether the server grants elevated access, for instance exposing an admin panel that allows account deletion or configuration changes.
A successful bypass confirms that the server trusts client supplied metadata (the algorithm field) rather than enforcing a fixed, server side validation policy, which is the root cause behind nearly every JWT related vulnerability.
5. Defensive Measures
Mitigating these attack classes is almost entirely about removing trust from the token itself and enforcing validation rules strictly on the server side.
- Pin the expected algorithm explicitly. Never derive the verification method from the token's own header.
// Vulnerable: algorithm derived from the token
const decoded = jwt.verify(token, publicKey);
// Secure: algorithm enforced server side
const decoded = jwt.verify(token, publicKey, {
algorithms: ["RS256"]
});// Vulnerable: algorithm derived from the token
const decoded = jwt.verify(token, publicKey);
// Secure: algorithm enforced server side
const decoded = jwt.verify(token, publicKey, {
algorithms: ["RS256"]
});- Reject
alg: noneoutright. Do not rely solely on library defaults; explicitly disallow it in the algorithm whitelist. - Use strong, high entropy secrets for HMAC signing, generated and stored through a secrets manager such as AWS Secrets Manager or HashiCorp Vault, never hardcoded or guessable.
- Never allow both symmetric and asymmetric algorithms on the same verification endpoint. If the application uses RS256, the verification function should never accept HS256 under any circumstance.
- Set short token expiration windows and implement proper refresh token rotation and revocation.
- Validate
iss(issuer) andaud(audience) claims to prevent tokens issued for one service being replayed against another. - Keep JWT libraries updated. Most of the attack classes described above were patched at the library level once publicly disclosed, but only in versions released after the fix.
6. Detection Opportunities for Defenders
From a blue team or SOC perspective, the following patterns are worth alerting on:
- Any token reaching the application layer with
alg: nonein the header. - A sudden valid session following a burst of authentication failures, which can indicate a successful offline secret brute force.
- Signature algorithm mismatches between the algorithm an application is expected to issue and the algorithm present in incoming tokens.
- Unusual privilege or role claims appearing on sessions for accounts that have historically held standard permissions.
Closing Thoughts
JWT is a sound authentication mechanism when implemented correctly, but it shifts a significant share of security responsibility onto the server's validation logic. The moment that logic trusts anything the client provides about how its own token should be verified, including the algorithm field, the token stops protecting anything. Testing for alg: none handling, weak HMAC secrets, and algorithm confusion remains one of the highest value checks in any web application security assessment, and enforcing strict server side algorithm pinning remains the single most effective fix across all three.