JWT (JSON Web Token) is a widely used technology for user authentication and information exchange in today's web applications and APIs. Although I thought I knew about JWT, which is commonly used in practical work and frequently appears in interview questions, I found myself unable to confidently answer when a junior developer asked me what it was.
Through this blog post, I'll take another look at JWT to understand it more precisely, starting from why it came into existence, how it works, and what advantages and disadvantages it has.
Authentication Methods Before JWT
Traditionally, the main authentication method for web applications was session-cookie based authentication. The operating principle of this method is as follows:
- The user attempts to log in.
- The server verifies if the information is valid, and if it is, stores the user's information in server memory or a database (hereinafter 'session store'). At this time, a unique ID (session ID) is generated that can identify each user.
- The server sends this session ID to the client, and the client stores this ID in a cookie.
- Subsequently, the client sends the session ID stored in the cookie with every request to the server.
- The server compares the received session ID with the information in the session store to identify the user and verify the authentication status.
This method is simple to implement and intuitive, but the server must create and manage a session store. As the number of users increases, the load on the session store increases, which can lead to bottlenecks and make it difficult for the server to handle.
Additionally, because values are sent in cookies, there are cross-domain issues due to CORS policies. For clients other than web browsers, such as mobile apps or other types of clients, managing cookies directly can be cumbersome or inappropriate, which becomes a constraint when considering client diversity.
The Evolution of the Web and the Need for New Authentication Methods
From the mid-2000s, the web moved beyond simple informational websites into the era of web services. This change brought new problems to existing authentication methods.
- Third-party service integration: Users want to log in to various services using accounts from Facebook, Google, etc.
- API authentication: Beyond simply accessing websites, authentication is also needed when exchanging data through APIs.
- Cross-domain problems: Since cookies are only valid in the same domain by default, problems arise when providing services across multiple domains or when authentication is needed between multiple domains.
To solve these problems, OAuth, which is widely used today, emerged. OAuth evolved through several stages to OAuth 2.0, which adopted a method of verifying user permissions through tokens.
The issue was that while OAuth 2.0 defined the authentication flow, it did not clearly define the format of the tokens actually used. As a result, each service used its own token format, which caused another form of inefficiency.
SAML
Before API-based authentication became popular, there was already a need for Single Sign-On (SSO) in corporate environments. SAML is an XML-based authentication and authorization standard developed by OASIS in 2002. It was mainly used to implement SSO in corporate environments.
However, SAML was large in file size as it was in XML format, and parsing and signature verification were complex. It was not suitable for REST methods.
Birth of JWT (JSON Web Token)
Based on the background mentioned earlier, JWT was developed in the early 2010s by the OAuth working group of the IETF (Internet Engineering Task Force). JWT is an open standard (RFC 7519) that defines a compact and independent method for securely transmitting claims between two entities.
With the emergence of JWT, standardized tokens appeared, and being JSON-based, they had a smaller data size than XML (SAML), making them more efficient for transmission in HTML and HTTP environments. Additionally, JWT contains all necessary information itself, so the server doesn't need to store separate session information.
Based on the background mentioned earlier, JWT was developed in the early 2010s by the OAuth working group of the IETF (Internet Engineering Task Force). JWT is an open standard (RFC 7519) that defines a compact and independent method for securely transmitting claims between two entities.
The emergence of JWT solved the following problems:
- Standardized tokens: The token format was standardized, greatly improving interoperability between services.
- Efficient data transmission: Being JSON-based, it has a much smaller data size than the existing XML (SAML) method. Therefore, data can be exchanged more efficiently in HTML and HTTP environments.
- Server statelessness: JWT contains all necessary information (user identification, permissions, etc.) in the token itself. Therefore, the server doesn't need to separately store and manage user session information.
Structure of JWT
JWT consists of three parts: Header, Payload, and Signature, separated by .
as a delimiter.
xxxxx.yyyyy.zzzzz
Header
The header of JWT includes claims (information) about JWT itself and defines the algorithm used, whether it's signed/encrypted, and how to parse it.
{
"alg": "HS256",
"typ": "JWT",
"cty": "JWT"
}
Note: typ
and cty
fields are optional
- Required header information
- alg: The algorithm used for signing/encrypting the JWT. For non-encrypted JWTs, the value is set to none.
- Optional header information
- typ: The media type of JWT. Used to distinguish when mixed with other JWT header objects. Usually set to JWT, but rarely used in practice.
- cty: Content type. Not set if the payload includes general claims and data. Set to JWT if the payload is a nested JWT, indicating that additional processing is needed. Nested JWTs are rare, so cty is also rarely used.
Payload
Includes the information to be contained in the token. These pieces of information are called claims.
{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"iat": 1516239022
}
Registered Claims
These are claims already defined in the JWT specification. They are not mandatory but are a recommended set.
- iss (issuer): A unique string or URI identifying the entity that issued the JWT.
- exp (expiration): A number in POSIX format indicating when the JWT expires.
- sub (subject): A unique string or URI identifying the subject that the JWT contains information about.
- aud (audience): A string, URI, or array identifying the intended recipient of the JWT.
- nbf (not before): A number in POSIX format indicating the starting point when the JWT becomes valid.
- iat (issued at): A number in POSIX format indicating when the JWT was issued.
- jti (JWT ID): A unique identifier string for the JWT.
Public and Private Claims
- Public: Publicly defined claims to prevent collisions among JWT users.
- Private: Claims used by agreement between the server and client. Information such as user ID, name, permissions, etc. is included here.
Signature
The signature is created by encrypting the encoded values of the header and payload along with the server's secret key using the algorithm specified in the header. For example, if using the HMAC SHA256 algorithm, the signature is created as follows:
HMACSHA256(
Base64UrlEncode(header) + "." + Base64UrlEncode(payload),
secret
)
This signature serves to ensure the integrity of the token.
Combining
Now, by encoding the three values with Base64Url and combining them into a single string through delimiters (.
), a JWT is created.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30
JWT Authentication Process
Now that we know what information JWT contains and its structure, let's look at how it actually works in sequence.
Note
The process below is explained based on the HS256 (symmetric key) algorithm, so the process may differ when using other algorithms.
- When a user successfully logs in, the server creates a JWT containing the user's information and delivers it to the client.
- The client (browser) stores the issued JWT in a storage (local storage, session storage, cookies, etc.).
- For subsequent requests to the server, the JWT is included in the header.
- The server verifies the signature of the received JWT to check the validity and whether it has been tampered with.
- Once verification is complete, the server trusts the user information contained in the token and processes the request.
How is the signature verified?
When the server receives a JWT (xxxxx.yyyyy.zzzzz
) from the client, it follows the following procedure:
-
Token separation: The server first separates the received JWT into three parts: header, payload, and signature, based on
.
. -
Header and payload preparation: The separated header and payload are prepared. These two parts are in Base64Url encoded state, just as when creating the token.
-
Signature recreation: The server recreates the signature using the secret key that only it safely keeps.
javascriptHMACSHA256( Base64UrlEncode(header) + "." + Base64UrlEncode(payload), secret )
-
Signature comparison: The server compares the signature it directly created with the existing signature included in the JWT sent by the client.
Advantages and Disadvantages of JWT
Advantages
- Stateless and scalability: Since the server doesn't store the user's state, it reduces server load and makes it easy to scale horizontally.
- Platform independence: Being token-based, it works the same across various platforms and devices such as mobile, web, desktop, etc.
- Security: The token's tampering can be verified through the signature.
Disadvantages
- Token length: The token is longer compared to a session ID. This can cause a slight overhead in network traffic.
- Cannot store security-sensitive information: The payload is only encoded in Base64, not encrypted. Anyone can decode it and check the contents, so sensitive information like passwords should not be included.
- Difficulty in invalidating tokens: Once a JWT is issued, it remains valid until its expiration time. Since the server doesn't manage the state, it's difficult to forcibly invalidate a token even if it's stolen.
Conclusion
JWT, which I had been using simply "because everyone else does." But to clearly explain this technology to someone else, I took the time to revisit it from its birth background to its operation method. I hope this article provides an opportunity for others reading it to learn about JWT again.