In my earlier post on Cryptography, we looked at some of the cryptographic techniques and cryptographic functions that are commonly used to secure the data.
In this post, we’ll discuss JSON Web Token (JWT) which is one of the most commonly used token based authentication. It has become quite popular since it allows the distributed systems to securely communicate with each other without having the need to share the user id and password. In the microservices architecture, it is important to ensure that the APIs are able to authenticate and authorize the end-user identity seamlessly which is both secure and scalable. JWT allows the APIs to share the identity of the principal and verify its identity to establish the trust before sending the response back.
Authentication Token Types
Token by Reference – Reference based token contains no information except some random strings which is useful to the authentication server or the entity that generated the token. Token information including the identity of the principal is known only to the authentication server or the entity that generated the token.
Token by Value – Value based token contains all the information in the token itself. Anyone can read the information contained inside the token. JWT falls under this category as it contains all the information pertaining to the token as discussed later in the post.
JSON Web Token
JWT is a compact and URL-safe means of representing claims to be transferred between two parties. JWT is self-contained since all the necessary information is contained in the payload within the token itself. JWT tokens are quite widely used for securing the REST APIs in a microservices architecture. JWT can also be used as the identity token in the OpenID connect, access tokens in OAuth and as a session id stored in the cookie after the user is authenticated.
JWT token could be either JSON Web Signature (JWS) or JSON Web Encryption (JWE). When the JWT is signed by using either a symmetric key or an asymmetric key then it is known as JWS.
JWT/JWS Token Structure
JWT token consists of 3 sections that are separated by dots and base64URL encoded.
JWT header is a JSON object that usually contains 2 attributes and provides information about how the JWT signature should be computed.
typ – Identifies the type of object i.e. JWT
alg – Identifies the type of hashing algorithm (HS256, RS 256 etc.) used to sign the token
JSON object containing the information about the token i.e. the claims. Some of the claims are predefined based on the JWT standard. Custom claims can be added which are not part of the JWT standard. Even though anyone can see the claims, payload cannot be tampered since the JWT token becomes invalid if any of the claims are modified.
Below are some of the standard claims that identify the entity which issued the token, subject of the token, TTL (Time To Live) and the audience that identifies the group of entities for which the token is valid.
- iss (Issuer) – Identifies the principal that issued the token
- sub (Subject) – Identifies the principal that is the subject of the token. It is usually the entity for which claim statements are being made.
- aud (Audience) – Identifies the recipients (audience) that the JWT is intended for. JWT is rejected if the principal processing the claim does not identify itself with the value in the audience when the claim is presented.
- exp (Expiration Time) – Identifies the expiration time for the token
- nbf (Not Before) – Identifies the time before which the token is invalid for processing
- iat (Issued At Time) – Identifies the time at which the token was issued
- jti (JWT Id) – Unique Identifier that can be used to prevent the JWT from being replayed
JWT token is secured by using digital signature or by generating the Message Authentication Code (MAC). Asymmetric algorithm (e.g. RS256) is used for signing the token using the private key of the entity generating the token. On the other hand, symmetric algorithm (e.g. HS256) uses a shared secret key known to both the parties i.e. token generator and token validator.
Signature algorithm – HS256
key= "Shared Secret Key" unsignedToken = base64URLEncode(header) + "." + base64URLEncode(payload) signature = HMAC-SHA256(unsignedToken , key)
Signature algorithm – RS256
key= "Private Key" unsignedToken = base64URLEncode(header) + "." + base64URLEncode(payload) signature = RSA-SHA256(unsignedToken , key)
Below diagram shows how both the symmetric and asymmetric algorithm can be used together for authenticating the API consumer to the API provider using the Authentication Server. API consumer (microservice A) generates the HS256 JWT token using its own shared secret key and sends it over to the authentication server. Authentication server validates the HS256 JWT token using the shared secret key of microservice A. If the token verification is successful, authentication server generates the RS256 JWT token using its own private key and sends it back to microservice A. Microservice A sends the request to microservice B with RS256 JWT token that it got from the authentication server. Microservice B can authenticate the request from microservice B by validating the RS256 JWT token using the public key of the authentication server. Since microservice A has already established the trust with the authentication server, microservice B can trust the request from microservice A if the RS256 token is successfully validated.
JWT does not encrypt the data and hence it does not offer confidentiality. Instead, it provides a standard based (RFC7519) and scalable solution to authenticate the request by encoding and signing the data in the token.