<?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>Forem: Vinicius Lopes</title>
    <description>The latest articles on Forem by Vinicius Lopes (@visepol).</description>
    <link>https://forem.com/visepol</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%2F1019823%2Fac3c9716-f5fd-46f7-be4b-198cfa981a53.png</url>
      <title>Forem: Vinicius Lopes</title>
      <link>https://forem.com/visepol</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/visepol"/>
    <language>en</language>
    <item>
      <title>Load Balancing gRPC traffic with Istio</title>
      <dc:creator>Vinicius Lopes</dc:creator>
      <pubDate>Mon, 17 Feb 2025 03:46:42 +0000</pubDate>
      <link>https://forem.com/visepol/load-balancing-grpc-traffic-with-istio-1k49</link>
      <guid>https://forem.com/visepol/load-balancing-grpc-traffic-with-istio-1k49</guid>
      <description>&lt;p&gt;gRPC has gained a lot of popularity for building microservices. Because it is based on persistent HTTP/2 connections, it offers advantages over regular HTTP calls, such as multiplexing requests over a single connection. However, this protocol’s load balancing may not work out of the box in the Kubernetes environment.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚠️ Houston we have a problem
&lt;/h2&gt;

&lt;p&gt;When working with tens of millions of messages whose traffic needs to be as quick as possible in real-time, indicators such as &lt;strong&gt;&lt;em&gt;SLA&lt;/em&gt;&lt;/strong&gt; (Service Level Agreement) become a major concern. And, as the volume grows, performance degrades, requiring more infrastructure scalability and, in turn, a smaller profit margin. One strategy to optimize the internal network and avoid spending on resources would be to replace all HTTP 1.1 connections between microservices with a single gRPC connection.&lt;/p&gt;

&lt;h3&gt;
  
  
  gRPC
&lt;/h3&gt;

&lt;p&gt;gRPC is a remote procedure call framework created by Google based on HTTP/2. It can set an interface and serialize data through a Protocol Buffer, a binary format less heavy than the PLAIN TEXT format of HTTP 1.1. With gRPC, you set the methods and the types by creating files &lt;code&gt;.proto&lt;/code&gt;. These files can be used to automatically generate the client and the server code for a lot of languages. Additionally, as mentioned, it multiplexes requests into a single connection, which creates less network overhead and speeds up communication.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why do the L4 proxies struggle when operating with gRPC?
&lt;/h3&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%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXfRdovNUm19oCiytyaLMYo3UyF4bx3iOZXaFYaHuRiiDlG79iHrxVTINx6gdoTfmAa__RqDOPotAqZ3G3PD7DHXWTVXirmRHXa6GeMzTyUkhd4CSDt2VXfPaP59OVXcGDGCK0a0_A%3Fkey%3DEdhtX-X6Ht135Qxcy-fyXkdx" 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%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXfRdovNUm19oCiytyaLMYo3UyF4bx3iOZXaFYaHuRiiDlG79iHrxVTINx6gdoTfmAa__RqDOPotAqZ3G3PD7DHXWTVXirmRHXa6GeMzTyUkhd4CSDt2VXfPaP59OVXcGDGCK0a0_A%3Fkey%3DEdhtX-X6Ht135Qxcy-fyXkdx" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above diagram suggests a common use case for traffic balancing. The green pod sees the &lt;code&gt;SVC&lt;/code&gt;, which sees the other blue pods. This should be enough to do a simple round-robin when we are talking about conventional HTTP. But here we are talking about HTTP/2, which establishes a long-lived connection, through which all requests must pass to reach their destination. Load balances that operate at layer four of &lt;a href="https://en.wikipedia.org/wiki/OSI_model" rel="noopener noreferrer"&gt;&lt;strong&gt;the OSI model&lt;/strong&gt;&lt;/a&gt; (L4) only decide the destination at the beginning of the connection, all subsequent requests under this connection will go to the same server, which leads to poor load distribution. L4 proxies handle connections, not requests. They have no visibility of what happens inside the connection.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do we operate over the L7 layer?
&lt;/h3&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%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXcnyf5fQrYyTMse50sGWyyZs0FNGHTnCfKH1NOXQlTonbmBdd7k32XZpniWPPOQrXiWSPRmRgM2HoTNCOm71EAx7oQzToqRI5w_IHq5LWEd_FpJQIyzkYXBFXUk7c_-5J63-fKb6Q%3Fkey%3DEdhtX-X6Ht135Qxcy-fyXkdx" 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%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXcnyf5fQrYyTMse50sGWyyZs0FNGHTnCfKH1NOXQlTonbmBdd7k32XZpniWPPOQrXiWSPRmRgM2HoTNCOm71EAx7oQzToqRI5w_IHq5LWEd_FpJQIyzkYXBFXUk7c_-5J63-fKb6Q%3Fkey%3DEdhtX-X6Ht135Qxcy-fyXkdx" width="800" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Proxies operating at this layer have visibility into the packet content and can make different decisions regarding the delivery destination. This is where Istio comes in. Istio can provide a service mesh that deploys proxies as sidecar containers alongside the application container. Instead of a centralized entry point, the sidecar interacts with the Istio control plane, which in turn interacts directly with the Kubernetes API to retrieve the destination endpoints. In this way, the sidecar establishes a continuous and direct connection to all available endpoints, and then performs routing based on the rules that are defined.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌐 Istio: The Service Mesh
&lt;/h2&gt;

