# JSON Web Token

## Summary


JSON is a data format commonly used in web applications. JSON Web Token (JWT) is a mechanism that brings **security to JSON data**. 

JSON grew in adoption from the mid-2000s. This influenced the adoption of JWT. Compared to alternatives such as XML or SAML, app developers found JWT easier to implement and use. JWTs are less verbose and more secure. By the late 2010s, JWTs were widely used in the world of cloud computing and microservices. 

JWT is available in two formats: JSON Web Signature (JWS) and JSON Web Encryption (JWE). JWS offers protection against data tampering (integrity). JWE prevents others from reading the data (confidentiality). Moreover, developers have a choice of various keys and algorithms to protect JSON data in either of these formats.

IETF has published the main RFCs that cover JWTs. There are also plenty of open source implementations in many languages.

## Discussion

### How does JWT bring security to the web?

Consider an application consisting of many services exposed to clients via APIs. We certainly don't want clients to authenticate with each service. Authentication is done by a specific service or server. Once authenticated successfully, the client should be able to access any of the services without further authentication. This is where JWTs can help. 

For example, in AWS, Amazon Cognito does authentication. An authenticated client is issued a JWT. Whenever the client makes an API request, it presents this token. The API gateway validates the token before allowing the client to access the requested service. Thus, all relevant information is within the JWT. The API gateway need not contact the authentication server to determine if the client should be allowed access. 

For authorized access, privileges can be set within the token. For example, the name-value pair `admin:true` could be set to allow deletion of records and other admin operations. Moreover, such privileges are set when the token is issued. The client or third-party hackers can't tamper with the token. 


### What are some use cases where JWT can be used?

The common use case of JWTs is **authorization**. For example, APIs often require an access token and this could be a JWT. Systems implementing Single Sign-On (SSO) can issue JWTs to allow the user to access various services. 

Assume a server authenticates a user and issues a single-use short-lived JWT. User uses this token to download a file from another server. In this example, JWT temporarily authorizes the user to download a protected resource. In microservices architecture, JWTs are used to pass authorization across services. OAuth 2.0 access tokens are JWTs. 

JWTs can be used for **authentication**. For example, in OpenID Connect (OIDC), users login with a JWT. Another example is to authenticate a SOAP request with JWT rather than SAML2 assertion. In Oracle Cloud, API gateway authenticates an API client based on the JWT it receives. Once validated, claims in the token are used to authorize the client. JWTs can be used to authenticate SPAs. 

Due to its protection against tampering and snooping, JWTs are a means to **exchange information securely**. 


### What are the main components of a signed JWT?

A JWT has two essential components: header and payload. In practice, JWTs are signed, that is, they include a signature. This is what we call *JWS*. Thus, the three main components of a signed JWT are:  

    + **Header**: Specifies the type of token (typically `JWT`) and the algorithm used.
    + **Payload**: The main content of the token that includes a set of claims.
    + **Signature**: This is computed from header and payload to protect the integrity of the token.Header and payload are JSON objects. However, these are not transmitted as such. They are Base64-URL encoded, which is similar to Base64 encoding except that characters special to URLs are replaced: `+` becomes `-`, `/` becomes `_`. 

Signature is computed as `BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload)` and then Base64-URL encoded. 

The JWS is constructed by concatenating header, payload, and signature. Period character separates the fields. We can represent this as `BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload) || '.' || BASE64URL(JWS Signature)`. This format of JWS is called *JWS Compact Serialization*. There's also *JWS JSON Serialization* that can have multiple signatures. 


### What are JWT claims and how to specify such claims?

The payload of a JWT has a set of claims. A claim is a name-value pair. It states a fact about the token and its subject such as username or email address. Claims are not mandatory since JWTs are meant to be compact. It's up to applications to include claims that matter. 

