May 31, 2026/Lucas Brandt/8 min read
JWTs Aren't Actually the Hard Part
JWTs look intimidating until you decode one. The token itself is usually the easy part. The real complexity comes from revocation, permissions, trust, and everything that happens after a token is issued.
JWTs are one of those technologies that seem far more complicated than they really are. At first they seem intimidating, a few hundred seemingly random characters seperated by three periods. However, they're actually really simple to understand. The problems start with all of the surrounding infrastructure around JWTs. Things like:
- Revoking access
- Handling refresh tokens
- Managing permissions
- Supporting multiple services
- Dealing with users who somehow have six active sessions across four devices and one browser tab from three weeks ago
- And more
The token itself? That's the easy part, so let's take a look at one.
Most JWTs Are Just JSON With Extra Steps
Here's an example JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NSIsInJvbGUiOiJhZG1pbiJ9.abc123signaturexyz456
I bet you think that's encrypted right? Wrong, and you'll want to remember that. Storing non-public information within a JWT is a common security vulnerability that happens all the time.
A JWT is typically made up of three simple pieces: Header.Payload.Signature
Three periods seperate the different sections of a JWT. The first section is a header that contains metadata about the token. The second section is the payload, which contains the actual data (called claims). The final section is a cryptographic signature that let's other systems check if the data stored within the JWT has been modified by an outside source.
That's the entire structure, it really is that simple. The thing that surprises most developers is how readable JWTs are once they're decoded. Whether it is User IDs, email addresses, roles, expiration timestamps, etc, it's often just ordinary JSON.
The payload is generally visible to anyone holding the token, the signature proves the data hasn't been altered, and most importantly, it does not hide the data. That distinction sounds small until somebody accidentally stores information inside a token that was never meant to be public.
The Payload Is Visible
A lot of developers hear "signed token" and assume that means secured data. Those are two very different things.
Consider this payload:
{
"sub": "12345",
"email": "user@example.com",
"role": "admin",
"exp": 1756425600
}Anyone holding the token can usually decode and read the data as JSON like the above example. The signature exists to prevent tampering, but it does not hide the contents. This sounds obvious once you've heard it, yet it's responsible for an incredible number of security mistakes.
This is how API keys, internal system identifiers, or even password hashes can end up in JWTs. The presumption that the payload data is secured or encrypted.
A good rule of thumb is:
If you're uncomfortable seeing it in browser developer tools, don't put it in a JWT payload.
The Part Everyone gets Wrong
Most JWT articles focus on the token itself. That being said, the token is almost never the actual issue. For instance, imagine a user logs in successfully. The authentication service verifies their credentials and generates a JWT to preserve their session. The frontend stores this token locally and attaches it to future network calls (most likely in an authentication header). The API can then validate the JWT via it's signature and extracts the user's data (claims).
The problem is in reality things never stay that simple. Maybe the user's role changes, maybe the admin has to disable their account, or worst case a company discovers a compromised login. The JWT itself hasn't changed, the problems involving it have.
This is where we all discover that authentication and authorization are much larger topics than JWTs themselves. The token is usually just carrying information from one system to another. The difficult part comes from deciding how that information or data should be trusted over time.
Why JWTs Feel Simpler Than They Are
One of the biggest selling points of JWTs is stateless authentication. You don't need to constantly hit API endpoints or make database calls if the necessaryy session information is stored within a JWT.
In distributed systems, the benefits of that are priceless. API gateways, microservices, serverless environments, and servers hosted across the globe can all use a simple JWT to manage authentication instead of constant expensive session calls.
The problem is that statelessness is an incredible concept on paper, while being very difficult to architect well in a production enviornment.
Suppose a token is valid for eight hours. What happens if you need to revoke access after two? What happens if permissions change after the token has already been issued? What happens if you need to invalidate thousands of active sessions immediately?
Eventually many systems start introducing additional infrastructure to solve those problems such as revocation lists, session registries, token blacklists, and refresh token databases. Some teams spend months migrating away from sessions only to later rebuild portions of their old session management system. While there's nothing wrong with that, it's just a reminder that complex code doesn't just disappear, it simply gets moved around.
Security Mistakes That Keep Showing Up
JWTs aren't inherently dangerous, but a few mistakes appear often enough to be worth discussing. We've touched on this before, but it still bears mentioning again. The first is treating the payload like secure storage. Developers hear "signed token" and assume the contents are protected. Then someone stores API credentials, internal identifiers, or other sensitive information inside the payload. Since JWT payloads are generally readable, that information becomes exposed to anyone holding the token.
Another common issue is overly long token lifetimes. A stolen token with a 15 minute expiration window is problematic. A stolen token that's valid for six months is a completely different conversation entirely. While neither is particularly good, you always want to minimize the amount of time a potential attacker has to access to your systems.
Key management is another area that tends to get ignored until it becomes a fire that needs putting out. Teams often generate a signing secret during the initial setup of their JWT authentication system, forget about it for several years, then discover nobody remembers where it came from or how many systems depend on it. Plus, like all secrets, you need to be rotating them to minimize impact if they are ever stolen.
The technology isn't usually what causes these vulnerability incidents. Operational and managerial decisions are. That's true for JWTs just like it's true for most security systems.
When I'd Use Something Simpler
There's a large tendency in software engineering to assume newer or more flexible solutions are automatically better, and JWTs are no exception to this.
If you're building a traditional web application with a single backend and straightforward authentication requirements, http secured session cookies are almost always the right choice. They are simple to understand, and far easier to manage than a full fledged JWT authentication system. Most importantly, they probably solve the problem you have.
JWTs start becoming much more attractive when requests need to move across multiple services, systems need to independently verify identity, or scaling session storage becomes a genuine concern.
The important question isn't whether JWTs are good. The important question is whether they actually solve a problem you have. A lot of the time they are going to be overkill for your simple web application. Make sure when you use a new technology that it solves a real problem you have
Debugging JWTs Is Usually Easier Than Debugging Authentication
One thing JWTs have going for them is visibility. When something breaks, you can usually inspect the token directly and learn quite a bit. Is the expiration time wrong? Did the issuer change? Was the token signed with the expected algorithm?
These issues are surprisingly common. Actual cryptographic failures are relatively rare. Most JWT bugs turn out to be configuration issues, data (claims) mismatches, environment differences, or simple misunderstandings about what the token contains. That's good news because configuration problems are a lot easier to fix than broken cryptography.
The Real Lesson
Understanding JWTs isn't as difficult as you think. Once you decode one and learn about the relationship between the data and the signature, most of the mystery disappears.
What's harder is understanding the architecture around them: How tokens are issued, How they're refreshed, How permissions change, How access gets revoked, How multiple services establish trust, How authentication decisions evolve after a token has already been created.
Those are the questions that make authentication systems complicated, and the JWT is usually just along for the ride.