Why JWTs Can Be Risky

Lakin Mohapatra
6 min readNov 3, 2024

--

As a developer, I have used JSON Web Tokens (JWTs) many times. At first, they seemed like the best solution for authentication in my web applications — easy to use, stateless, and flexible. But through my experience, I learned that while JWTs have advantages, they can also create serious security problems if not used carefully.

In this article, I’ll share my experience with JWTs, the issues I faced, and what I learned to help you avoid the same mistakes.

What is JWT, and Why Do Developers Like It?

At its core, a JWT is a compact, self-contained way to transmit information between two parties securely. It’s often used for authentication and authorization in web applications.

A JWT consists of three parts:

  1. Header: Contains metadata like the signing algorithm (HS256 or RS256).
  2. Payload: Stores data (claims), such as user ID, roles, or permissions.
  3. Signature: Verifies that the payload hasn’t been tampered with.

Here’s a simple JWT example:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

I remember the first time I implemented JWTs in an application. It felt great to handle authentication without relying on session storage! However, I soon discovered that there was more to JWTs than meets the eye.

1. JWT Payloads Are Not Encrypted

Developers often believe that because JWTs are secure, the data in the token is hidden.

But JWTs are not encrypted by default. The payload is encoded in Base64URL format, which anyone can decode. This means that if your JWT contains sensitive data, an attacker can easily read it.

In one project, I included sensitive user information in the JWT payload, thinking it would be safe. To my horror, I learned that anyone with access to the token could decode it and see everything. This experience taught me a hard lesson about data exposure.

Solution:

  • Always use TLS (HTTPS) to protect the token in transit.
  • If the payload contains sensitive information, consider using JWE (JSON Web Encryption) instead of a regular JWT to encrypt the contents.

2. JWTs Can’t Be Easily Revoked

Developers assume logging out will immediately invalidate a JWT.

JWTs are stateless and cannot be revoked once issued. Even if a user logs out, the token remains valid until it expires, meaning an attacker who steals the token can continue to use it.

I once had a user who logged out of the application, but they remained able to access protected resources for hours. This created confusion and potential security risks, making it clear that I needed a better strategy for session management.

Solution:

  • Use short-lived tokens (e.g., 5–10 minutes).
  • Implement a refresh token system. The refresh token can be revoked, forcing the user to reauthenticate once the short-lived token expires.

3. JWTs Can Lead to Stale Data Issues

Developers believe that JWTs automatically update if user roles or permissions change.

But in reality — Once a JWT is issued, its payload is static. If a user’s role or permission changes (e.g., from admin to user), the old JWT still reflects the outdated role until it expires.

I experienced this firsthand when a user’s permissions changed due to an internal policy update, but they retained access until their JWT expired. This incident highlighted how critical it is to manage user roles effectively in JWT-based systems.

Solution:

  • Keep JWTs short-lived to minimize the impact of stale data.
  • Use token versioning: Track token versions in your database. If a user’s role changes, invalidate their current token by changing their version, forcing them to reauthenticate.

4. JWTs Are Vulnerable to Replay Attacks

Misconception: Once a JWT is signed, it’s immune to attacks.

Reality: JWTs are vulnerable to replay attacks, where an attacker intercepts a token and reuses it to make valid requests as the user.

In a project where I was using JWTs for an API, I realized that if an attacker intercepted a valid token, they could resend it and make unauthorized requests. This realization was a wake-up call about the importance of securing tokens during transmission.

Solution:

  • Always use HTTPS to protect JWTs during transit.
  • Implement one-time tokens or nonces for critical actions like payments, ensuring the token cannot be reused.
  • Consider using short expiration times to reduce the replay window.

5. Weak Secrets Make JWTs Easy to Crack

Developers assume that A simple secret is enough to secure a JWT.

Reality: If you use a weak secret for signing your JWT (e.g., a short or common password), an attacker can brute-force the secret using tools like Hashcat. Once the secret is known, the attacker can forge valid JWTs.

During one project, I initially used a simple secret for my JWT signing. Later, I found out that it could be cracked in just a few hours. This pushed me to research and implement stronger cryptographic practices.

Solution:

Use complex secrets of at least 256 bits when using HMAC algorithms like HS256. Alternatively, use asymmetric algorithms like RS256, where the secret is a private key that only the server knows.

6. Algorithm Confusion Can Lead to Token Forgery

Developers believe that All algorithms in JWT are equally secure.

Reality: JWTs allow specifying the algorithm used for signing in the header. If the server isn’t configured properly, an attacker can change the algorithm from RS256 (which requires a private key) to none or HS256 (which uses a symmetric key), effectively bypassing signature verification.

I encountered this issue in an early project when I didn’t enforce a specific algorithm. An attacker could have easily manipulated the algorithm and gained unauthorized access to protected routes.

Solution:

Always enforce specific algorithms on the server (e.g., RS256), and never trust the algorithm provided by the client. Reject tokens with alg: none.

7. JWTs Should Not Be Used for Sessions

There is a common misconception that JWTs are a perfect replacement for traditional session management.

Reality: While JWTs can be used to manage stateless authentication, they are not ideal for long-term sessions due to their revocation and expiration challenges. Traditional session cookies provide a more reliable and secure mechanism for session management.

When I attempted to use JWTs for persistent user sessions, I quickly ran into issues where users remained logged in even after changes to their account status. This led to confusion and potential security risks.

Solution:

For long-term sessions, it’s better to use server-managed sessions with cookies. JWTs are more suited for short-lived, single-use cases like API authorization.

Final Thoughts :

Through my experiences, I have learned that while JWTs offer flexibility and simplicity in certain scenarios, they come with significant risks if misused. By understanding the limitations, keeping payloads minimal, using strong cryptographic practices, and implementing short-lived tokens, you can mitigate many of the risks associated with JWTs.

For persistent session management, consider sticking with traditional server-side sessions or other secure alternatives. Avoiding these pitfalls will not only enhance the security of your applications but also lead to a smoother experience for your users.

Let my journey be a guide, so you don’t have to face the same challenges I did!

References :

https://book.hacktricks.xyz/pentesting-web/hacking-jwt-json-web-tokens

--

--

Lakin Mohapatra
Lakin Mohapatra

Written by Lakin Mohapatra

Software Engineer | Hungry coder | Proud Indian | Cyber Security Researcher | Blogger | Architect (web2 + web 3)

No responses yet