This blog is a compilation of various aspects of JSON Web Tokens collected from different sources viz. jwt.io, The JWT Handbook by Sebastián E. Peyrott (Auth0 Inc.) and RFC 7519. My main intention behind writing this blog is to go through it whenever I need to revise this topic.
What is JWT?
According to jwt.io, JWT is an open standard claims representation format that defines a compact way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with HMAC algorithm) or a public-private key pair using RSA.
When to use JWT?
We can use JWTs in the following cases.
When the user logs-in to a website, the authorization server provides him with an access token that can be used to access routes, services and resources. This access token can be a JWT.
Nowadays, JWT is widely used in single sign-on feature, as JWT is compact as compared to XML based standards such as SAML and it can be easily passed in HTML and HTTP environments.
2. Information exchange
JWTs provide a secure way of transmitting information between parties as these can be signed.
For example — With public-private key pairs, we can be sure that the senders are who they say they are. Also, as the signature is calculated using the header and the payload, we can also verify that the content hasn’t been tempered with.
JWT contains three elements — header, payload and signature/encryption data.
The header and the payload are JSON objects and the signature/encryption data is dependent on the algorithm used for signing or encryption. In case of unencrypted JWTs, the third part is not present.
JWTs are encoded in a compact representation which is known as JWS/JWE Compact serialization.
JWS/JWE compact serialization is a Base64-URL encoding of the UTF-8 bytes of the first two elements (header and payload) and the data for signing/encrypting (which is not a JSON object). All the three elements are separated by dots (‘.’). It can be easily passed in HTML and HTTP environments, while being more compact when compared to XML-based standards such as SAML.
Base64-URL is a variant of Base64 encoding that is used by JWTs and it is safe for URLs. This encoding substitutes the ‘+’ and ‘/’ characters for the ‘-’and ‘_’ characters respectively.
Now, let’s discuss about all the three elements of JWT.
1. The header
The header of a JWT is also called as JOSE header which claims about itself. These claims establish the algorithms used, whether the JWT is signed or encrypted. In general, how to parse the rest of the JWT.
There is one mandatory claim for all the JWT header which is known as ‘alg’ claim. It represents the main algorithm used for signing and/or encrypting the JWT.
For unencrypted JWTs, this ‘alg’ claim must be set to the value ‘none’.
Optional header claims include the ‘typ’ and ‘cty’ claims.
typ — It is the media type of JWT itself. this parameter is only meant to be used as a help for users where JWTs may be mixed with other objects carrying a JOSE header. In practice, this rarely happens. So, we generally set this attribute to ‘JWT’.
cty — It means content type. When the payload of a JWT is a JWT itself (a nested JWT), then this ‘cty’ claim must be present and carry the value ‘JWT’. This tells the implementation that further processing of the nested JWT is required. Nested JWTs are rare, so the ‘cty’ claim is rarely present in headers.
2. The payload
It is the section where all the user data is added. It is also a JSON object and contains various claims. the claims with specific meanings attached to them are known as registered claims. The details of registered claims are given in section 4.1 of RFC 7519.
All the claims that are not a part of the registered claims are either private or public claims. The details of public claims and private claims are given in section 4.2 and 4.3 of the RFC 7519 respectively.
3. The signature/encryption data.
To create the signature part, we have to take —
- Base64url encoded header
- Base64url encoded payload
- A secret or a private key
- The algorithm specified in the header
and sign that.
The signature is used to verify that the message isn’t changed along the way and in case of tokens signed with a private key, it can also verify that the sender of JWT is who it says it is.
It is important to note that signature doesn’t prevent other parties from reading the contents inside JWT, even though they are unable to change it. This means we should not put secret information within the token. To hide the information inside the token, we should encrypt it.
JWS compact serialization flow chart
All signing algorithms provide a way to establish the authenticity of the data contained in the JWT. We’ll discuss about the basics of two algorithms — HMAC and RSASSA.
It stands for Hash-based Message Authentication Code. It is an algorithm in which a payload is combined with a shared secret using a cryptographic hash function. the result is a code that can be used to verify a message only if both the generating and verifying parties know the secret.
The cryptographic hash function used in HS256 is SHA-256.
In HS256 algorithms, any party can create new messages as they have the secret.
The following diagram represents a typical HMAC flow chart.
Its a public key algorithm. Public-key algorithms generate split keys — one public key and one private key.
The private key can be used both to create a signed message and to verify its authenticity. But the public key can only be used to verify the authenticity of a message.
Thus, this scheme allows for the secure distribution of a one-to-many message.
Receiving parties can verify the authenticity of a message by keeping a copy of the public key associated with it, but they cannot create new messages with it.
It is a system which centralizes user’s identity. In this system, different parties share authentication and authorization services with other parties.
SAML and OpenID Connect are the most common solutions for federated identity management.
While implementing these features, JWT can be used.
A typical federated identity flow is given below.
- The user tries to access the resource handled my resource server.
- The server redirects the user to the authorization server as he is not having proper credentials to access the resource. The authorization server is configured to let users login using the credentials managed by an identity provider.
- Authorization server redirects the user to the login page of the identity provider.
- After logging-in successfully, the user is redirected to the authorization server along with the credentials provided by the identity provider. These credentials are used by the authorization server to access the credentials required by the resource server.
- The authorization server redirects the user to the resource server along with the credentials required to access the resource.
- The user successfully accesses the resource.
Access token and refresh tokens
Access tokens are the tokens which are often short-lived and give the user access to protected resource. It can also carry additional data which may be defined by the implementer.
Refresh tokens are used by the clients to obtain new access token when the old one expires. for getting a new access token, the user has to request the authorization server with the refresh token. Refresh tokens are generally long-lived.
Note — An access token that carries a signature may be validated by the resource server on its own. There is no need to contact the authorization server for this.
OAuth 2.0 and JWT
There is no mention of JWT in OAuth 2.0 specification. But JWTs are a good match for this purpose.
A good access tokens can be made using signed JWT. Signed JWT eliminates the need to contact the authorization server for validation, which can now be done by the resource server. With JWT, all the necessary data can be encoded to differentiate access levels to a resource.
OpenID Connect and JWT
It is a standardization effort to bring typical use cases of OAuth 2.0 under a common, well-defined spec.
Many details in OAuth2.0 is left to the implementers, which is filled up by the OpenID Connect as it attempts to provide proper definitions for the missing parts. Specifically, it defines an API and data format to perform OAuth 2.0 authorization flows. Additionally, it provides an authentication layer built on top of this flow.
The data format chosen for some its parts is JWT.
In particular, ID token is a special type of token that carries information about the authenticated user.
OpenID Connect flows
- Authorization flow — In this flow, the client requests the authorization endpoint (/authorize) and receives an authorization code, which it uses to request the token endpoint (/token) to get an ID token (in JWT format), an access token and a refresh token (optional).
- Implicit flow — Here, the client requests the tokens directly from the authorization endpoint (/authorize). These tokens are specified in the request. If the client requests an ID token, it will be returned in JWT format.
- Hybrid flow — In this flow, both the authorization code and certain tokens are requested from the authorization endpoint (/authorize). If the client requests an ID token, it will be returned in JWT format. If the ID token is not requested at this step, it can be requested directly from the token endpoint (/token) later.
This explains the meaning of JWT, when to use it, JWT structure, how it works and why to use it.
This is a book written by Sebastián E. Peyrott (Auth0 Inc.) which explains JWT in detail, JWS, JWE, JWK, and JSON web algorithms.
RFC 7519 — JSON Web Token (JWT)