Before getting into coding, we need to be conversant with some important concepts. This section is aimed at introducing you to some of these concepts in detail.
Representational State Transfer (REST) is an architectural style presented by Roy Fielding in the year 2000 for developing web services. It is built on top of the well-known Hypertext Transfer Protocol (HTTP) and can transfer data in multiple formats, the most common being JavaScript Object Notation (JSON) and eXtensible Markup Language (XML). The status of a request in REST is indicated using standard HTTP status code (200: OK, 404: Page not found!, and so on). Being based on HTTP, security is taken care of using the already familiar Secure Sockets Layer (SSL) and Transport Layer Security (TLS).
While writing such web services, you are free to use any programming language (Java, .NET, and so on) that is capable of making web requests based on HTTP (which is a de facto standard that every language supports). You have a number of well-known frameworks, using which developing RESTful APIs on the server side is quite easy and simple. Also, on the client side, there are a number of frameworks that make invoking RESTful APIs and handling responses straightforward and easy.
Since REST works on internet protocol, the caching of a web service response can be achieved quite easily by supplying appropriate HTTP headers (Cache-Control, Expires, and so on). The HTTP methods PUT and DELETE are not cacheable in any scenario. The following table summarizes the use of HTTP methods:
| HTTP method | Description |
| GET | Retrieves a resource |
| POST | Creates a new resource |
| PUT | Updates an existing resource |
| DELETE | Deletes an existing resource |
| PATCH | Makes a partial update to a resource |
Table 1: HTTP method usage
A REST API request/response (data sent over the wire) can be compressed by specifying appropriate HTTP headers, similar to caching. The HTTP header, Accept-Encoding, is sent by the client to the server, to let the server know the compression algorithms it can understand. The server successfully compresses a response and puts out another HTTP header, Content-Encoding, letting the client know which algorithm has to be used to decompress.
"JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties."
- https://jwt.io/
In the past, the stateless nature of HTTP was circumvented in a web application (most of them are stateful in nature) by associating each request with a session ID created on the server and then stored by the client using cookies. Each request sends the cookie (session ID) in the form of an HTTP header, which gets validated by the server, and a state (a user session) is associated with each request. In modern applications (we will cover this in a bit more detail in the next section), a server-side session ID is replaced with the JWT. The following diagram shows the workings of the JWT:
Figure 1: Workings of the JWT in modern applications
The web server, in this case, doesn't create a user session and the user session management capability needed for a stateful application is offloaded to other mechanisms.
In the world of the Spring Framework, the Spring Session module can be employed to externalize the session from the web server to a central persistence store (Redis, Couchbase, and so on). Every request containing a valid token (JWT) is validated against this external store of authenticity and validity. After successful authentication, applications can generate a valid token and send it as a response to the client. The client can then store this token in any client storage mechanism it uses (sessionStorage, localStorage, cookies, and so on, in a browser). Using Spring Security, we can validate this token to ascertain the authenticity and validity of the user and then do whatever is required. We have a dedicated example in a subsequent section (Simple REST API security) of this chapter, which uses a basic authentication mechanism and, if successful, creates the JWT. Subsequent requests use the token in the HTTP header, which gets validated on the server to give access to other secured resources.
The following points highlight some of the advantages of using the JWT:
- Better performance: Each request, when reaching the server, has to check the authenticity of the token send. The authenticity of the JWT can be checked locally and doesn't require an external call (say, to a database). This local validation is performant and reduces the overall response time for a request.
- Simplicity: JWT is easy and simple to implement. Also, it is a well established format in the industry for tokens. There are a number of well-known libraries which can be used to easily work with the JWT.
Unlike common security mechanisms, such as encryption, obscuring, and hiding, the JWT doesn't encrypt or hide the data contained within. But, it does the destination system to check whether the token is from an authentic source. The structure of the JWT consists of a header, payload, and a signature. As mentioned, rather than encryption, the data contained within the JWT is encoded and then signed. Encoding does the job of transforming the data in a way that is acceptable by a variety of parties and signing allows us to check for its authenticity and, in fact, its origin:
JWT = header.payload.signature
Let's go into more detail about each of the components constituting the token.
This is a JSON object and takes the following format. It gives information on how the signature should be computed:
{
"alg": "HS256",
"typ": "JWT"...