JSON Web Tokens (JWT) have become somewhat of an industry-standard for securing REST API’s. The main advantage of JWT is that each token is self-contained, meaning that it contains all information needed to allow or deny any given requests to an API. This means JWT authentication can be implemented in a distributed fashion, is less resource-intensive and generally the preferred choice in enterprise-level services.
Unfortunately, implementing JWT is not always straightforward and can quickly become very complex. Amongst the things you will need to learn are how to format and encode payloads, sign and encrypt messages and format HTTP headers correctly. There are plenty of coding tutorials and libraries out there for any programming language and, with some time and effort, you will probably be able to implement JWT correctly to make your API secure.
However, in this article, I will explain to you how you can easily and simply secure a REST service with Linx. When you use Linx, you can use JWT without having to learn encoding techniques, cryptography and the https protocol and secure your REST API in just a few clicks.
Here are the common myths explained and debunked.
The OpenAPI3 specification defines the security scheme for token-based authentication, like JWT, as “Bearer authentication”. The scheme is called “bearer” and the type is “http” (see spec at swagger.io). So, in Linx, we call this scheme the “HTTP Bearer” security scheme.
In order to implement the “HTTP Bearer” security scheme for a REST Web Service in Linx, we first need to create a new solution in the Linx Designer. We then add the REST plugin to our solution and can drag the SimpleRESTHost service into our solution.
In the properties panel of the SimpleREST Host service, we can find a range of properties to configure the API. The two I want to focus on in this article are:
- Security scheme – a simple drop-down where you can choose between two currently supported security schemes
- Operations – the property where you will configure the operations, sometimes also called methods, for your service
To set the security scheme for the service, you just need to select “HTTP Bearer” in the dropdown. When you do this a field called “Bearer secret” appears. The value from the “Bearer secret” field will be used to digitally sign and to validate JWT security tokens for the service.
To make this service secure, it is advisable to enter a long string of random characters into this field. In order to be able to access the secret when I generate the token, I need to add the secret as a setting. I can then select that setting in any property where I want to refer to the secret in my solution.
In any typical business, there are a multitude of business-enhancing applications that don’t require full-stack development teams, where practices such as continuous deployment or test-driven development might be overkill. Similarly, a true developer will know, 50-80% of the code they write doesn’t directly support business-specific use cases; it goes into coding and supporting a number of non-unique systems that every application needs – authentication, authorization, database, etc.
Now, I want to create two operations under my service.
Firstly, an operation to authenticate users called Login. Here I accept some credentials and will not apply a security scheme as this operation must be open so that anyone can call it with their login credentials to gain access to the service. This operation will return the token users must provide when they call my second operation.
My second operation will return some sensitive information and requires the caller to be authenticated. I will call it “GetData” and, to secure it, I just need to select “Apply security scheme” when I create this operation. Calls made to this operation must now supply a valid JWT token to be processed by Linx.
In the login operation, I want to do two things. Firstly, I want to check that the login credentials that were submitted are valid. This would typically be done by checking a username and password in a database. I can find these values in the input to my operation and can verify them by using an ExecuteSQL function from the database plugin.
If the details are valid, I want to generate a JWT token and return it to the caller. I have created a process called CreateJWTToken where I will generate that token. Tokens can have a payload that is composed of bits of information called “claims”. In the payload of my token, I have included an expiry time for this token in a claim called “exp” and the logged-in users name in a claim called “unique_name”.
Into my CreateJWTToken process, I dragged a premade function called CreateJWT from the Cryptography plugin that will create the token and sign it with an algorithm I choose. Inputs to this function are:
- The secret key I generated for my REST service
- The payload I want to include in my tokens
- The algorithm I want to use to sign the token
Using the CreateJWT function saves me from having to learn a lot about cryptography and gives me the power of adding the functionality of generating many types of JWT tokens very easily.
The JWT specification defines that JWT tokens must be provided in a header with a key called “Authorization”. The token must further be provided as a value for the header and must be prefixed with the word “Bearer” like so:
When a call is made to an operation that requires authentication, Linx will handle the validation of the token. So, when my secured operation, GetData, is called, the JWT token has already been validated and I don’t need to do anything to actively authenticate the token provided by the caller. I thus don’t have to worry about the validity of the token at all and can completely focus on developing my business logic.
I can find the username I stored in the token by selecting the User -> Name value in the Input object. This value may be important in my business logic and I can use it when I process requests made to my API to restrict access to operations and data, or to log calls for billing purposes, for example.
When a call with an expired token is made, Linx will automatically respond to the caller with a 401 unauthenticated status code and the user will need to log into the service again to get a new token.
And that’s it. The entire process took less than 10 minutes to complete and I now have a REST API secured with JSON Web Tokens.