&lt;p&gt;What is it? Istio is a service mesh. And to understand what this means, we need to understand what a service mesh is. &lt;/p&gt;

&lt;p&gt;A service mesh is a widely used solution to manage communication between microservices individually. It solves problems such as poor load balancing by operating at the application layer, and also adds retries in case of communication failure, traffic metrics, and security.&lt;/p&gt;

&lt;p&gt;Using a sidecar, all these responsibilities are abstracted and the application only needs to worry about the logical layer in its implementation. This is done through the Istio Control Plane, which injects a sidecar proxy container into the pod along with the application. The applications now communicate with each other through these proxies. This network layer is composed of: a control plane and proxies, that is the service mesh.&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%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXeGFsoW8n9M6miOBj9T1Tkyo6vBC--IO1YZ6j-Jwh4jmZj2zSO19W67zoUwHTZr3MrHgwuz8eIRfSwTvNLh5gjzRwgSrxq9-hs_7yrWciscWcqqkpu4n3biJaVUCSbxgNpSZUqrOw%3Fkey%3DEdhtX-X6Ht135Qxcy-fyXkdx" 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%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXeGFsoW8n9M6miOBj9T1Tkyo6vBC--IO1YZ6j-Jwh4jmZj2zSO19W67zoUwHTZr3MrHgwuz8eIRfSwTvNLh5gjzRwgSrxq9-hs_7yrWciscWcqqkpu4n3biJaVUCSbxgNpSZUqrOw%3Fkey%3DEdhtX-X6Ht135Qxcy-fyXkdx" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Hands-On
&lt;/h2&gt;

&lt;p&gt;In a local environment, for demonstration purposes, I am using MicroK8s, maintained by Canonical. In production environments, add-ons can be installed by tools such as Helm. In MicroK8s, add-ons can be enabled directly from the command line.&lt;/p&gt;

&lt;p&gt;First, let's enable third party and community maintained add-ons with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s &lt;span class="nb"&gt;enable &lt;/span&gt;community
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, enable Istio by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s &lt;span class="nb"&gt;enable &lt;/span&gt;istio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should add:&lt;/p&gt;

&lt;p&gt;✔ &lt;strong&gt;Istio core installed&lt;/strong&gt;                                                                &lt;br&gt;
✔ &lt;strong&gt;Istiod installed&lt;/strong&gt;                                             &lt;br&gt;
✔ &lt;strong&gt;Egress gateways installed&lt;/strong&gt;                                                 &lt;br&gt;
&lt;strong&gt;✔ Ingress gateways installed&lt;/strong&gt;                                                        &lt;br&gt;
&lt;strong&gt;✔ Installation complete&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now let's set up a namespace for the lab. It will be named &lt;code&gt;serivce-mesh-lab&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;microk8s kubectl apply -f - &amp;lt;&amp;lt;EOF&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;  name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service-mesh-lab&lt;/span&gt;
&lt;span class="na"&gt;  labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;    istio-injection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;enabled&lt;/span&gt;
&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;em&gt;Notice that there is a label called &lt;strong&gt;istio-injection&lt;/strong&gt; with the value set to &lt;strong&gt;enabled&lt;/strong&gt;. This label is how the Istio Control Plane knows that it will need to inject a sidecar proxy into the pods under this namespace.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Building the gRPC application
&lt;/h3&gt;

&lt;p&gt;I have made available a repository that performs message transmission between client and server via gRPC in a simple way. Clone the repository using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git@github.com:visepol/grpc-relay.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it is necessary to build the images.  &lt;/p&gt;

&lt;p&gt;To build the client, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; grpc-client:local &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;APP_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;client &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To build the server run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; grpc-server:local &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;APP_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;server &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding an image to the local registry
&lt;/h3&gt;

&lt;p&gt;Kubernetes is not aware of the newly built images. We can export the built image from the local Docker daemon and import it into the MicroK8s local registry like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker save grpc-client:local &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; grpc-client.tar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker save grpc-server:local &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; grpc-server.tar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then import with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s ctr image import grpc-client.tar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s ctr image import grpc-server.tar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we can deploy the applications for analysis in two namespaces.&lt;/p&gt;

&lt;p&gt;The first will be in the default namespace, where we will use the default L4 proxy to distribute messages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; ./kubernetes &lt;span class="nt"&gt;-n&lt;/span&gt; default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second will be in the namespace we created, service-mesh-lab, where the proxies will be injected as a sidecar to operate in L7.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;microk8s kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; ./kubernetes &lt;span class="nt"&gt;-n&lt;/span&gt; service-mesh-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🎥 Demo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A look at the Code
&lt;/h3&gt;

&lt;p&gt;The code below shows the contents of the gRPC Server. Note that on line 6 a UUID is generated to identify the message receiver in the gRPC Client. Next, the &lt;code&gt;IExampleServer&lt;/code&gt; interface is implemented on line 12, ensuring adherence to the contract defined in &lt;code&gt;.proto&lt;/code&gt;. The service is then added to the server on line 33, making the methods available to the client. On line 40 I use &lt;code&gt;.createInsecure()&lt;/code&gt; to make the Demo easier. In production environments, the use of TLS is ideal.&lt;/p&gt;

