JWT, or JSON Web Token, is one of those technologies that almost every developer uses today. If you have worked with modern web applications, REST APIs, Angular, React, or mobile apps, chances are you have already used JWT.
Yet, if someone asks “How does JWT actually work?”, many developers struggle to explain it clearly.
Why JWT Exists
Before JWT became popular, most applications relied on session-based authentication. When a user logged in, the server created a session and stored it in memory. The browser received a session ID and sent it back with every request. The server then looked up the session data and decided whether the user was authenticated.
This approach worked well for small applications, but it created problems as systems grew. Server memory usage increased, scaling across multiple servers became difficult, and microservices architectures made session sharing complicated. Modern applications needed a solution that did not depend on server-side memory.
JWT was introduced to solve this problem by making authentication stateless.
What JWT Really Is
JWT stands for JSON Web Token. It is an open standard that defines a compact and secure way to transmit information between a client and a server using a JSON object.
In simple terms, a JWT is a digital identity card. After a user logs in successfully, the server gives this card to the client. The client then presents this card with every request, and the server trusts the client based on the information inside the token.
The key idea is that the server does not need to store anything. All the required information travels with the token itself.
Where JWT Is Commonly Used
JWT is most commonly used in applications where the frontend and backend are separate. Single Page Applications like Angular and React, mobile applications, REST APIs, and microservices all rely heavily on JWT. It is also a core part of OAuth2 and OpenID Connect authentication systems.
If your application needs to scale and remain stateless, JWT naturally fits into the architecture.
Understanding the Structure of a JWT
A JWT always consists of three parts separated by dots. These three parts are the header, the payload, and the signature.
At first glance, a JWT may look like a random string. However, each part has a clear purpose and meaning.
The Header
The header contains metadata about the token. It tells us what type of token it is and which algorithm is used to sign it.
A typical header looks like this:
{
"typ": "JWT",
"alg": "HS256"
}
This simply means that the token is a JWT and that it uses the HS256 algorithm for signing. The header is Base64 encoded, not encrypted.
The Payload
The payload contains the actual data, also known as claims. This is where information about the user is stored, such as user ID, email, role, and token expiry time.
A simple payload example looks like this:
{
"userId": 101,
"role": "USER",
"exp": 1700000000
}
It is important to understand that the payload is not encrypted. Anyone who has the token can decode and read this data. Because of this, sensitive information such as passwords or secrets should never be stored in the payload.
The payload is readable, but it is not meant to be editable.
The Signature
The signature is what makes JWT secure. It is created using the encoded header, the encoded payload, and a secret key or private key.
The purpose of the signature is simple. If someone tries to modify the payload, the signature will no longer match. When the server verifies the token and detects this mismatch, it immediately rejects the request.
This is why JWT is considered tamper-proof. The data can be seen, but it cannot be changed without invalidating the token.
How JWT Authentication Works in Real Applications
When a user logs in, the client sends their credentials to the server. The server validates these credentials and, if they are correct, creates a JWT. This token is then sent back to the client.
The client stores the token, ideally in an HttpOnly cookie for security reasons. From this point onward, every request sent to protected APIs includes the JWT.
When the server receives a request, it verifies the token’s signature, checks whether it has expired, and validates any required claims such as user roles. If everything is valid, the request is allowed to proceed. Otherwise, it is rejected.
This process repeats for every request, without the server needing to store any session data.
JWT Is Not Encryption
One of the most common misunderstandings about JWT is that it encrypts data. JWT does not encrypt anything by default. It only signs the data.
This means that JWT ensures data integrity and authenticity, not confidentiality. If confidentiality is required, JWT must be used over HTTPS or combined with additional encryption mechanisms.
Token Expiry and Refresh Tokens
JWT tokens should not live forever. If a token is stolen, it can be misused until it expires. To reduce risk, access tokens are usually kept short-lived, often lasting only a few minutes.
To avoid forcing users to log in repeatedly, applications use refresh tokens. When an access token expires, the client sends a refresh token to the server, and the server issues a new access token.
This balance between usability and security is a key part of modern authentication systems.
Many Developers Misuse JWT
Most problems with JWT do not come from JWT itself, but from incorrect usage. Common mistakes include storing tokens in insecure places, using very long expiry times, choosing weak secret keys, or placing sensitive data inside the payload.
JWT is powerful, but only when implemented with care.
Final Thoughts
JWT has become the backbone of modern authentication systems. It is simple, scalable, and efficient. However, using JWT without understanding it can lead to serious security issues.
The truth is simple:
JWT is not insecure.
Bad implementation makes it insecure.



Top comments (2)
Recently our system went through a penetration testing exercise carried out by an external party, and one of the “vulnerabilities” they reported was our use of JWT.
We are not using JWT in any improper way and everything is transmitted over HTTPS. Their main complaint was that “nowadays everyone should use JWE instead”. However, many authentication systems still do not support JWE natively, and using it would break an important part of our design: after AWS API Gateway validates the token, we rely on the claims in the backend to enforce fine-grained access to specific resources.
Do you see JWE realistically becoming the standard in the near future?
Personally, I don’t see JWE becoming the default standard in the near future. What I do see is continued use of short-lived signed JWTs over HTTPS, with JWE being used only in cases where claim confidentiality is a real requirement.
In practice, JWE support is still limited, and many architectures rely on readable claims after API Gateway validation for authorization.