<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Luca Nicolini</title>
    <description>The latest articles on DEV Community by Luca Nicolini (@mithosk).</description>
    <link>https://dev.to/mithosk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2707998%2F756886c7-6f7b-4f76-ac1a-b42984c0ecd2.jpg</url>
      <title>DEV Community: Luca Nicolini</title>
      <link>https://dev.to/mithosk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mithosk"/>
    <language>en</language>
    <item>
      <title>The best software architecture with the smaller effort</title>
      <dc:creator>Luca Nicolini</dc:creator>
      <pubDate>Wed, 05 Mar 2025 16:26:08 +0000</pubDate>
      <link>https://dev.to/claranet/the-best-software-architecture-with-the-smaller-effort-3njf</link>
      <guid>https://dev.to/claranet/the-best-software-architecture-with-the-smaller-effort-3njf</guid>
      <description>&lt;p&gt;For many years, code was written to create applications that got bigger and bigger, which we now call monolithic. Then we understood that this application was a big problem for businesses. Here are the main problems we have found with monolithic applications.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced development speed&lt;/strong&gt;: a large monolithic application makes development more complex and slower.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: scaling of individual components is not possible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reliability&lt;/strong&gt;: failures in one module can affect the availability of the entire application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Non-Agile development&lt;/strong&gt;: Often more teams found a conflict in development code because they were working on the same code repository for different projects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lack of flexibility&lt;/strong&gt;: a monolith is constrained by the technologies already used in the monolith itself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deployment&lt;/strong&gt;: a minor change to a monolithic application requires a re-deployment of the entire monolith.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fupn27axd2hfbqn4wcwhl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fupn27axd2hfbqn4wcwhl.png" alt="Image description" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In recent years, many companies have migrated their monoliths to microservices architectures. Theoretically, I can assure you that it's the best choice, but in practice, there are different control indicators. Let's focus on the advantages of microservices over monoliths.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improved scalability&lt;/strong&gt;: because each service is a separate component, it is possible to scale a single function or service without having to scale the entire application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Right tool for the right function&lt;/strong&gt;: with microservices, it is possible to achieve greater independence from suppliers by choosing the right tool for each function. Each service can be written in its own programming language, can use its own structure and utilities, and can communicate with the other services in the application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increased resilience&lt;/strong&gt;: with microservices, the entire application is decentralised and decoupled into services that act as separate entities. Unlike monolithic architecture, where a bug in the code affects more than one service or function, the impact of a bug in this architecture is minimal.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Faster deployment times&lt;/strong&gt;: in monolithic architectures, changes require redeploying the entire application. A microservices architecture enables faster releases because each service is developed and deployed independently, reducing the risk and time associated with coordinating changes across an entire application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Greater cost efficiency&lt;/strong&gt;: activities are focused on specific services, reducing the overall cost of developing and maintaining the system. Teams work on specific functionalities, ensuring that resources are used efficiently without redundancy or excess.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let's talk about the drawbacks. When using microservice architecture there are two main disadvantages, in this article we'll focus on these ones and try to find a solution.&lt;/p&gt;

&lt;p&gt;The first contraindication is the cost of the infrastructure, but we won't talk about this because it was discussed in a previous article that you can find &lt;a href="https://dev.to/claranet/how-to-reduce-the-cost-of-microservices-architecture-ef4"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The second contradiction we're going to talk about in this article is the implementation effort. Building a microservices architecture is very expensive, both in terms of development and in terms of maintenance and monitoring. It's important not to underestimate the difficulty of the design, a bad design will become the most important problem.&lt;/p&gt;

&lt;p&gt;There are companies that start a project with microservices and then come back because they understand that they are not ready for this architectural solution. Instead, there are companies that start migrating their monoliths to microservices and then stop because it's too expensive or too complicated.&lt;/p&gt;

&lt;p&gt;The solution I want to recommend to you today is semi-monolithic architecture. I am talking about a hybrid architecture that uses monolithic and microservices in total harmony.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1m3idetye1qcuvskgh1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1m3idetye1qcuvskgh1.png" alt="Image description" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above shows a hybrid microservices and monolithic architecture.&lt;/p&gt;

