TL;DR: In today's post, we are going to learn how to develop RESTful APIs with Kotlin, the thriving programming language that is eating Java's world. We will start by creating a small Spring Boot RESTful API that handles CRUD operations. After that we are going to secure this API with Auth0, which brings to the table many security features such as Multifactor Authentication, integration with Social Providers, and so on. In the end, we will also see how to manage the JWTs by ourselves, replacing Auth0 with an in-house solution where we issue our own tokens.

What is Kotlin

Kotlin is a programming language, developed by JetBrains, that runs on Java Virtual Machines (JVMs) and that can also be compiled to JavaScript. This programming language is statically typed, which means that variables, functions, and expressions use predefined sets of types that can be checked on compile time.

One of its main goals is to solve the problems that comes along with Java. For example, compared to Java, a software written in Kotlin is expected to have roughly 40% less lines of code, while still being able to interoperate with the rich set of libraries available for Java.

How Kotlin Differs from Java

First of all, the syntax. Kotlin's syntax is somewhat similar to Java's, but there are many differences. JetBrains states that Java developers will have an smooth learning curve when migrating to Kotlin. Although this might be true, becoming a Kotlin developer and writing idiomatic code in this new language is not that straightforward.

If you start studying Kotlin's specifics, you will note that Kotlin is an advanced programming language with a glossary of its own. For example, Kotlin has features like data classes, sealed classes, inline functions, and more. Most of these features can be mirrored in Java, but not without writing some pretty verbose code. Therefore, writing true idiomatic Kotlin source code is not as easy as JetBrains wants you to believe.

Learning Kotlin

If you have never used Kotlin before, you can still follow along with this blog post. But it will do you no harm to study the language a little before. The following list contains some resources where you can learn Kotlin:

If you already have some experience with Kotlin or are just wondering if developing a simple RESTful API will be easy, read on.

Starting a Spring Boot Kotlin Application

Spring Initializr is a great way to start a Spring Boot application, and they already added Kotlin as one of the options for the chosen programming language (there are three available at the time of writing: Java, Kotlin, and Groovy). This website easily allows us to select what other libraries we want in our application. However, for the sake of simplicity, we will start by cloning this GitHub repository that I have prepared for this article, and then we are going to evolve from it.

This startup project already comes with Spring Data JPA and HSQLDB. Together, these features will hold a set of customers that our API is going to allow users to manage. Our job will be just to create the Customer entity model that represents the customers, a CustomerRepository interface to handle the persistence layer, and a CustomerController class that will define the RESTful endpoints.

Creating a Kotlin Data Class

As already mentioned, one of Kotlin's best features is that it's a very concise programming language. Most of the boilerplate code that Java developers are used to—like getters, setters, equals, and hashCode—were dropped in favor of a succinct syntax. Well, actually dropped is not the correct term here. Methods like equals and hashCode are automatically derived by the compiler, but one can still explicitly define them if needed.

As the idea of our RESTful API is to enable users to manage a set of customers, our Kotlin Data Class is going to be called Customer. Let's start by creating a new directory called model in the src/main/kotlin/com/auth0/samples/kotlinspringboot/ directory, and then let's add a file called Customer.kt in it with the following source code:

Note that, differently from Java, we defined the basic properties of the Customer class embraced in parentheses after the class declaration. In Kotlin, this is called a primary constructor. We could define these properties in the class's body, and we could also define other constructors as well, but for our case this is enough. Also note that we have added two annotations, @Id and @GeneratedValue, to the id property. This syntax is identical to Java's syntax.

Creating a Repository for Customer

The CustomerRepository interface that we are going to create will be very similar to what we would do on a regular Java Spring Boot application. To keep things organized, let's first create a directory called persistence in the src/main/kotlin/com/auth0/samples/kotlinspringboot/ directory. In this new directory, we are going to create a file called CustomerRepository.kt and add the following code:

Defining Customer RESTful Endpoints

The RESTful endpoints that will handle user requests is also going to be similar to its Java counterpart, a little bit more succinct, but still pretty familiar for Java developers. You may also note that the import statements haven't changed. Although they are quite verbose, in my opinion this is a good thing. Like that, one can easily identify where a dependency comes from.

To create our class, let's start by creating a controller directory in the src/main/kotlin/com/auth0/samples/kotlinspringboot/ directory. After that, let's create a file called CustomerController.kt in this new directory and add the following code:

The source code of this class is pretty self-explanatory, but for the sake of completeness here is an explanation of it:

@RequestMapping("/customers") annotation declares that all endpoints in this class will have the /customers prefix.

@GetMapping annotation defines findAll as the method responsible for handling HTTP GET requests to /customer.

@PostMapping annotation defines addCustomer as the method responsible for handling HTTP POST requests to /customers. Also, this method accepts a JSON version of customer and deserialize it to our Customer class automatically.

@PutMapping("/{id}") annotation defines updateCustomer as the method responsible for handling HTTP PUT requests to /customers. This method also accepts a Customer as the body of the request. The difference between the put and post methods is that put expects the request path to have an {id} of the Customer to be updated.

@DeleteMapping("/{id}") annotation defines removeCustomer as the method responsible for handling HTTP DELETE requests to /customers. {id}, in this case, defines the id of the customer to be deleted.

@GetMapping("/{id}") annotation defines getById as the method responsible for handling HTTP GET requests to /customer/{id}, where {id} defines which customer will be serialized as a response.

And that's it. We have now our first Kotlin RESTful API, backed by Spring Boot. If you want to play with it, type mvn spring-boot:run in the root directory of the application and Spring Boot will startup. After that, you can use the following commands to interact with the API:

