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. You will need to learn 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.
Defining API Security
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.
To implement the “HTTP Bearer” security scheme for a REST Web Service in Linx, you 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 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 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 sign digitally and to validate JWT security tokens for the service. To secure this service, it is advisable to enter a long string of random characters into this field. To be able to access the secret when you generate the token, you need to add the secret as a setting. Select that setting in any property you want to refer to the secret in your solution.
Creating Secure Operations
In any typical business, there is 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 several non-unique systems that every application needs – authentication, authorization, database, etc.
To create two operations under the service. Firstly, an operation to authenticate users called Login. Here you will 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.
The second operation will return some sensitive information and requires the caller to be authenticated. Call it “GetData” and, to secure it, select “Apply security scheme” when you create this operation. Calls made to this operation must now supply a valid JWT token to be processed by Linx.
Generating JSON Web Tokens
In the login operation, there are two tasks to complete. Firstly, check that the submitted login credentials are valid. This would typically be done by checking a username and password in a database. You can find these values in the input to the operation and verify them using an ExecuteSQL function from the database plugin.
If the details are valid, you can generate a JWT token and return it to the caller. We 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, include 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, drag a premade function called CreateJWT from the Cryptography plugin that will create the token and sign it with an algorithm you select. 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 you from having to learn a lot about cryptography and gives me the power to add the functionality of generating many types of JWT tokens very quickly.
Validating JSON Web Tokens
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 the secured operation, GetData, is called, the JWT token has already been validated and you won’t need to do anything to actively authenticate the token provided by the caller. By doing so, you don’t have to worry about the validity of the token at all and can completely focus on developing your business logic.
You 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 you can use it to 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.