&lt;p&gt;I think that when you start a project you need to build a monolithic application. By monolithic I mean a large application that handles a significant part of the application domain. There may be more than one monolith in an organisation. The first thing you need to think about is dividing the application domain into a few parts and creating a monolithic application for each of them. You can think that a monolith needs to be only one, at actually we talk about monolith every time we have an application as managing a large part of the domain. So in a company there can be more monolithic application.&lt;/p&gt;

&lt;p&gt;If you need a common part for multiple monoliths, you can create a microservice instead of a library, giving you a piece of code that can be written in a different language, updated and deployed independently of other applications.&lt;/p&gt;

&lt;p&gt;Sometimes we need to create a microservice for a critical part that we can't scale horizontally. There are cases where we'll create a new microservice just because there's more functionality that's better implemented in a particular language. &lt;/p&gt;

&lt;p&gt;In this type of architecture, it's very important that services communicate with them in asynchronous mode, using message queues such as SQS in AWS services. For communication from monoliths to microservices we can use http protocol for example.&lt;/p&gt;

&lt;p&gt;Another important concept is that there will be no database sharing by applications. Each microservice will have its own database and will not access another microservice's database. This is fundamental when we use a modern ORM for database maintenance with migrations. Of course, the same is true for monoliths.&lt;/p&gt;

&lt;p&gt;This solution allows us to create a hybrid architecture that uses microservices without abusing them. In this way, we can reduce infrastructure and development costs while taking advantage of the key benefits of microservices.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>monoliths</category>
      <category>architecture</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to reduce the cost of microservices architecture</title>
      <dc:creator>Luca Nicolini</dc:creator>
      <pubDate>Wed, 12 Feb 2025 11:55:47 +0000</pubDate>
      <link>https://dev.to/claranet/how-to-reduce-the-cost-of-microservices-architecture-ef4</link>
      <guid>https://dev.to/claranet/how-to-reduce-the-cost-of-microservices-architecture-ef4</guid>
      <description>&lt;p&gt;Over the past few years, more and more companies have decided to go the microservices way. Some companies are now happy with their choice, but others have unfortunately encountered various problems. In this article, we look at the cost issue of a microservices architecture and try to provide a solution.&lt;/p&gt;

&lt;p&gt;A big issue with microservices architecture is the cost of infrastructure. A microservice is a small application that runs inside a container. To create a microservices architecture, you need to manage tens or hundreds of containers. Obviously, this comes at a high cost in terms of the price of the machines running the containers, or cloud services if the containers are hosted in the cloud.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo0wyv2o07sv03outxtu6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo0wyv2o07sv03outxtu6.png" alt="Image description" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we're looking at AWS for cloud computing of our microservices. We need to know that in AWS we have two different ways of running containers, we can use EC2 machines or we can use Fargate.&lt;/p&gt;

&lt;p&gt;With EC2, we have to pay a fixed price to AWS to run containers. A microservices architecture can consist of hundreds of microservices, and the cost of that can be very expensive.&lt;/p&gt;

&lt;p&gt;With Fargate, the containers are serverless, so when we are not using them, they are off. We only pay for the containers while they are active.&lt;/p&gt;

&lt;p&gt;In general, from a cost perspective, serverless resources make sense for low usage, while always-on resources make sense for high usage.&lt;/p&gt;

&lt;p&gt;Within a microservices architecture, there are services that are called with high frequency and others that are called with low frequency, this makes you understand that some containers, unlike others, will be used very little and this represents a waste. A recent idea is to build a microservices architecture using serverless functions called Lambda, in this way microservices become a set of functions that only run when called. These functions are often called FaaS or Functions as a Service. This solution costs less than Fargate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwt17xfnsqpbbtk57ei2y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwt17xfnsqpbbtk57ei2y.png" alt="Image description" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above shows an example of a serverless architecture implemented on AWS. This is a solution to save money by using a lambda serverless functions instead of microservices. This way we don't need containers and we write code without worrying about server. This is a modern solution that many companies are using today.&lt;/p&gt;

&lt;p&gt;The first problem is that we need to create a Lambda for each function, so for large application domain we'll find a large number of Lambda function. Managing too many Lambda function may not be easy.&lt;/p&gt;