For starters, if you haven't done so yet, this is a good time to sign up for a free Auth0 account. Having an Auth0 account, the first thing that we must do is to create a new API on the dashboard. An API is an entity that represents an external resource, capable of accepting and responding to protected resource requests made by clients. And this is exactly what the Kotlin app that we just built is, an API.

When creating an API, we must define three fields: Name, which is just a friendly name for our new API; Identifier, which is a String that we will use when requesting an access_token; and the Signing Algorithm, which defines if this API will use a symmetric or asymmetric algorithm to sign the access_token. In our case, we will fill these fields, respectively, with: Kotlin RESTful API; kotlin-jwts; and RS256 (i.e. we will use an asymmetric algorithm).

To use the APIs & Trusted Clients flow, we must first configure the Default Directory property on our Auth0 account. To do so, head to the Account settings page and add Username-Password-Authentication as the value of the Default Directory property. This value is the name of the database connection that comes by default on any Auth0 account.

We also need to enable the Password grant type on the client. If we created the API as explained above, Auth0 will have automatically created a client called Kotlin RESTful API (Test Client). Accessing its settings, we can click on the Show Advanced Settings option, check Password on the Grant Types tab and save the change.

Changing the Code

Under ./src/main/resources, there is a file called application.properties. This file needs to be populated with data from our Auth0 account. By default, when creating a new account we get a "Default App", which could be used for this. These are the important parts of that config, so remember to replace the values with the values of your application:

# this is the identifier of the API that we just created
auth0.audience=kotlin-jwts
# replace YOUR-DOMAIN to get something like https://bkrebs.auth0.com/
auth0.issuer=https://YOUR-DOMAIN.auth0.com/

Before we jump into the code, we need to add three dependencies to our Maven configuration:

And that's it. This is everything that we need to do to use Auth0 with our Kotlin Spring Boot RESTful API. To test our application's security, let's re-run the application:

mvn spring-boot:run

Before getting an access token to issue requests to our API, we first need to create a new user on Auth0. To do that we have to issue a POST request to the /dbconnections/signup endpoint. This request requires a Content-Type header with application/json following JSON body:

Note that the client_id and client_secret properties, on both requests, must be changed accordingly. Their values can be found in the Kotlin RESTful API (Test Client) client that Auth0 created for us. Head to the Clients page to get them.

Issuing this last request will give us an access_token. From now on, we will use this token in the header of the requests that we will send to our Kotlin API. Therefore, if we query our endpoints with this access_token, we will be able to manage the set of customers again.

Securing Kotlin with a Home Made Solution

If, for whatever reason, we prefer not to have a RESTful API as secure as we would have with Auth0, we would have to proceed as explained in this section. First, we would need to remove Auth0's dependencies from pom.xml:

After that, we could also remove the two properties that we've added to the application.properties file, as they won't be used anymore. Then, to issue and validate JWTs, we would need to add the following Maven dependency:

Handling Users

To support multiple users in our API, we will first create three classes: ApplicationUser.kt, ApplicationUserRepository.kt, and SignUpController.kt. These classes will behave pretty much like the classes that support customers' management. The first class, ApplicationUser.kt class, will be created in the model package and will contain the following code:

In this case, the only difference when compared to CustomerRepository is that we defined a method called findByUsername. This method will be used by our homegrown solution to find users by their usernames. Now the last class, SignUpController.kt, will be created in the controller package with the following code:

The only endpoint defined in this controller is the signUp one, which allows new users to register in our application. The sign in process and token validation will be handled in a different area, as we will see soon. Note that to keep our users' password secure even in an eventual data breach, we have used the BCryptPasswordEncoder class, that comes along with Spring Security, to encode all passwords.

Issuing and Validating JWTs with Kotlin

Now that we have our User data class mapped and an endpoint to allow new users to register themselves, we need to allow these users to sign in and also validate JWTs before enabling them to interact with our API. To achieve this, we will create two filters and one class: JWTAuthenticationFilter, JWTAuthorizationFilter, and UserDetailsServiceImpl. The first filter, which will be responsible for the sign in feature, will be created in a new directory file called JWTAuthenticationFilter.kt in the same package as the WebSecurity class. This file will have the following source code:

attemptAuthentication, which will parse the credentials from the user and try to authenticate them

and successfulAuthentication, which will generate a JWT if the user is successfully authenticated.

Note that both filters use some undefined constants like SECRET and EXPIRATION_TIME. To define these constants, we will create a file called SecurityConstants.kt in this same directory with the following code:

This filter will be utilized whenever a secured endpoint is requested and will start by checking if there is a token in the Authorization header. If it manages to find one, it will try to validate it and set the user in the SecurityContext. If no token is found, it will simply let the request move along the Spring Security filter chain, and then this request will be answered with a 401 (Unauthorized) status code.

The last class that we will need to create is UserDetailsServiceImpl. This class will extend the UserDetailsService class from Spring Security and will be responsible for finding users in our database so Spring Security can check their credentials. This class will be created in the main kotlinspringboot directory and will contain the following source code:

Conclusion

Writing code in Kotlin is not that hard for a Java developer, as there are not that many pitfalls to be aware of. But, to become a true Kotlin developer, using the full power and best features of the language, is not straightforward and requires a few hours of study and development. Kotlin integration with existing Java libraries is very good, as we could while using Spring Boot, and the code developed was very concise and easy to read. We haven't covered that many features of Kotlin, but we managed to validate its applicability on the backend.