&lt;p&gt;The code (&lt;a href="https://github.com/visepol/grpc-relay/blob/main/_server.ts" rel="noopener noreferrer"&gt;on Github&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;grpc&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@grpc/grpc-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;IExampleServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ExampleService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./generated/example_grpc_pb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DataResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./generated/example_pb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;randomUUID&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uuid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Implements the ExampleService defined in the proto file.
 * @type {IExampleServer}
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exampleService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IExampleServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/**
   * Handles the sendData RPC call.
   * @param {grpc.ServerUnaryCall&amp;lt;DataRequest, DataResponse&amp;gt;} call - The call object containing the request.
   * @param {grpc.sendUnaryData&amp;lt;DataResponse&amp;gt;} callback - The callback to send the response.
   */&lt;/span&gt;
  &lt;span class="na"&gt;sendData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Received message:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMessage&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DataResponse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setReply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`Hello, I'm &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. You sent: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMessage&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;grpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Adds the ExampleService to the gRPC server.
 */&lt;/span&gt;
&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ExampleService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;exampleService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Binds the server to the specified address and starts it.
 */&lt;/span&gt;
&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bindAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.0.0.0:50051&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;grpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ServerCredentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createInsecure&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Server's up—smooth as a race car! 🏎️💨&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code below shows the content of the gRPC Client. In line 10 I use the K8s metadata to set the &lt;code&gt;SVC&lt;/code&gt; that I should point to and in line 11 I avoid the use of TLS again. The request is instantiated from the model generated by ProtoBuff in line 18. And finally, in line 23, I define the continuous sending of messages within a 10-second window.&lt;/p&gt;

&lt;p&gt;The code (&lt;a href="https://github.com/visepol/grpc-relay/blob/main/_client.ts" rel="noopener noreferrer"&gt;on Github&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;grpc&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@grpc/grpc-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ExampleClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./generated/example_grpc_pb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DataRequest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./generated/example_pb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Creates a new gRPC client for the ExampleService.
 * @type {ExampleClient}
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExampleClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ExampleClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;`grpc-service.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;K8S_NAMESPACE&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.svc.cluster.local:50051`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;grpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createInsecure&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Creates a new DataRequest object.
 * @type {DataRequest}
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DataRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DataRequest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Sends a message to the gRPC server every 10 seconds.
 */&lt;/span&gt;
&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, gRPC!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server reply:`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getReply&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;Let's analyze the communication established in the default namespace:&lt;/p&gt;

&lt;p&gt;✳️ Each pod contains only one container, indicated by the single green square in the containers column. This indicates that the application is running stand-alone.&lt;/p&gt;

&lt;p&gt;✳️ The client gRPC received messages only from the server with UUID &lt;code&gt;efd7bef0-0148-4296-b243-3262c7d82fd1&lt;/code&gt;. Once the connection was established all responses were issued by the same gRPC server.&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%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXeZ8TUueeuegW5TuCNwLzySWAeXpDTYHfw84gB0M048jvrr9HUfAufNV0uAmHt4KyfBZ_TxG-7fAxjypWlQh_aZr0z3gXeD1SN3lpZAZh4rHKwwGpScvFB3MOblnzHasKyaPSAZ%3Fkey%3DEdhtX-X6Ht135Qxcy-fyXkdx" 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%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXeZ8TUueeuegW5TuCNwLzySWAeXpDTYHfw84gB0M048jvrr9HUfAufNV0uAmHt4KyfBZ_TxG-7fAxjypWlQh_aZr0z3gXeD1SN3lpZAZh4rHKwwGpScvFB3MOblnzHasKyaPSAZ%3Fkey%3DEdhtX-X6Ht135Qxcy-fyXkdx" width="800" height="794"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's analyze the communication established in the service-mesh-lab namespace:&lt;/p&gt;

&lt;p&gt;✳️ There were three containers inside each pod. An ephemeral container for sidecar injection, a container that remains alive and running which is the injected proxy, and another standing container which is the application itself.&lt;/p&gt;

&lt;p&gt;✳️ The Server reply that is logged by the gRPC client indicates different UUIDs. This means that more than one gRPC server is responding to the same client.&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%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXcWk72yOtS68MUoxHd_VsoaxNNIZIA49b2MzgkW3MjjvH6rKvRrPSkxeNRpkD3uSX-otUx2pWUtcWgeEKbX7ANotin6m3X-3XBZLmf2z_PL1LhVEYjeLYR7YLEmwOddZ8D41FAyug%3Fkey%3DEdhtX-X6Ht135Qxcy-fyXkdx" 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%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXcWk72yOtS68MUoxHd_VsoaxNNIZIA49b2MzgkW3MjjvH6rKvRrPSkxeNRpkD3uSX-otUx2pWUtcWgeEKbX7ANotin6m3X-3XBZLmf2z_PL1LhVEYjeLYR7YLEmwOddZ8D41FAyug%3Fkey%3DEdhtX-X6Ht135Qxcy-fyXkdx" width="800" height="794"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🚦 Advanced Routing &amp;amp; Balancing
&lt;/h2&gt;

&lt;p&gt;Istio allows you to configure load balancing and routing through &lt;a href="https://istio.io/latest/docs/reference/config/networking/destination-rule/" rel="noopener noreferrer"&gt;DestinationRules&lt;/a&gt; and &lt;a href="https://istio.io/latest/docs/reference/config/networking/virtual-service/" rel="noopener noreferrer"&gt;VirtualServices&lt;/a&gt;. Configurations are defined through YAML manifests and you can choose between different load balancing algorithms, such as round-robin or least-conn. As for routing, Istio allows you to direct traffic based on headers, paths, and other criteria to different subsets of a service. Explore more about these and other features by browsing &lt;a href="https://istio.io/latest/docs/reference/config/networking/" rel="noopener noreferrer"&gt;the official documentation.&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Final Considerations
&lt;/h2&gt;

&lt;p&gt;gRPC is a great solution for improving the speed of your internal network, but to get the most out of the solution, you need to provide an environment that meets the requirements. Istio is a great way to make your network more robust, providing a service mesh standard with proxies acting on layer seven of the OSI model. This ensures not only the proper balancing of packet traffic in persistent connections but also promotes security with internal encryption, traffic metrics, and more routing strategies.&lt;/p&gt;

&lt;h3&gt;
  
  
  References:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/OSI_model" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/OSI_model&lt;/a&gt;&lt;br&gt;
&lt;a href="https://grpc.io/blog/grpc-load-balancing/" rel="noopener noreferrer"&gt;https://grpc.io/blog/grpc-load-balancing/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://istio.io/latest/docs/overview/what-is-istio/" rel="noopener noreferrer"&gt;https://istio.io/latest/docs/overview/what-is-istio/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://istio.io/latest/docs/setup/platform-setup/microk8s/" rel="noopener noreferrer"&gt;https://istio.io/latest/docs/setup/platform-setup/microk8s/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://istio.io/latest/docs/reference/config/networking/" rel="noopener noreferrer"&gt;https://istio.io/latest/docs/reference/config/networking/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://istio.io/latest/docs/reference/config/networking/destination-rule/" rel="noopener noreferrer"&gt;https://istio.io/latest/docs/reference/config/networking/destination-rule/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://istio.io/latest/docs/reference/config/networking/virtual-service/" rel="noopener noreferrer"&gt;https://istio.io/latest/docs/reference/config/networking/virtual-service/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://microk8s.io/docs/addons" rel="noopener noreferrer"&gt;https://microk8s.io/docs/addons&lt;/a&gt;&lt;br&gt;
&lt;a href="https://microk8s.io/docs/registry-images" rel="noopener noreferrer"&gt;https://microk8s.io/docs/registry-images&lt;/a&gt;&lt;/p&gt;

</description>
      <category>istio</category>
      <category>grpc</category>
      <category>kubernetes</category>
      <category>typescript</category>
    </item>
    <item>
      <title>OAuth2, JWT, and JWKS: Using Amazon Cognito as IdP</title>
      <dc:creator>Vinicius Lopes</dc:creator>
      <pubDate>Wed, 27 Nov 2024 00:16:01 +0000</pubDate>
      <link>https://forem.com/visepol/oauth2-jwt-and-jwks-using-amazon-cognito-as-idp-1jod</link>
      <guid>https://forem.com/visepol/oauth2-jwt-and-jwks-using-amazon-cognito-as-idp-1jod</guid>
      <description>&lt;p&gt;The amount of interconnected applications on the web has grown significantly over the last decade. With it, the number of threats aimed at fraud or other malicious actions has also increased. OAuth, now in version 2.0, emerges as a protocol to define how these applications should communicate with each other without compromising the security of the transmitted information and ensuring its authenticity.&lt;/p&gt;

&lt;p&gt;This article will discuss how this protocol works and how we can implement it modern and securely using JWT tokens and validating with JWKS. The content here can be used as a guide for beginners who have yet to become familiar with the mentioned concepts.&lt;/p&gt;




&lt;h2&gt;
  
  
  OAuth 2.0
&lt;/h2&gt;

&lt;p&gt;OAuth2 is an authorization protocol that allows third-party applications to access a user's resources without directly exposing their credentials. Instead, OAuth2 uses access tokens, which are limited in scope and time.&lt;/p&gt;

&lt;p&gt;✨ OAuth2 defines four actors&lt;/p&gt;

&lt;p&gt;✳️ &lt;strong&gt;Resource Owner&lt;/strong&gt;:     This entity has access rights to the resource, which grants the credentials. It is typically classified as a user.&lt;/p&gt;

&lt;p&gt;✳️ &lt;strong&gt;Resource Server&lt;/strong&gt;:     This is the API exposed on the web that contains the user's data. Access to this data is granted through a token issued by the following actor, the Authorization Server.&lt;/p&gt;

&lt;p&gt;✳️ &lt;strong&gt;Authorization Server&lt;/strong&gt;:     Responsible for authentication, it is the one who receives the user's credentials and returns an access token. The tokens issued can be rich, containing information about the Resource Owner, or opaque, provided only as a signed key. This token grants access to the Resource Server.&lt;/p&gt;

&lt;p&gt;✳️ &lt;strong&gt;Client&lt;/strong&gt;:     This is the application that effectively interacts with the Resource Owner, such as a browser or another HTTP client.&lt;/p&gt;

&lt;p&gt;This flow demonstrates, in a simplified way, the relationship between the actors involved.&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%2Fjulp2kax5jo8gll10cln.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%2Fjulp2kax5jo8gll10cln.png" alt="oauth flow" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Bearer Token &amp;amp; JWT (JSON Web Token): &lt;br&gt; The Language of Tokens
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Bearer Token
&lt;/h3&gt;

&lt;p&gt;In practical terms, a Bearer Token is the access token issued by the Authorization Server to be sent to the APIs via Header, granting access to the content. The most widely adopted implementation format is JWT. However, the OAuth 2.0 protocol does not mention JWT as a standard. RFC 6750 only specifies the nature of the token as an authentication string but is broad regarding formats and structures.&lt;/p&gt;

&lt;h3&gt;
  
  
  JWT
&lt;/h3&gt;

&lt;p&gt;It is a token standard whose format allows it to be transmitted between two parties. It not only authorizes access to resources but also carries other relevant information through claims. It has a set of rules, both for issuance and validation, that must be followed to comply with the format. This format allows information to be transmitted securely over an insecure channel.&lt;/p&gt;

&lt;p&gt;A JWT token follows this format:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔴eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.&lt;br&gt;
🔵eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.&lt;br&gt;
🟢SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This sequence is composed of three segments: &lt;br&gt;
🔴Header, 🔵Payload, and 🟢Signature.&lt;/p&gt;
&lt;h4&gt;
  
  
  Header
&lt;/h4&gt;

&lt;p&gt;It includes a small JSON that stores data about the token type and the encryption algorithm used.&lt;/p&gt;
&lt;h4&gt;
  
  
  Payload
&lt;/h4&gt;

&lt;p&gt;Also in JSON, it carries the user's Claims. Claims contain data that the API uses to verify a user's access rights to the resource and, at times, share information with other services and applications.&lt;/p&gt;
&lt;h4&gt;
  
  
  Signature
&lt;/h4&gt;

&lt;p&gt;The signature is formed by the Header and Payload encoded in Base64. Then, a password is combined using the encryption algorithm specified in the Header, thus forming the final key.&lt;/p&gt;

&lt;p&gt;The signature protects the token against malicious changes, ensuring the authenticity of the information being transmitted. Attacks like man-in-the-middle are unable to forge the Claims content, as they do not have the password to generate a new signature.&lt;/p&gt;


&lt;h2&gt;
  
  
  JWKS (JSON Web Key Set):  &lt;br&gt; Public Key Management
&lt;/h2&gt;

&lt;p&gt;A JWKS is a set of public keys made available through an endpoint of the token issuer itself to validate JWT signatures. When using asymmetric cryptography, meaning a key pair to sign the token instead of a unique secret (symmetric cryptography), only the Authorization Server has access to the private key, and the public keys are shared so that applications can validate whether the token was indeed issued by the Authorization Server.&lt;/p&gt;

&lt;p&gt;Take a look at an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"keys"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"kty"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RSA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"e"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AQAB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"use"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sig"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"kid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ca761cd3-8092-46be-926b-ef28465ff942"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"n"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"oXAP360uf_9_KXTCk6BiQOgwQJlqoycCbsukFtoUCmn57jM-9n2uqBBPT_8VnTIaYr4h8zxMy8HRkdX35HRmZANoqekhH03hhMc69mK4yEYZwBNyV9SteXrF5hfj4SWsK0t3CZ_G_U303XLj7ak5m-4w1UXCmvBERR_SwXjLOKwAAFlOQS_0sAB9yzvJkvsuvqd4lA3-vFFF_ZVbTHuJAznqB_avwCbCHJWfiWln2PN7LsieX08tE13bPP1TVEFid9mcUz5dwz0J9QKTYCd90fkyzqanzG638SFoyL84ddmD_9pef5x03oMWEU9-dxEI6PFfWEQmXN1eg7GfJI6bxQ"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One of the fields is &lt;strong&gt;&lt;em&gt;kid&lt;/em&gt;&lt;/strong&gt;, which is a key identifier, also present in the JWT header. It is through this identifier that we know which key in the JWKS set will be used to validate the signature of our token.&lt;/p&gt;




&lt;h2&gt;
  
  
  AWS Cognito: Identity Provider
&lt;/h2&gt;

&lt;p&gt;Cognito is an AWS service that manages identity and access. It acts as a user directory, capable of storing and validating data, authenticating access, and securely providing identity. We can store fields such as email, name, phone, birthdate, nickname, gender, or any other information through custom attributes. In addition, Cogito offers multiple ways to log in to the same resource.&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo with JWKS
&lt;/h3&gt;

&lt;p&gt;Let's break down a TypeScript project that implements the OAuth 2.0 solution using Cognito as the identity provider. The goal here will be to retrieve an access token using the credentials provided by an HTTP Client and validate the token's signature against a JWKS keychain.&lt;/p&gt;

&lt;h3&gt;
  
  
  User Pool Creation
&lt;/h3&gt;

&lt;p&gt;First, we need to configure our provider. Access the AWS Management Console and search for Cognito. Navigate to the service and look for the &lt;strong&gt;Create user pool&lt;/strong&gt; option. There are a total of 6 steps, the last one being a review of the options selected before creating the user pool. I will display my final step, highlighting the selected options and emphasizing what is relevant to the demonstration.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sign-in experience:
&lt;/h4&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%2Fkx5gtu9gcks0hth35mrb.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%2Fkx5gtu9gcks0hth35mrb.png" alt="Sign-in experience" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  User name is enabled as a login option.&lt;/li&gt;
&lt;li&gt;  Email is enabled as a login option.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Security requirements:
&lt;/h4&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%2Fmn3w3nj4pusgsiqm0aj8.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%2Fmn3w3nj4pusgsiqm0aj8.png" alt="Security requirements" width="800" height="588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  I used Cognito's default policy for user password definition.&lt;/li&gt;
&lt;li&gt;  MFA is disabled.&lt;/li&gt;
&lt;li&gt;  Self-service account recovery option is disabled.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Sign-up experience:
&lt;/h4&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%2Fere3o2p728iokzmwxtsa.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%2Fere3o2p728iokzmwxtsa.png" alt="Sign-up experience" width="800" height="691"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Self-registration is disabled, users will be created directly in the console for demo purposes.&lt;/li&gt;
&lt;li&gt;  None of the default attributes are mandatory.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Message delivery:
&lt;/h4&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%2F3mvhkmo80czqxe55gkb7.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%2F3mvhkmo80czqxe55gkb7.png" alt="Message delivery" width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  I am not using SES for sending emails.&lt;/li&gt;
&lt;li&gt;  I am not using SNS to send any type of notification.&lt;/li&gt;
&lt;li&gt;  I selected the option Send email with Cognito.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Integrate your app:
&lt;/h4&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%2Fs0tlz6ax1rjn74eb2nvv.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%2Fs0tlz6ax1rjn74eb2nvv.png" alt="Integrate your app" width="800" height="669"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  I added the following authentication flows: &lt;strong&gt;ALLOW_REFRESH_TOKEN_AUTH&lt;/strong&gt;, &lt;strong&gt;ALLOW_USER_SRP_AUTH&lt;/strong&gt; and &lt;strong&gt;ALLOW_USER_PASSWORD_AUTH&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  My User pool name will be byte-terrier-idp&lt;/li&gt;
&lt;li&gt;  My App type will be Public client&lt;/li&gt;
&lt;li&gt;  And finally, My App client name will be aws-cognito-w-jwks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With everything set up, access: &lt;em&gt;&lt;code&gt;cognito -&amp;gt; user pools -&amp;gt; “the-pool-created”&lt;/code&gt;&lt;/em&gt;&lt;br&gt;
Now, you should see a screen similar to this:&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%2Fk76c3y7lpscxc61n0hp0.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%2Fk76c3y7lpscxc61n0hp0.png" alt="idp" width="800" height="208"&gt;&lt;/a&gt;&lt;br&gt;
Take note of two items from the screen, as these values will be used later in the demo.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  User pool ID, It is the identifier of your pool.&lt;/li&gt;
&lt;li&gt;  Token signing key URL, this is the JWKS endpoint where the set of public keys for validation will be available.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  User Creation
&lt;/h3&gt;

&lt;p&gt;Still in the created pool, look for the &lt;strong&gt;Create user&lt;/strong&gt; option. A new page should appear. Once again, I have listed the options that should be selected.&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%2Fbb2g1nxbbclee5lx5f4p.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%2Fbb2g1nxbbclee5lx5f4p.png" alt="User Creation" width="800" height="689"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The user will be able to log in with either the Username or the Email.&lt;/li&gt;
&lt;li&gt;  The user will not receive any type of invitation.&lt;/li&gt;
&lt;li&gt;  The username will be Meyer (it's the name of my dog).&lt;/li&gt;
&lt;li&gt;  The email will be &lt;a href="mailto:meyer@boston.com"&gt;meyer@boston.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  A temporary password will be created.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click on &lt;strong&gt;Create user&lt;/strong&gt;. A new user will be created but with the status &lt;strong&gt;Force change password&lt;/strong&gt;. Since the goal here is only to perform a demo and not an end-to-end implementation, I will force the user's password through CLI. I am assuming that your AWS credentials are correctly configured in the environment.&lt;/p&gt;

&lt;p&gt;Check at: &lt;em&gt;&lt;code&gt;~/.aws/credentials&lt;/code&gt;&lt;/em&gt;&lt;br&gt;
If they are not, here’s how to set them up: &lt;a href="https://docs.aws.amazon.com/pt_br/cli/latest/userguide/cli-chap-configure.html" rel="noopener noreferrer"&gt;Configuring AWS CLI Credentials&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run the following command, making the necessary replacements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws cognito-idp admin-set-user-password &lt;span class="nt"&gt;--user-pool-id&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;your-user-pool-id&amp;gt;'&lt;/span&gt; &lt;span class="nt"&gt;--username&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;your-username&amp;gt;'&lt;/span&gt; &lt;span class="nt"&gt;--password&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;your-new-password&amp;gt;'&lt;/span&gt; &lt;span class="nt"&gt;--permanent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws cognito-idp admin-set-user-password &lt;span class="nt"&gt;--user-pool-id&lt;/span&gt; &lt;span class="s1"&gt;'us-east-1_ErtWYLogU'&lt;/span&gt; &lt;span class="nt"&gt;--username&lt;/span&gt; &lt;span class="s1"&gt;'meyer'&lt;/span&gt; &lt;span class="nt"&gt;--password&lt;/span&gt; &lt;span class="s1"&gt;'t!)l5T$C825l'&lt;/span&gt; &lt;span class="nt"&gt;--permanent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should change the user's status to &lt;strong&gt;Confirmed.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  App Client
&lt;/h3&gt;

&lt;p&gt;Finally, go to: &lt;em&gt;&lt;code&gt;App integration -&amp;gt; App client list&lt;/code&gt;&lt;/em&gt;&lt;br&gt;
...and find the app's Client. This ID will be needed for integration between the AWS SDK and Cognito.&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%2Fvr460kf2pc9nxt9uhavp.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%2Fvr460kf2pc9nxt9uhavp.png" alt="App client list" width="800" height="160"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  A look at the code
&lt;/h2&gt;

&lt;p&gt;I created a simple HTTP API in TypeScript for us to dissect and analyze how the integration with Cognito works using the AWS SDK. For better tracking, you might want to clone the repository to your machine, which can be done using the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:vynnux/aws-cognito-w-jwks.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the directory structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/aws-cognito-w-jwks
├── .env.example
├── .gitignore
├── package-lock.json
├── package.json
├── request.http
└── src
    ├── app.ts
    ├── server.ts
    ├── http
    │ ├── _routes.ts
    │ ├── authenticate.controller.ts
    │ └── verify-jwt.controller.ts
    └── lib
        ├── cognito.ts
        └── jwks.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the server
&lt;/h3&gt;

&lt;p&gt;To start the project we must define the environment variables. Create a new file named &lt;code&gt;.env&lt;/code&gt; based on &lt;code&gt;.env.example&lt;/code&gt; and set the values according to what is shown in your user pool. &lt;/p&gt;

&lt;p&gt;Here is a description of each one for better understanding:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;COGNITO_CLIENT_ID&lt;/code&gt;&lt;/strong&gt; - This is the Application's Client ID, which can be found in the App client list. It should be unique for each application, for better management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;AWS_REGION&lt;/code&gt;&lt;/strong&gt; - This is the region where the user pool that was created is located.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;JWKS_URI&lt;/code&gt;&lt;/strong&gt; - This is the JWKS endpoint for querying public keys. It appears in the main dashboard of the User Pool.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;DEBUG&lt;/code&gt;&lt;/strong&gt; &lt;em&gt;(optional)&lt;/em&gt; - When set to the value - jwks, it increases verbosity for the jwks-rsa dependency, which we use to validate the token signature.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Moving on… Now, we need to install the project dependencies. Run &lt;strong&gt;npm&lt;/strong&gt; to download the packages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once completed, we are ready to start our server, which will listen on port &lt;strong&gt;3000&lt;/strong&gt;. Run...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything goes well, your output should be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;🍃 HTTTP Server Running.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Analysis
&lt;/h3&gt;

&lt;p&gt;There’s no reason to cover the entire code in this article; in short, it’s an API built with Fastify. Both controllers perform some processing and validation before actually executing their actions. Feel free to take a look at the other files, but here, we will focus on &lt;code&gt;cognito.ts&lt;/code&gt; and &lt;code&gt;jwks.ts&lt;/code&gt; under the lib folder.  &lt;/p&gt;

&lt;h4&gt;
  
  
  cognito.ts
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;/authenticate&lt;/code&gt; route is responsible for generating the JWT token. This is where the user credentials are passed via the &lt;em&gt;POST&lt;/em&gt; method. If we open the &lt;code&gt;request.http&lt;/code&gt; file, located at the root of the project, we will see…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;POST http://localhost:3000/authenticate HTTP/1.1
content-type: application/json

&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="s2"&gt;"username"&lt;/span&gt;: &lt;span class="s2"&gt;"meyer"&lt;/span&gt;,
&lt;span class="s2"&gt;"password"&lt;/span&gt;: &lt;span class="s2"&gt;"t!)l5T&lt;/span&gt;&lt;span class="nv"&gt;$C825l&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This request should return the following response:&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%2Fg51mytgjn84py4otnqps.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%2Fg51mytgjn84py4otnqps.png" alt="authenticate" width="800" height="442"&gt;&lt;/a&gt;&lt;br&gt;
In username field, we must pass the username that was registered. The interesting thing here is that, as mentioned previously, Cognito supports several login methods, and one of the methods we enabled was via email. Therefore, we could log in as the same user using a different credential, in this case, &lt;a href="mailto:meyer@boston.com"&gt;meyer@boston.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As for the password, we must pass the permanent password that we set for the user, the one we defined using the AWS CLI.&lt;/p&gt;

&lt;p&gt;The code (&lt;a href="https://github.com/visepol/aws-cognito-w-jwks/blob/main/src/lib/cognito.ts" rel="noopener noreferrer"&gt;on Github&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;CognitoIdentityProviderClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;InitiateAuthCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;InitiateAuthCommandInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-sdk/client-cognito-identity-provider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AWS_REGION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AWS_REGION&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;us-east-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;COGNITO_CLIENT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COGNITO_CLIENT_ID&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cognitoClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CognitoIdentityProviderClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AWS_REGION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Get a JWT token from Cognito using the USER_PASSWORD_AUTH flow
 * @param {string} username - The login credential of the user
 * @param {string} password - The password credential of the user
 * @returns {Promise&amp;lt;string | undefined&amp;gt;} - The JWT Token
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getJwtToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InitiateAuthCommandInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;AuthFlow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;USER_PASSWORD_AUTH&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ClientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;COGNITO_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;AuthParameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;USERNAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InitiateAuthCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cognitoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AuthenticationResult&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;IdToken&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we make the request, the data is delivered to the &lt;code&gt;getJwtToken&lt;/code&gt; function (line 20), which in turn initializes an AWS Client to interact with our IdP (Cognito). We tell the Client that the authentication flow to be used will be &lt;code&gt;USER_PASSWORD_AUTH&lt;/code&gt; (line 25), meaning authentication via username and password. If the authentication is successful, the token is returned. Otherwise, the controller will set the HTTP status 401, which is unauthorized access.&lt;/p&gt;

&lt;h4&gt;
  
  
  jwks.ts
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;/verify-jwt&lt;/code&gt; route (&lt;em&gt;GET&lt;/em&gt;) is responsible for validating the signature of our token. We must add a header - &lt;em&gt;Authorization&lt;/em&gt; - with the value Bearer + jwt. The controller will sanitize the token, removing the Bearer prefix before invoking the &lt;code&gt;validateTokenSignature&lt;/code&gt; method in the &lt;code&gt;jwks.ts&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The full request looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;GET http://localhost:3000/verify-jwt HTTP/1.1
content-type: application/json

Authorization: Bearer eyJra...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fi5kqplccnl10oqxqk9kx.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%2Fi5kqplccnl10oqxqk9kx.png" alt="verify jwt" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code (&lt;a href="https://github.com/visepol/aws-cognito-w-jwks/blob/main/src/lib/jwks.ts" rel="noopener noreferrer"&gt;on Github&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jsonwebtoken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;jwksClient&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jwks-rsa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;JWKS_URI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;JWKS_URI&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JWKSValidationError&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;JWKSValidationError&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Validate the signature of a JWT Token against the JWKS URI
 * @param {string} token - The JWT Token to verify
 * @returns {Promise&amp;lt;void&amp;gt;} - Promise that resolves if the token is valid
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateTokenSignature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;jwksClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;jwksUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JWKS_URI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})?.&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JWKSValidationError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signingKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSigningKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;signingKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JWKSValidationError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;signingKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPublicKey&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;algorithms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RS256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decoded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decoded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;jwks.ts&lt;/code&gt;, on line 18, a JWKS Client is created to fetch the JSON containing the collection of public keys. On line 22, we decode the token to extract its header and locate the &lt;strong&gt;&lt;em&gt;kid&lt;/em&gt;&lt;/strong&gt;, which is the key ID we need to match. On line 27, we search for the key in the set. Finally, on line 30, we create a promise and use &lt;code&gt;jwt.verify&lt;/code&gt; to verify the signature of the keys. The key will be decrypted using the RS256 algorithm and its content must be exactly a base64 of the Header + Payload.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;em&gt;This is why every JWT starts with ey, it is the encoding of {", the beginning of a JSON structure in base64.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If something goes wrong, anything at all, an exception will be thrown, and the controller will reject access to the resource, not displaying the expected response — &lt;strong&gt;&lt;em&gt;HTTP 200 OK&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Considerations
&lt;/h2&gt;

&lt;p&gt;This article covered concepts that promote greater care and security for our user's data. We applied these concepts to one of AWS's services, Cognito, which offers several other strategies beyond the one discussed - such as MFA or SSO. These practices should help prevent malicious attacks and minimize the risk of fraud, as well as being an efficient way to ensure granular access control for your users.&lt;/p&gt;

&lt;p&gt;For more information about Cognito, &lt;a href="https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools.html" rel="noopener noreferrer"&gt;see the official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  References:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/cognito/latest/developerguide/what-is-amazon-cognito.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/cognito/latest/developerguide/what-is-amazon-cognito.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://jwt.io/introduction/" rel="noopener noreferrer"&gt;https://jwt.io/introduction/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://datatracker.ietf.org/doc/html/rfc6750" rel="noopener noreferrer"&gt;https://datatracker.ietf.org/doc/html/rfc6750&lt;/a&gt;&lt;br&gt;
&lt;a href="https://datatracker.ietf.org/doc/html/rfc6749" rel="noopener noreferrer"&gt;https://datatracker.ietf.org/doc/html/rfc6749&lt;/a&gt;&lt;br&gt;
&lt;a href="https://datatracker.ietf.org/doc/html/rfc7519" rel="noopener noreferrer"&gt;https://datatracker.ietf.org/doc/html/rfc7519&lt;/a&gt;&lt;/p&gt;

</description>
      <category>oauth</category>
      <category>cybersecurity</category>
      <category>typescript</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