&lt;p&gt;The second problem is in the resource consuming, for example using more Lambda on the same database the DBMS it can manage too connections. This applies to all resources used, not just the database.&lt;/p&gt;

&lt;p&gt;The third problem is the start time for the Lambda startup when it is called in the off state. In fact, if we call a Lambda function in the off state, it'll perform a startup which will slow down the first execution. The lifecycle of a Lambda will last for a few minutes, then it'll be back in off and we'll find a new start time for the next execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fluxosy6bzt8q3wxd9k7a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fluxosy6bzt8q3wxd9k7a.png" alt="Image description" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above shows an example of microservices encapsulated within  Lambda functions. It may look strange, but it is a powerful and versatile solution. So we can write microservices normally without thinking about concepts of serverless functions, we can deploy our microservices on Lambda functions, we can migrate our microservices to containers later.&lt;/p&gt;

&lt;p&gt;My advice is to start with microservices within lambda function until  they have low usage. When the microservice has high usage then we'll migrate to container, we can choose Fargate for high usage, EC2 for very high usage.&lt;/p&gt;

&lt;p&gt;Now I'll show you how to implement this thing in Node.js using Fastify with TypeScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0dfhiek55lb819rol6c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0dfhiek55lb819rol6c.png" alt="Image description" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's start by creating a route as Fastify plugin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { FastifyPluginAsync } from 'fastify'

const routes: FastifyPluginAsync = async server =&amp;gt; {
    server.get('/api/hello-world', async () =&amp;gt; {
        return {
            hello: 'world'
        }
    })
}

export default routes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then we create a simple Fastify application that uses the plugin above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fastify from 'fastify'

const port = 5100
const server = fastify()

server.register(import('./routes'))

