Over the last few years web application development has seen drastic changes, with the front-end frameworks coming to the scene, the popularity of hybrid applications, mobile first strategy, rising demand for SPAs, Microservices etc.
In older times, both the frontend and the backend would be in a single place, but this has changed over the years now. Using separate client-side applications is a common choice now. It definitely has a lot of advantages, but it also has brought significant changes on the architecture as well.
The RESTful API service model has been used a great amount recently in applications. Nowadays our back-end is more about complex business logic and data while presentation logic is moved exclusively to the front-end or mobile applications using frameworks like Angular/React/Ember etc
Also in most cases the application would need to interface with 3rd party services for fetching data. Interfacing with the 3rd party apps are often done using the APIs.
With these changes in the architecture, sharing data securely has also changed a lot. Previously cookies and server-based authentication was the easiest and go to solution.
However, with the client side frameworks in place handling authentication in modern Mobile and Single Page Applications can be tricky and needs to be addressed carefully. The best-known approaches for implementing authenticated endpoints for the APIS are either using OAuth 2.0 or the token based authentication using JSON Web Token (JWT).
What are JSON Web Tokens?
The official draft of the JSON Web Tokens (JWT) is as below:
Abstract from the draft specification:
JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted.
Or in plain terms:
A JSON Web Token, or JWT, is a cryptographically signed token which can be used to send information that can be verified and trusted by means of a digital signature. This token can be verified against the signature to verify its authenticity. Since the token is encrypted we can include sensitive information like authorization headers in the payload,
Characteristics of JWT:
JWTs are self-contained: A JWT mainly has 3 parts, basic information about the token itself, a payload which can be sensitive information, and a signature. All these information are passed along with the JWT itself.
JWTs can be passed around easily: Since JWTs are self-contained, and encrypted they can be easily transmitted inside a HTTP header.
What is the JSON Web Token structure?
JSON Web Tokens are self-contained and consist of three parts separated by dots (.), which are:
Therefore, a typical JWT looks like the following.
Let's break down the different parts.
The header part of a JWT mainly consists of information related to the token itself. It has two parts:
- the type of the token, which is JWT,
- the hashing algorithm being used, such as HMAC SHA256 or RSA.
The above details are Base64Url encoded to form the header of a JWT
Payload is the second part of the JWT. It may include confidential information like user details, any other additional metadata etc. These are also called claims.
There are three types of claims: reserved, public, and private claims.
The standard defines a set of predefined claims. These are are not mandatory but hightly recommended.
Some of them are:
- iss: The issuer of the token
- sub: The subject of the token
- aud: The audience of the token
- exp: This will probably be the registered claim most often used. This will define the expiration in NumericDate value. The expiration MUST be after the current date/time.
- nbf: Defines the time before which the JWT MUST NOT be accepted for processing
- iat: The time the JWT was issued. Can be used to determine the age of the JWT
- jti: Unique identifier for the JWT. Can be used to prevent the JWT from being replayed. This is helpful for a one time use token.
Any custom claims can be defined in the public claims section.
These are the custom claims created to share information between parties that agree on using them.
Our example payload has two registered claims (iss, and exp) and two public claims (name, admin).
"name": "Manu S Ajith",
Payloads are also Base64Url encoded to form the second part of the JWT.
To create the signature for a JWT, we first need to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and using that sign that.
The commonly used algorithm is HMAC SHA256.
We can create the signature using the above header, payload, secret, and HMAC SHA256 algorithm in the following way:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
This signature is used to verify the authenticity of the sender, and also makes sure that the token hasn't tampered.
Combining all the parts:
We can get our final JWT by combining the three Base64 strings separated by dots
The following shows a JWT that has the previous header and payload encoded, and it is signed with a secret.
When should you use JSON Web Tokens?
Some of the most common use case of JWT are authentication and information exchange.
Authentication: This is the most common use case for JWT. The authentication would be done using token based strategy, and with each subsequent request a JWT is passed back to the server. This JWT is used to permit or deny access to routes, services, and resources for that user. Applications using the Single Sign On strategy heavily leverges JWT because of its small overhead and its ability to be easily used across different domains.
Information Exchange: JWT are a good way of securely exchanging confidential information between applications because they are signed and ecrypted. Additionally, as the signature is calculated using the header and the payload, you can also verify that the content hasn't been tampered with.
Advantages of Token-Based Authentication and JWT
Stateless, easier to scale: The JWT contains all the necessary information to identify a particular user. It can be sent to any server among a cluster of servers under a load balancer, not necessarily to the server that issued the token, or the server that the user logged in initially with.
Reusability: We can reuse the token generated across multiple servers and multiple platforms and domains. Applications using Single Sign On (SSO) are typical examples.
Security: Since the tokens are signed we can transmit the information securely over HTTP. Additionally, we can encrypt the tokens using JWE and also use an SSL and transmit over HTTPS
Performance: We can completely avoid deserializing the sessions back on the server on each request. We can use any of the servers to authenticate the token, validate it and parse the contents
How do JSON Web Tokens work with authentication ?
Upon successfully authenticating a user using his credentials(email/password combinication), the server issues a JWT. This token is used to authenticate the user in all further requests. This can be saved on the client side
either in local storage, or cookies.
Whenever the user wants to access a authenticated/authorized route or resource, the client app should send the JWT that was issued previously, typically in the Authorization header using the Bearer schema. The content of the header should look like the following:
Authorization: Bearer <token>
Since token based authenticate is stateless the user state is never saved in server memory. Each time the server gets a request to a protected route, it will check the validity of the JWT and the Authorization Header. Upon successfully decoding the token it will grant access to the resource if the user has permission to the same.
As JWTs are self-contained, it can even be used to store access levels for a particular user, reducing the need to query the database multiple times.
The JSON Web Token standard can be used across multiple languages, frameworks and is quickly and easily interchangeable.
You can use the token in a URL, POST parameter, or an HTTP header. The versatility of the JSON Web Token lets us authenticate an API quickly and easily by passing information through the token.