Some claim names are **registered** with IANA. Examples include "iss" (issuer), "sub" (subject), and "aud" (audience). Some registered claim names are of datetime type: "exp" (token expires at this time), "nbf" (token can't be used before this time), and "iat" (time when token was issued). For example, `"exp":1300819380` says that the token expires at the specified timestamp. 

There are also **public** or **private** claim names. These are application specific and their semantics are agreed between producer and consumer of the token. Public names must be collision-resistant. For example, a name based on domain name or Universally Unique IDentifier (UUID) is unlikely to collide with another public name. 


### Is it possible to encrypt the payload in a JWT?

A signed token can be read by anyone. The purpose of signature is to prevent hackers from tampering with the header or payload. Any changes to these would result in a different signature, which the attacker can't create without the secret key. Such tampering would cause a failure during signature verification. 

If the intention is to send sensitive payload, signature alone is inadequate. There's a need to encrypt the payload. This is where JWE format becomes relevant. 

Encryption of content uses symmetric keys. However, these keys need not be shared in advance. They can be generated dynamically and exchanged within JWE. However, the shared symmetric key is encrypted using asymmetric private-public key pair. 

It's also possible to do both, such as a JWS within a JWE or vice versa. Such as token is called **Nested JWT**. For example, we could create a JWS as usual and encrypt it. This then becomes the encrypted payload of a JWE. A simpler approach is to use only encryption algorithms mentioned in JWA since they also provide integrity protection. 


### Which are the various algorithms supported by JWT?

Both symmetric and asymmetric algorithms are supported for signing and encrypting tokens. In fact, this support for a variety of algorithms is perhaps one reason for the wider adoption of JWTs. 

For JWS, at the minimum, an implementation should support HMAC using SHA-256. This uses a shared symmetric key. For the "alg" header parameter, its value is "HS256". Apart from HMAC for signature, we can have digital signatures using asymmetric keys with RSASSA-PKCS1-v1\_5, ECDSA, or RSASSA-PSS. Signing is done with the private key. Verification happens with the public key. 

For content encryption in JWE, at the minimum, an implementation should support A128CBC-HS256 and A256CBC-HS512. A128CBC-HS256 does AES encryption in CBC mode with 128-bit IV value, plus HMAC authentication using SHA-256 and truncating HMAC to 128 bits. Encryption key is called Content Encryption Key (CEK). 

The CEK itself is encrypted using other algorithms and included in the JWE. Some of these are RSA-OAEP, A128KW, ECDH-ES, ECDH-ES+A128KW, and more. It's also possible to use a shared symmetric key as CEK. 


### Can I use JWTs as a replacement to session objects?

With session objects, server maintains the state about each logged-in user, who gets a session ID via a HTTP cookie. Subsequent requests contain the session ID. Server uses it to retrieve the session object and serve the client. Thus, stateless HTTP calls are strung together into a stateful session. 

With JWTs, server doesn't need to store session state. All relevant information is contained in the JWT. This also makes it convenient to deploy on a distributed architecture. One server might issue the JWT. Subsequent client requests could be served by another server via a load balancer. 

While JWTs seem attractive, a JWT takes more space compared to a session ID. Even without session objects, most client requests will still need access to the database, implying that JWTs don't improve performance. Most web frameworks automatically sign session cookies, implying that signing a JWT isn't really an advantage. JWTs stored on local storage can be less secure. We can't invalidate individual JWTs or deal with stale claims in the token. For these reasons, use of JWTs as an alternative to session IDs is not recommended. 


### Which are the known vulnerabilities of JWT?

Most attacks on JWT are due to implementations rather than its design. 

Some early implementations used the "alg" value in header to verify the signature. An attacker could set the value to "none"; or change "RS256" to "HS256" and use the public key as the shared secret key to generate a valid signature. Based on the "alg" value, the consumer would skip verification or incorrectly find that the signature is valid.  

Brute force attacks on HS256 are simple if the shared secret key is too short. Another possible oversight in implementations is not verifying the claims or not including adequate claims. For example, a token without audience is issued to Org1 but the attacker could present the same token to Org2 can gain access if that username exists in both organizations. 

Don't store sensitive information in JWS, that is, in unencrypted form. Don't also assume that encrypted data can't be tampered with. 

RFC8725 details many vulnerabilities and best practices to overcome the same. 


### What are some best practices when using JWT?

Pick strong keys. These are often long and created by cryptographic-quality pseudo-random number generators (PRNGs). Don't use human-readable shared secret keys. For federated identity, or when third-party services are involved, it's inconvenient and unsafe to use a shared secret. Instead, use public-private key pair. 

Don't rely on the header to select the algorithm for verifying the signature. Use libraries that allow for explicit selection of algorithm. 

It's a good practice to verify applicable claims. For example, verify that token has not expired. In AWS we might verify that the audience claim matches the app client ID created in the Amazon Cognito user pool. Where nested tokens are used, verify signature on all tokens, not just on the outermost token. 

Use different validation rules for each token. Avoid key reuse for different tokens. For example, we could use different secret keys for each subsystem. Using "kid" claim, we could identify which secret key is used by the token. 

Keep the lifetime of tokens short, says for a few minutes or hours. In addition, we could include a nonce in the token to prevent replay attacks (which is what OpenID Connect does). 


### Could you mention some resources concerning JWT?

IETF documents relevant to JWT include RFC7519: JSON Web Token (JWT), RFC7515: JSON Web Signature (JWS), RFC7516: JSON Web Encryption (JWE), RFC7517: JSON Web Key (JWK), RFC7518: JSON Web Algorithms (JWA), and RFC7797: JSON Web Signature (JWS) Unencoded Payload Option. 

IANA's JOSA page contains lists of registered header parameter names and algorithm names. 

Peyrott's JWT Handbook is worth reading. This book includes JavaScript code with explanations, which is a useful reference for developers. Another useful reference is a JWT cheatsheet published by Pragmatic Web Security.

For a simpler approach, developers can use third-party JWT libraries. These are available in many languages. Lists of JWT implementations are available at OpenID and at jwt.io. 

Site jwt.io offers a debugger to paste a JWT and view its decoded form. Optionally, signature verification is possible if you include the secret key. 

## Milestones

Apr  
2001

Douglas Crockford and Chip Morningstar send out what is historically the first JSON message. Since JSON is nothing more than plain JavaScript, Crockford himself states that probably this message format was in use as early as 1996. In July 2006, Crockford describes in RFC 4627 the JSON format and its MIME media type `application/json`. 

2005

From the mid-2000s, the growth of Web 2.0 and the use REST APIs in web apps lead to wider adoption of JSON. The term AJAX itself is coined in 2005 but it's clear than AJAX is not limited to XML: JSON can be used instead. By late 2000s, with the increasing use of JSON on the web, it's recognized that standards are needed to offer security services in JSON format. 

Dec  
2010

As an Internet-Draft, **JSON Web Token (JWT)** is published at IETF. This document goes through multiple revisions, with the final draft revision appearing in December 2014. In May 2015, it becomes RFC7519.

Sep  
2011

At IETF, the **Javascript Object Signing and Encryption (JOSE) Working Group** is formed. For better interoperability, the group aims to standardize the mechanism for integrity protection (signature and MAC), encryption, the format of keys and algorithm identifiers. 

May  
2015

IETF publishes **RFC7519: JSON Web Token (JWT)** as a Proposed Standard. Other relevant RFCs are also published the same month: RFC7515: JWS, RFC7516: JWE, RFC7517: JWK, RFC7518: JWA. 

Jul  
2015

On Auth0 blog, a new logo for JWT is announced along with a redesigned website at jwt.io. The blog post also notes that interest in JWT has been increasing since 2013. By now, there are 972 JWT-related GitHub repositories and 2600+ threads on StackOverflow. It's also claimed that,

> If you use Android, AWS, Microsoft Azure, Salesforce, or Google then chances are that you are already using JWT.

Feb  
2016

IETF publishes **RFC7797: JSON Web Signature (JWS) Unencoded Payload Option** as a Proposed Standard. Typically, JWT payload is Base64-URL encoded. This document gives the option of skipping this encoding step. For example, a payload `$.02` is sent as it is rather than sending its encoded form of `JC4wMg`. Header parameter "b64" controls the use of this option and "crit" parameter facilitates backward compatibility. 

Jul  
2019

JWTs stored in local or session storage are vulnerable to XSS attacks. On the other hand, JWTs stored in cookies are vulnerable to CSRF attacks. One blogger proposes to mitigate the risks by storing the signature in a HttpOnly, SameSite, Secure cookie. JWT header and payload are in local storage and transferred in HTTP header as a bearer token. The application server has to assemble the complete JWT from its parts. HttpOnly cookies are inaccessible to JavaScript.