server.listen({ port }, () =&amp;gt; {
    console.log(`http://localhost:${port}/`)
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simple application can be seen as a first step towards creating a microservice. In this case, we are talking about a microservice running in a container, because we are implementing a web server listening on port 5100.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fastify from 'fastify'
import awsLambdaFastify from '@fastify/aws-lambda'

const server = fastify()

server.register(import('./routes'))

export const lambda = awsLambdaFastify(server)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've modified the code to create a Lambda function using '@fastify/aws-lambda'. This Lambda can then be deployed to AWS, for example using CloudFormation or Terraform to perform the deploy. As you can see, it's very easy going from container to Lambda and from Lambda to container.&lt;/p&gt;

&lt;p&gt;In this &lt;a href="https://github.com/claranet-it/fastify-serverless-starter-infra" rel="noopener noreferrer"&gt;repository&lt;/a&gt; we show an example of Terraform usage for Lambda deploy.&lt;/p&gt;

&lt;p&gt;For container orchestration, we can use EKS or ECS. ECS is the first choice if you're in AWS, but EKS is important if you're a Kubernetes expert and you want to keep using it.&lt;/p&gt;

&lt;p&gt;We've learned a way to write microservices, which run in a container or as lambda functions, and it's very easy to move from lambda to container or vice versa. So we've got a lot of control over the cost of our architecture, safely executed in the cloud.&lt;/p&gt;

&lt;p&gt;The world of microservices is in continuous evolution, I think that encapsulating microservices to serverless functions is a good practice for services with low frequency of using. I also believe that using Semi-Monolithic Architecture could become important, but we will talk about this in the next episodes.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>lambda</category>
      <category>aws</category>
      <category>programming</category>
    </item>
    <item>
      <title>Securing APIs: Techniques and Best Practices for Security</title>
      <dc:creator>Luca Nicolini</dc:creator>
      <pubDate>Thu, 30 Jan 2025 16:40:48 +0000</pubDate>
      <link>https://dev.to/claranet/securing-apis-techniques-and-best-practices-for-security-14ik</link>
      <guid>https://dev.to/claranet/securing-apis-techniques-and-best-practices-for-security-14ik</guid>
      <description>&lt;p&gt;We write and design our API very carefully, but when we perform penetration tests we usually find many problems. In this article I'll tell about a technique to project REST API and structure the resources, to facilitate and make security controls more effective.&lt;/p&gt;

&lt;p&gt;The basic principle is that we don't perform security check on a group of resources, but on a one single resource or better on URL paths.&lt;/p&gt;

&lt;p&gt;The best practice is to define for each path-HTTPverb couple, a list of user groups that can have access to it. Often this solution is facilitated by the web framework. Below we will see some examples of path protection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET  /api/users     &amp;gt; only authenticated users
POST /api/notes     &amp;gt; only admins
GET  /api/products  &amp;gt; open to all users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take the list of users as an example, and let's assume that a user wants to access to read or modify his data: I believe that the user must access to the resource identified by the following path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/api/users/{id}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The handler of this call should check if the authenticated user is the same of the user identified by id passed as parameter.&lt;/p&gt;

&lt;p&gt;Now let's analyse the order list problem of the specific user. The following one is a bad solution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/orders
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, in order to force the selection of orders by user, we can add a required querystring parameter like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/orders?userId={id}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, we must write code to filter orders by user identifier, and check if the user identifier is accessible from the authenticated user. In this way I dirty the code with conditional check. Moreover, required querystring parameter is not nice to see.&lt;/p&gt;

&lt;p&gt;Another way is filtering orders by user identifier using the identifier inside of the authentication data, for example the JWT token. So, it's not possible to use the same path to get a list of all orders, for example useful for an administration panel.&lt;/p&gt;

&lt;p&gt;Now I'll show my best solution to solve this problem to get a list of user orders.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/users/{id}/orders
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, I recycle the user id validation and expose only the orders connected with the specified user. This is a cleaned solution for paths design and to minimize the code for access checking.&lt;/p&gt;

&lt;p&gt;What if I wanted to access to the full order list?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/orders
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case I set the check directly on the path from web framework, for example, I can authorise only administrators. So, we have two path for orders, one for administration panel, another one for user orders. The security is guaranteed because the user can read only his orders if he isn't an administrator.&lt;/p&gt;

&lt;p&gt;I have just shown you a way to design REST API that allows you to structure resources and sub-resources based on the security rules required by the application domain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwbcorv106m8vm8bl5ffi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwbcorv106m8vm8bl5ffi.png" alt="Image description" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now I want to show how it's possible to implement this type of security on REST API. I will take into consideration Fastify, a famous web framework for Node.js which allows to create fast web api with cleaned and quality code. The programming language used for the following examples is TypeScript.&lt;/p&gt;

&lt;p&gt;With Fastify it's possible to create plugins to extend the framework. In this case, we'll create a plugin to check the jwt token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fp from 'fastify-plugin'
import { jwtDecode } from 'jwt-decode'
import { FastifyAuthFunction } from '@fastify/auth'
import {
    FastifyPluginAsync,
    FastifyReply,
    FastifyRequest
} from 'fastify'

type TUserGroup = 'admin' | 'operator' | 'customer'

declare module 'fastify' {
    interface FastifyInstance {
        jwtAuth: (userGroups: TUserGroup[]) =&amp;gt; FastifyAuthFunction
    }

    interface FastifyRequest {
        authUser: {
            userId: string,
            userGroup: TUserGroup
        }
    }
}

const jwtAuthUtility: FastifyPluginAsync = async server =&amp;gt; {
    const jwtAuth = (userGroups: TUserGroup[]): FastifyAuthFunction =&amp;gt;
        async (request: FastifyRequest, response: FastifyReply) =&amp;gt; {
            const authorization = request.headers.authorization ?? ''

            if (!authorization.startsWith('Bearer ')) {
                response.status(401).send()
            }
            else {
                const token = authorization.replace('Bearer ', '')
                const payload = jwtDecode&amp;lt;{
                    userId: string,
                    userGroup: TUserGroup
                }&amp;gt;(token)

                request.authUser = { ...payload }

                if (!request.authUser.userId ||
                    !request.authUser.userGroup ||
                    !userGroups.includes(request.authUser.userGroup))
                    response.status(401).send()
            }
        }

    server.decorate('jwtAuth', jwtAuth)
}

export default fp(jwtAuthUtility)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above represents a fastify-plugin, which retrieves the jwt token from the HTTP header and decodes it to extract the token payload. We assume that, in the payload, there are a user identifier and a user group. The array of groups passed as parameter is the list of enabled groups. In this example we don't validate the token, but normally we must specify the validation rule for expiration and secret key. Token validation is not important in this case. Notice that token data are copied from payload to the request, so, user identifier and user group are available to the request object. Now let's see how to use the plugin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { FastifyPluginAsync } from 'fastify'
import { findAllOrders } from './repository'

const routes: FastifyPluginAsync = async server =&amp;gt; {
    server.get('/api/orders',
        {
            preValidation: server.jwtAuth(['admin'])
        },
        async () =&amp;gt; findAllOrders()
    )
}

export default routes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this way we've created an endpoint for the path &lt;code&gt;/api/orders&lt;/code&gt; that provides all orders. This endpoint is accessible only for admin users, if another user tries to call it he'll receive the error 401 Unauthorized. So we have written a security control, simple, clean, reusable and effective, which will help us to face the penetration test.&lt;/p&gt;

&lt;p&gt;Now it's time to create a route that responds to path &lt;code&gt;/api/users/{id}&lt;/code&gt; to get the user detail. Notice that this route is opened for admin, operator and customer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    server.get&amp;lt;{ Params: { id: string } }&amp;gt;('/api/users/:id',
        {
            preValidation: server.jwtAuth([
                'admin',
                'operator',
                'customer'
            ]),
            preHandler: (request, response, next) =&amp;gt; {
                checkUser(
                    request.params.id,
                    request.authUser.userId
                ) ? next() :
                    response.status(403).send()
            }
        },
        async (request, response) =&amp;gt; {
            const user = findUser(request.params.id)

            if (!user) {
                response.status(404).send()
            }
            else return user
        }
    )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the first step I check the user with &lt;code&gt;checkUser&lt;/code&gt;, one can think that this function contains logic to determine if the request user is accessibile from the current user. If the current user can't access to the request user, then I return 403 Forbidden. In the second step  I get the user with &lt;code&gt;findUser&lt;/code&gt;, one can think that this function retrieves user from database. If the user is not present on database, then I return 404 Not Found. In case of positive outcome of the two functions seen above, I return the user data with status code 200.&lt;/p&gt;

&lt;p&gt;Now I'll show the route that responds with the orders of the specific user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    server.get&amp;lt;{ Params: { id: string } }&amp;gt;('/api/users/:id/orders',
        {
            preValidation: server.jwtAuth(['customer']),
            preHandler: (request, response, next) =&amp;gt; {
                checkUser(
                    request.params.id,
                    request.authUser.userId
                ) ? next() :
                    response.status(403).send()
            }
        },
        async (request, response) =&amp;gt; {
            const user = findUser(request.params.id)

            if (!user) {
                response.status(404).send()
            }
            else return findOrdersByUser(request.params.id)
        }
    )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above we've seen that the route is accessible only for customer user, so admin user must use the route &lt;code&gt;/api/orders&lt;/code&gt; to get the list of orders. Customer user can access only his orders, and we've chosen that operator user do not access to order list. Notice that we recycled the function &lt;code&gt;checkUser&lt;/code&gt; and so we've centralized his logic.&lt;/p&gt;

&lt;p&gt;Now it's time to talk about how to test this solution to make sure that the next penetration tests will be fine. But we'll talk about this in the next episode.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Do you find this article helpful? Then you’ll love the webinar based on this article! Claranet Italy is going live on Thursday, February 6th, at 12:00 CET with a Securing APIs: Techniques and Best Practices webinar.&lt;br&gt;
It’s going to be public and in English so that everyone is welcome! Also, feel free to invite friends and colleagues.&lt;br&gt;
The speaker for this first session will be &lt;a href="https://dev.to/balastrong"&gt;Leonardo Montini&lt;/a&gt;, who will demonstrate how little changes in the way we design our APIs can make a significant impact on security.&lt;br&gt;
Register now: &lt;a href="https://bit.ly/secure-api-sed-dt" rel="noopener noreferrer"&gt;https://bit.ly/secure-api-sed-dt&lt;/a&gt;&lt;br&gt;
See you there!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>restapi</category>
      <category>fastify</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
