JSON Web Token (JWT) is a widely adopted open standard (defined in RFC 7519) that offers a compact and self-contained method for securely transmitting information between multiple parties in the form of a JSON object. The key advantage of JWTs is their ability to be verified and trusted due to digital signatures.
JWTs can be signed using different approaches:
By utilizing a secret with the HMAC algorithm or
By using a public/private key pair with RSA or ECDSA algorithms.
While JWTs have the capability to be encrypted to provide confidentiality, we will primarily focus on the usage of signed tokens. Signed tokens ensure the integrity of the claims present within them, verifying that the token has not been tampered with during transmission. In contrast, encrypted tokens serve to conceal claims from unauthorized parties. When a token is signed using a public/private key pair, the signature acts as proof that only the entity possessing the private key has endorsed it.
By utilizing JWTs, applications can securely transmit information between parties while ensuring data integrity and authenticity. The compact format of JWTs makes them easily transferable across different systems and platforms. Whether it's for authentication, authorization, or exchanging information, JWTs provide a flexible and reliable solution for secure communication.
JSON Web Token Structure
In a JWT, the syntax is divided into three parts separated by dots ('.'). Each part represents a specific section of the token:
const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
Let's understand it in detail.
The header contains information about the algorithm used for signing the token and the token type. In this example, the header is a Base64Url encoded JSON object with the following properties:
alg: The algorithm used for signing the token (in this case, "HS256" indicating HMAC-SHA256).
typ: The type of the token, which is typically "JWT".
The payload contains the actual data or claims encoded in the token. It is also a Base64Url encoded JSON object with various properties specific to the application or use case. In the above example, the payload includes the following claims:
sub: Subject, representing the identifier of the token's subject.
name: Name of the subject.
iat: Issued at, representing the timestamp when the token was issued.
The JSON Web Token (JWT) specification defines three types of claims: Registered claims, Public claims, and Private claims. Let's recreate the explanation for each type:
1. Registered claims: These are a set of predefined claims that are not mandatory but recommended. They provide a set of useful and interoperable claims. Some of the commonly used registered claims include:
iss (issuer): Identifies the issuer of the token, typically the entity that issues the JWT.
exp (expiration time): Defines the expiration time of the token. After this time, the token should not be accepted.
sub (subject): Represents the subject of the token, typically an identifier for the user or entity the token belongs to.
aud (audience): Specifies the intended audience for the token, i.e., the recipients or the system that should accept the token.
And there are several others, such as iat (issued at), nbf (not before), and jti (JWT ID).
These registered claims provide a standardized way to convey essential information about the token and can be universally understood by JWT consumers.
2. Public claims: These claims can be defined by anyone using JWTs, and they are not registered or predefined by the JWT specification. To prevent naming collisions, it is recommended to define public claims in the IANA JSON Web Token Registry or use a URI that includes a namespace that is collision-resistant. By using unique namespaces or referencing the IANA registry, different parties can define their own claims without conflicts.
Public claims allow developers to include additional information in the token payload that is specific to their application or use case. They provide flexibility and extensibility to JWTs beyond the registered claims.
3. Private claims: These claims are custom claims created to share information between parties that agree on using them. Private claims are neither registered nor part of the public claims defined in the IANA registry. They are specific to the parties involved in the token exchange and are used to convey custom or proprietary information.
Private claims allow organizations or systems to include domain-specific data or application-specific details in JWTs. These claims enable customization and collaboration between trusted parties, as long as they agree on the shared private claims.
The signature is the result of applying a cryptographic algorithm to the encoded header, encoded payload, and secret key. It ensures the integrity and authenticity of the JWT by verifying that it hasn't been tampered with. The signature is specific to the combination of the header, payload, and secret key used during the token generation. It is added as the third and final part of the JWT.
The signature provides a means for verifying the validity of the token, and it is used by the receiving party to ensure that the token has not been modified since it was signed.
Why Use JSON Web Tokens?
JSON Web Tokens (JWT) offer several benefits compared to Simple Web Tokens (SWT) and Security Assertion Markup Language Tokens (SAML). Here are the advantages of using JWT:
Compact and Efficient: JSON is less verbose than XML, resulting in a smaller token size when encoded. This makes JWT more compact than SAML, making it an ideal choice for passing tokens in HTML and HTTP environments. The reduced size contributes to improved network efficiency and reduced overhead.
Versatile Security Options: While SWT can only be symmetrically signed using a shared secret and the HMAC algorithm, JWT and SAML tokens can utilize a public/private key pair in the form of an X.509 certificate for signing. This flexibility allows for stronger security options with JWT, making it more adaptable to different security requirements.
The simplicity of Signing: Signing XML with XML Digital Signature without introducing security vulnerabilities can be complex. In contrast, signing JSON is straightforward and less prone to introducing obscure security holes. JWT's simplicity in signing and verifying tokens makes it easier to implement and maintain secure token-based authentication.
Natural Object Mapping: JSON parsers are widely available in most programming languages, and JSON objects can be easily mapped to native data structures or objects in those languages. On the other hand, XML does not have a natural document-to-object mapping, making it more cumbersome to work with SAML assertions. The native support for JSON in programming languages simplifies the processing and handling of JWT tokens.
Widely Used and Supported: JWT is extensively used at an internet scale and has gained significant adoption. It has become a popular choice for token-based authentication and authorization in various scenarios. The broad usage of JWT emphasizes its compatibility and ease of integration across different platforms and systems, including mobile devices.
These advantages make JWT a preferred choice for secure and efficient token-based authentication in web applications and services.
When to use JSON Web Tokens?
JSON Web Tokens (JWT) are useful in various scenarios. Here are some situations where JWTs can be applied effectively:
Authorization: JWTs are commonly used for authorization purposes. Once a user is authenticated and logged in, subsequent requests can include the JWT in the authorization header or as a parameter. This allows the user to access routes, services, and resources that are permitted based on the claims encoded in the JWT. JWTs are particularly useful for implementing Single Sign-On (SSO) functionality, where a user can authenticate once and then access multiple applications or services across different domains without the need for repeated logins.
Information Exchange: JWTs serve as a secure means of transmitting information between parties. Due to their ability to be signed using public/private key pairs, JWTs provide assurance that the sender is authentic and can be trusted. By verifying the signature using the header and payload, the recipient can ensure that the content of the token has not been tampered with during transmission. This makes JWTs suitable for scenarios where data integrity and authenticity are crucial, such as transmitting sensitive information between different systems or services.
Statelessness and Scalability: JWTs are stateless tokens, meaning the server does not need to store any session data. This statelessness makes JWTs highly scalable, as they can be easily validated and processed without the need for server-side storage or session management. This characteristic makes JWTs ideal for distributed and microservices architectures where scalability and performance are critical.
Cross-Domain Usage: JWTs can be used across different domains or systems. The token carries the necessary information within its payload, enabling secure communication and interoperability between various services or applications. JWTs can facilitate seamless integration and data exchange between different domains, making them suitable for distributed environments.
By using JWTs, developers can implement secure and efficient authentication and data transmission mechanisms in a variety of applications, services, and architectures.
Where to Store JSON Web Tokens?
When it comes to storing JSON Web Tokens (JWTs), there are three primary options available:
Each option has its own advantages and disadvantages. Let's explore them in detail:
Storing JWTs in cookies allows the browser to automatically include the token in same-site requests, which simplifies handling on the server side. However, using cookies for JWT storage poses a vulnerability to Cross-Site Request Forgery (CSRF) attacks.
To protect against CSRF, it is recommended to set a cookie with the SameSite attribute set to "true". This attribute ensures that the cookie is sent only with same-site requests, mitigating the risk of unauthorized requests from other domains.
Automatic inclusion in same-site requests.
Availability of the same token across multiple tabs of the application.
Vulnerable to XSS attacks.
Need to manually attach the token in the request header when using protocols like OAuth 2.0.
Storing JWTs in localStorage does not automatically send the token with each request. Therefore, you need to implement a mechanism to include the token in the request header for every URL. The advantage of using localStorage is that it is not vulnerable to CSRF attacks.
Not vulnerable to CSRF attacks.
The same token is available across multiple tabs of the application.
Vulnerable to XSS attacks.
Requires implementation of a mechanism to include the token in requests.
3. Session Storage
Similar to localStorage, sessionStorage does not automatically send the token with requests. However, the difference is that sessionStorage is limited to a single tab, and the session data is destroyed when the tab is closed. This makes it less suitable for features like "remember me." However, sessionStorage can be useful in scenarios where multiple logins are needed within a single browser.
Not vulnerable to CSRF attacks.
Easy implementation of multiple logins within one browser.
Vulnerable to XSS attacks.
Session data is destroyed when the tab is closed.
Choose the storage mechanism that aligns with your specific requirements and implement additional security measures to ensure the integrity and confidentiality of the tokens.