<?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: Dan</title>
    <description>The latest articles on Forem by Dan (@phrawzty).</description>
    <link>https://forem.com/phrawzty</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%2F307203%2Fd057f73e-82c8-44df-ac9f-ddd19a60ea05.jpg</url>
      <title>Forem: Dan</title>
      <link>https://forem.com/phrawzty</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/phrawzty"/>
    <language>en</language>
    <item>
      <title>Authorization needs to be dynamic, declarative, and decoupled</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Tue, 12 Nov 2024 10:00:00 +0000</pubDate>
      <link>https://forem.com/cerbos/authorization-needs-to-be-dynamic-declarative-and-decoupled-2omd</link>
      <guid>https://forem.com/cerbos/authorization-needs-to-be-dynamic-declarative-and-decoupled-2omd</guid>
      <description>&lt;p&gt;&lt;em&gt;Guest article written by Fatuma Abdullahi. Thanks! For more great community content and discussions, join our Slack today!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Authorization mechanisms have traditionally been closely tied to the main application logic, and while this works in traditional monolithic systems, maintaining this coupling becomes harder as application complexity grows.&lt;/p&gt;

&lt;p&gt;As authorization is a significant aspect of creating and maintaining secure systems, it is better to have it &lt;a href="https://www.cerbos.dev/features-benefits-and-use-cases/decoupled-authorization" rel="noopener noreferrer"&gt;decoupled&lt;/a&gt; (or "externalized"); that is, to reduce the dependence between authorization and core application logic. Decoupling simultaneously increases the reliability of the authorization functionality whilst decreasing the complexity of the core system itself.&lt;/p&gt;

&lt;p&gt;It is also advantageous to have authorization logic expressed in declarative terms to describe the rules and expected outcomes. This allows the system to make decisions rather than explicitly stating how decisions should be made, making the authorization system accessible to less technical members of an organization. This leads to a dynamic authorization system, or one that makes real-time decisions as requests come in.&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%2Fjk6hfdxa1nfzr39a8is3.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%2Fjk6hfdxa1nfzr39a8is3.png" alt="A flowchart that shows the process for user access to a resource. It starts with " width="800" height="1226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Decoupled, or externalized, authorization
&lt;/h2&gt;

&lt;p&gt;Using an authorization system that is external to your primary system offers some hard-to-beat advantages, including:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enhanced Security&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;External authorization providers are more secure because they are specialized, and are designed from the ground-up with domain-specific experience. They are more aware of the landscape and know what to look out for better than any team whose focus is pulled in many different directions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simpler Policy Management&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;External authorization providers offer a standard way of writing policies and rules, making policy management predictable and allowing the team to move faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Straightforward Scaling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;External authorization systems have the concept of scale built in. They can be adapted at any size, and when the application grows or its authorization needs change, the external system grows with it seamlessly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of externalizing authorization
&lt;/h2&gt;

&lt;p&gt;Decoupling authorization shares advantages with using an external system because both rely on the separation of authorization and business logic as a central pillar. However, additional advantages appear when using an internally-decoupled system. These include:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Increased System Resilience&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Separating authorization logic and rules from your main application increases your systems' resilience as the interdependence between them reduces. This allows your system to withstand outages without affecting all your functions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simplified Workflows&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Keeping authorization external to your primary system simplifies setting up authorization logic and rules. It keeps the teams' focus on how authorization should look independent of any core logic, reducing chances of blind spots and increasing clarity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Easier Maintenance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using separate authorization systems makes maintaining the authorization engine more straightforward because of the decoupling that occurs. This makes it simpler to debug and increases the team's developer experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  RBAC and decoupled authorization
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.cerbos.dev/features-benefits-and-use-cases/rbac" rel="noopener noreferrer"&gt;Role-based access Control (RBAC)&lt;/a&gt; is an authorization technique that uses a user's role in a system to determine what resources they can access. It is a common way to enforce authorization across systems by assigning permissions to roles rather than to individual users and then assigning roles to users. When enforcing decoupled authorization, RBAC is implemented by centralizing all roles and their related permissions across the system.&lt;/p&gt;

&lt;p&gt;There are some trade-offs when using RBAC to manage authorization, including:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Role Explosion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a system grows, the number of roles and permissions might rapidly multiply leading to too many role definitions overall. This makes it harder to manage and reason about the authorization policies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Granular Permissions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sometimes, RBAC is used even in situations better served by more granular access controls. Scenarios requiring dynamic or context-specific permissions might be better served using other techniques like ABAC (Attribute-Based Access Control), which offer more control and flexibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reduced Flexibility&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Making changes to RBAC-based policies can be difficult in a growing system, and changes may cause system-wide repercussions. This can lead to a system being slower in adapting to changing authorization needs.&lt;/p&gt;

&lt;p&gt;It is important to consider these trade-offs when designing RBAC-based authorization policies and to consider whether other access control techniques might be a better fit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorization and microservices architecture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://solutions.cerbos.dev/monolith-to-microservices-migration-ebook" rel="noopener noreferrer"&gt;Microservice architecture&lt;/a&gt; refers to organizing application logic into services that typically carry out one thing and can be deployed independently while loosely coupled. For example, edge functions are microservices.&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%2Fzzzkywpiqsbf32kv7cmk.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%2Fzzzkywpiqsbf32kv7cmk.png" alt="A flowchart diagram showing a client communicating with an API Gateway, which routes requests to four services: Auth Service, User Service, Payment Service, and Notification Service. Each service connects to its respective database: Auth Database, User Database, Payment Database, and Notification Database." width="800" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a system where the backend isn’t distributed in this way (i.e. monolithic architecture), managing authorization queries is reasonably straightforward, as all the data is available in a central location. The challenge with authorization in a microservice architecture is that the services are separated by definition, and often may not talk to each other, making consistent access control and synchronization hard.&lt;/p&gt;

&lt;p&gt;There are several ways to handle authorization in a microservices architecture, including implementing a gateway API (Application Programming Interface) service. Cerbos can be integrated into a microservices architecture as a mechanism deployed alongside microservices (e.g. a sidecar in Kubernetes), such that every service has consistent access to the authorization endpoint.&lt;/p&gt;

&lt;p&gt;This flexible approach ensures that policies stay consistent across the entire system, regardless of the many services involved. This further simplifies policy management while enhancing security.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorization best practices
&lt;/h2&gt;

&lt;p&gt;There are several principles to keep in mind to help make your authorization system robust and to follow best practices, including:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Principle of Least Privilege&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This principle emphasizes that users should only ever have the minimum access to perform the required role and no more. This reduces the risk of unauthorized access and the chances of a breach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Continuous Monitoring and Logging&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Logging authorization requests is good practice. This makes it easier to monitor and detect any anti-patterns. Implementing this makes your authorization system more robust and secure, and it also simplifies compliance and audit procedures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Separation of Concerns&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Keeping authorization logic and policies decoupled increases your system's resilience, as any issues in parts of the application will not bring down the entire system. Additionally, decoupling authorization increases flexibility, extensibility, and maintainability at a system level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn more!
&lt;/h2&gt;

&lt;p&gt;You can learn more about decoupled / externalized authorization using the resources below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.cerbos.dev/blog/authentication-vs-authorization" rel="noopener noreferrer"&gt;AuthN vs AuthZ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cerbos.dev/blog/why-organizations-are-turning-to-decoupled-authorization-solutions" rel="noopener noreferrer"&gt;On decoupled authorization&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>authorization</category>
      <category>authz</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Authentication and authorization in Node.js applications</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Tue, 08 Oct 2024 13:00:00 +0000</pubDate>
      <link>https://forem.com/cerbos/authentication-and-authorization-in-nodejs-applications-12fk</link>
      <guid>https://forem.com/cerbos/authentication-and-authorization-in-nodejs-applications-12fk</guid>
      <description>&lt;p&gt;&lt;em&gt;Thanks to our friendly Cerbos community member—who wishes to remain anonymous—for this tutorial. For more great community content and discussions, &lt;a href="https://go.cerbos.io/slack" rel="noopener noreferrer"&gt;join our Slack&lt;/a&gt; today!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this article, we will discuss authentication and authorization, and how to implement both JWT authentication and Cerbos authorization in a Node.js application.&lt;/p&gt;

&lt;h1&gt;
  
  
  Understanding authentication
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://www.cerbos.dev/blog/authentication-vs-authorization" rel="noopener noreferrer"&gt;Authentication&lt;/a&gt; is the process of verifying the identity of a user. In a Node.js application, we typically authenticate a user based on a set of credentials, such as a username and password, to gain access to the application.&lt;/p&gt;

&lt;p&gt;Some common authentication methods are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Username and password&lt;/li&gt;
&lt;li&gt;Token-based authentication&lt;/li&gt;
&lt;li&gt;Single Sign-On (SSO)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The authentication process works like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The user provides their credentials.&lt;/li&gt;
&lt;li&gt;The server verifies the provided credentials.&lt;/li&gt;
&lt;li&gt;If the credentials are valid, the server generates an authentication token or session ID for the user.&lt;/li&gt;
&lt;li&gt;The newly generated token/session ID is sent back to the client and stored for future use.&lt;/li&gt;
&lt;li&gt;To prove their authenticity, the user includes the token/session ID in each request.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Understanding authorization
&lt;/h1&gt;

&lt;p&gt;Authorization is the process of giving access to users to do specific work/actions. It decides what an authenticated user is allowed to do within the application. After authentication, authorization makes sure that the user only does what they're allowed to do, following specific rules and permissions.&lt;/p&gt;

&lt;p&gt;Some common authentication models are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.cerbos.dev/features-benefits-and-use-cases/rbac" rel="noopener noreferrer"&gt;Role-based access control (RBAC)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cerbos.dev/features-benefits-and-use-cases/abac" rel="noopener noreferrer"&gt;Attribute-based access control (ABAC)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cerbos.dev/features-benefits-and-use-cases/pbac" rel="noopener noreferrer"&gt;Policy-based access control (PBAC)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How does authorization work?
&lt;/h2&gt;

&lt;p&gt;The authorization process works like this: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The authenticated user makes a request to the server.&lt;/li&gt;
&lt;li&gt;The server verifies the user and gets their assigned roles and permissions.&lt;/li&gt;
&lt;li&gt;The server evaluates if the user has permission for the requested actions.&lt;/li&gt;
&lt;li&gt;If the user is authorized, the server allows the user to perform the requested actions.&lt;/li&gt;
&lt;li&gt;Otherwise, it denies access and returns an appropriate error response.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is RBAC?
&lt;/h2&gt;

&lt;p&gt;Role Based Access Control, or RBAC, is an access control method that gives permissions to the user based on their assigned roles within our applications. In simple words, it controls what users can do within the application.&lt;/p&gt;

&lt;p&gt;Instead of assigning permissions to individual users, RBAC groups users into roles, and then assigns permissions to those roles. This makes it easier to manage access control, as we only need to update permissions for a role, rather than for each individual user. &lt;/p&gt;

&lt;p&gt;Key components of RBAC are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Role: Defines a set of responsibilities, tasks, or functions within the application.&lt;/li&gt;
&lt;li&gt;Permissions: Represents specific actions that users can perform.&lt;/li&gt;
&lt;li&gt;Role Assignments: Users are assigned to one or more roles, and each role is associated with a set of permissions.&lt;/li&gt;
&lt;li&gt;Access control policies: Dictate which roles can access particular resources and what actions they can take.&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%2Foeijuj5c5d5ub200d9bw.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%2Foeijuj5c5d5ub200d9bw.png" alt="{User} -- is assigned to --&amp;gt; {Role} -- has --&amp;gt; {Permission} -- grants access to --&amp;gt; {Resource}" width="632" height="624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RBAC is powerful, but implementing and managing it yourself is not easy. The open-source Cerbos PDP (or Policy Decision Point), acts as a &lt;a href="https://www.cerbos.dev/blog/authorization-as-a-service" rel="noopener noreferrer"&gt;stand-alone service&lt;/a&gt;, streamlining access control by centralizing both policy decisions and audit log collection, and decoupling authorization logic from your application. &lt;/p&gt;

&lt;p&gt;Cerbos can function effectively within diverse software environments, from monoliths to fully decentralized architectures. It’s stateless and can be deployed via a Kubernetes sidecar, in a Docker container, or even as a single binary on a virtual machine. Cerbos exposes a rich HTTP API, which makes it language-agnostic, and allows it to interact and scale seamlessly with other services.&lt;/p&gt;

&lt;h1&gt;
  
  
  Implementing authentication and authorization in Node.js
&lt;/h1&gt;

&lt;p&gt;Now that we have an understanding of authentication and authorization, let’s explore how to implement them in our Node.js application. In this section, we’ll build a simple Node.js app and integrate authentication and authorization functionalities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting the project, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js and npm installed on your system.&lt;/li&gt;
&lt;li&gt;Docker installed on your machine (for running the Cerbos container).&lt;/li&gt;
&lt;li&gt;Postman or a similar tool for testing API endpoints.&lt;/li&gt;
&lt;/ul&gt;

&lt;center&gt;

  &lt;a href="https://cta-service-cms2.hubspot.com/web-interactives/public/v1/track/redirect?encryptedPayload=AVxigLJA2octU4MHpvkByVY8c8GGX54s4sv%2FREy0FQ%2BENY%2BVh7GayBJpPBkDBHlFn%2BKRuPaVeZltIDeDoMZ69iqehJYl0A4MPFRzo00stUk2S%2Bttd%2FH6pEZn4tU%2FfISJxM5G0vTcoT514DqmX7ZIbcifP4z4zly5UN2NRmyOeKg%3D&amp;amp;webInteractiveContentId=168994186087&amp;amp;portalId=20289770" rel="noopener noreferrer"&gt;
    &lt;img alt="BlogCTA - PDP" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fno-cache.hubspot.com%2Fcta%2Fdefault%2F20289770%2Finteractive-168994186087.png" width="538" height="277"&gt;
  &lt;/a&gt;

&lt;/center&gt;

&lt;h2&gt;
  
  
  Set up a Node.js project
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create the project
&lt;/h3&gt;

&lt;p&gt;To start with, we need to set up a Node.js project. Run the following command in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will initialize a new Node.js project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install the dependencies
&lt;/h3&gt;

&lt;p&gt;Next, install the required dependencies for our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;express jsonwebtoken dotenv bcryptjs nodemon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will install the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;express&lt;/code&gt;: A popular web framework for Node.js.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;jsonwebtoken&lt;/code&gt;: For generating and verifying JSON Web Tokens (JWT) for authentication.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dotenv&lt;/code&gt;: loads environment variables from a &lt;code&gt;.env&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bcryptjs&lt;/code&gt;: to hash the password.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nodemon&lt;/code&gt;: nodemon helps Node.js-based application restarts automatically when there is a change in the code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Environment variables
&lt;/h3&gt;

&lt;p&gt;Next, create a &lt;code&gt;.env&lt;/code&gt; file to securely store our sensitive information, such as API credentials.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Your_Secret_Key_Here"&lt;/span&gt;
&lt;span class="py"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create the Express server
&lt;/h3&gt;

&lt;p&gt;Now, we'll create an &lt;code&gt;index.js&lt;/code&gt; file in the base directory and set up a simple Express server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&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;dotenv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&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;port&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;PORT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//middleware provided by Express to parse incoming JSON requests.&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; 

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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;res&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&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;PORT&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="s2"&gt;`Server is running on port &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;PORT&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the top of the project, we're loading environment variables using &lt;code&gt;dotenv.config()&lt;/code&gt; to make them accessible throughout the file. This way, we can use the &lt;code&gt;dotenv&lt;/code&gt; package to access the &lt;code&gt;PORT&lt;/code&gt; number from the &lt;code&gt;.env&lt;/code&gt; file, instead of hardcoding it directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run the project
&lt;/h3&gt;

&lt;p&gt;In this step, we'll add a start script to the package.json file to easily run our project.&lt;/p&gt;

&lt;p&gt;By default we'd have to restart our server each time we make changes to a file. To avoid this, we can use &lt;code&gt;nodemon&lt;/code&gt;, which will scan for changes and restart automatically.&lt;/p&gt;

&lt;p&gt;Add the following item to &lt;code&gt;package.json&lt;/code&gt;:&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="nl"&gt;"scripts"&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;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nodemon index.js"&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;And now, we test!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run start
&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%2Ff3r2g8u6ilmxsu7v1im1.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%2Ff3r2g8u6ilmxsu7v1im1.png" alt="Screenshot of npm run start, running successfully" width="800" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, open &lt;code&gt;http://localhost:3000/&lt;/code&gt; in a browser, and if everything went to plan, you'll see the default "Hello World" page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing authentication with JWT
&lt;/h2&gt;

&lt;p&gt;Our basic project setup is done! Next, we’ll implement authentication using JWT tokens.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create routes for authentication
&lt;/h3&gt;

&lt;p&gt;The authentication route will allow users to sign up and log in. Commonly, routes go in &lt;code&gt;routes/&lt;/code&gt;, and since this is an authentication mechanism, we'll name it &lt;code&gt;authentication.js&lt;/code&gt;. I've split this into multiple sections to make it easier to read, but it's the same file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&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;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&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;jwt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;);&lt;/span&gt; 
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bcryptjs&lt;/span&gt;&lt;span class="dl"&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// in-memory database to keep things basic for this tutorial&lt;/span&gt;

&lt;span class="c1"&gt;// Register route&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/signup, (req, res) = &amp;gt;{

  const { username, password, role } = req.body;

  if (!Array.isArray(role)) {
    return res.status(400).json({ message: "Role must be an array" });
  }

  const userExists = users.find(user = &amp;gt;user.username === username);
  if (userExists) {
    return res.status(400).json({
      message: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="nx"&gt;already&lt;/span&gt; &lt;span class="nx"&gt;exists&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;
    });
  }

  const hashedPassword = bcrypt.hashSync(password, 8);

  users.push({
    username,
    password: hashedPassword,
    role
  });

  res.status(201).json({
    message: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="nx"&gt;registered&lt;/span&gt; &lt;span class="nx"&gt;successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;
  });
});
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Login route &lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&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="nx"&gt;password&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;username&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;user&lt;/span&gt;&lt;span class="p"&gt;)&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;message&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 not found&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isPasswordValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compareSync&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="nx"&gt;user&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="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;isPasswordValid&lt;/span&gt;&lt;span class="p"&gt;)&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid credentials&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&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;sign&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;user&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;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&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;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;expiresIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1h&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The signup route allows users to register by providing a username and password. Upon receiving the data, it creates a new user instance and saves it to the in-memory database.&lt;/p&gt;

&lt;p&gt;And, the login route verifies the user's credentials against the in-memory database. If the username and password match, it generates a JWT token and returns it to the client.&lt;/p&gt;

&lt;h3&gt;
  
  
  Middleware for JWT verification
&lt;/h3&gt;

&lt;p&gt;Now, we’ll add one middleware function called &lt;code&gt;verifyJWT&lt;/code&gt; that verifies the JWT token sent by the client, and which authenticates the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;authenticateToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allowedRoles&lt;/span&gt;&lt;span class="p"&gt;)&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;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;authorization&lt;/span&gt;&lt;span class="dl"&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;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;authHeader&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;authHeader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&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;token&lt;/span&gt;&lt;span class="p"&gt;)&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;No&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="nx"&gt;provided&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;
      });
    }

    jwt.verify(token, process.env.JWT_SECRET, (err, user) = &amp;gt;{
      if (err) {
        return res.status(403).json({
          message: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;Invalid&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;
        });
      }

      if (!allowedRoles.includes(user.role)) {
        return res.status(403).json({
          message: ‘You do not have the correct role&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;next&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="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;authenticateToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Protected route
&lt;/h3&gt;

&lt;p&gt;Finally, we'll integrate these authentication routes with our express application in the &lt;code&gt;index.js&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/protected&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;authenticateToken&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Welcome Admin &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&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="s2"&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;Here we have created a &lt;code&gt;/protected&lt;/code&gt; route that uses &lt;code&gt;authenticateToken&lt;/code&gt; to check if the user is authenticated.&lt;/p&gt;

&lt;p&gt;If the user is authenticated, the server sends back a response saying "This is a Protected Route. Welcome [username]".&lt;/p&gt;

&lt;p&gt;Here, &lt;code&gt;[username]&lt;/code&gt; is replaced with the username of the authenticated user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the endpoints
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Sign-up
&lt;/h4&gt;

&lt;p&gt;To validate the sign-up endpoint, we'll make a POST request to this route:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http://localhost:3000/auth/signup&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this header:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Content-Type : application/json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the following JSON body:&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;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Arindam Majumder"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"071227"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"roles"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="s2"&gt;"admin"&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;&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%2Fzclu41leah8wi4b6hbci.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%2Fzclu41leah8wi4b6hbci.png" alt="Screenshot of a postman interaction" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We got the token back as a response. We will copy the token as we'll need it in the next section.&lt;/p&gt;

&lt;h4&gt;
  
  
  Protected route
&lt;/h4&gt;

&lt;p&gt;Now that we have obtained a JWT token from the login endpoint, we will test the protected route by including this token in the request headers.&lt;/p&gt;

&lt;p&gt;For that, we'll make a GET request to the protected route URL &lt;code&gt;http://localhost:3000/protected&lt;/code&gt;. In the request headers, we'll include the JWT token obtained from the login endpoint:&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%2Ftwgyx6244kp4a64eq21x.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%2Ftwgyx6244kp4a64eq21x.png" alt="Screenshot of a postman interaction" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this, we have successfully implemented JWT authentication in Node.js!&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing authorization with Cerbos
&lt;/h2&gt;

&lt;p&gt;Now that we have added authentication to our project, we can now proceed authorization using the Cerbos PDP.&lt;/p&gt;

&lt;h3&gt;
  
  
  Launch the Cerbos container
&lt;/h3&gt;

&lt;p&gt;We will begin by launching the Cerbos container via Docker.&lt;/p&gt;

&lt;p&gt;In the base directory, use the following command to run the Docker container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; cerbos &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/cerbos/policies:/policies &lt;span class="nt"&gt;-p&lt;/span&gt; 3592:3592 &lt;span class="nt"&gt;-p&lt;/span&gt; 3593:3593 ghcr.io/cerbos/cerbos:0.34.0 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a quick &lt;code&gt;docker ps&lt;/code&gt; to verify that the container persists.&lt;/p&gt;

&lt;p&gt;For more information about the Cerbos container, see the &lt;a href="https://docs.cerbos.dev/cerbos/latest/installation/container.html" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialize the Cerbos client
&lt;/h3&gt;

&lt;p&gt;Next, we set up the Cerbos client using the &lt;code&gt;@cerbos/grpc&lt;/code&gt; library, which we first need to install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @cerbos/grpc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we initialize the client with a few lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@cerbos/grpc&lt;/span&gt;&lt;span class="dl"&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;cerbos&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;GRPC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;localhost:3593&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="na"&gt;tls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Define a CRUD policy
&lt;/h3&gt;

&lt;p&gt;After initializing the Cerbos client, we’ll define a simple CRUD policy in place for our application. Add this basic policy into the policies folder at &lt;code&gt;cerbos/policies/contact.yaml&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="nn"&gt;---&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;api.cerbos.dev/v1&lt;/span&gt;
&lt;span class="na"&gt;resourcePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
  &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;contact&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;read"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;admin&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;user&lt;/span&gt;
    &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EFFECT_ALLOW&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;create"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;admin&lt;/span&gt;
    &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EFFECT_ALLOW&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Access control middleware
&lt;/h3&gt;

&lt;p&gt;Next, we'll create some middleware to check access for requests. In &lt;code&gt;middleware/access.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@cerbos/grpc&lt;/span&gt;&lt;span class="dl"&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;cerbos&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;GRPC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;localhost:3593&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="na"&gt;tls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;jwtToPrincipal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;roles&lt;/span&gt; &lt;span class="o"&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;rest&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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rest&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;readAccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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;decision&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;cerbos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkResource&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;jwtToPrincipal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contact&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;actions&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="s2"&gt;read&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isAllowed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read&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="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unauthorized&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;writeAccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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;decision&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;cerbos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkResource&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;jwtToPrincipal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contact&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;actions&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="s2"&gt;create&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isAllowed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;create&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="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unauthorized&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;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;readAccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;writeAccess&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the &lt;code&gt;jwtToPrincipal&lt;/code&gt; function is a utility function that converts a JSON Web Token (JWT) payload into a Cerbos principal object. It extracts the &lt;code&gt;sub&lt;/code&gt; (subject), &lt;code&gt;iat&lt;/code&gt; (issued at), and &lt;code&gt;roles&lt;/code&gt; properties from the JWT payload and assigns them to the corresponding properties of the principal object&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;readAccess&lt;/code&gt; function is an asynchronous middleware function that checks if the current user has permission to read a contact resource. It uses the &lt;code&gt;cerbos.checkResource&lt;/code&gt; method to make an authorization decision. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;writeAccess&lt;/code&gt; function is similar to the &lt;code&gt;readAccess&lt;/code&gt; function, but it checks for permission to write to the contact resource instead of reading. It uses the "write" action in the &lt;code&gt;cerbos.checkResource&lt;/code&gt; method.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implement authorized routes
&lt;/h3&gt;

&lt;p&gt;Finally, let's implement routes to check user access using Cerbos.&lt;/p&gt;

&lt;p&gt;Import the required middleware functions for read and write access checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;readAccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;writeAccess&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./middleware/access&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update &lt;code&gt;index.js&lt;/code&gt; file to include the following routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/read&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;readAccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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;res&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Read Access Granted&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/write&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;writeAccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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;res&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Write Access Granted&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s it! By following these steps, we have successfully implemented authorization and RBAC in our Node.js application using Cerbos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test the authorized route
&lt;/h2&gt;

&lt;p&gt;Now, we’ll test to see if the user has permission to do specific tasks. &lt;/p&gt;

&lt;p&gt;To check if the user has write access, we'll make a POST request to &lt;code&gt;http://localhost:3000/write&lt;/code&gt; with the following headers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Content-Type: application/json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Authorization: JWT_TOKEN&lt;/code&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%2Fsvt5629hfx909l9g014j.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%2Fsvt5629hfx909l9g014j.png" alt="Screenshot of a postman interaction" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The user with the admin role has access to this route.&lt;/p&gt;

&lt;p&gt;Next, to check if the user has read access, we'll make a GET request to &lt;code&gt;http://localhost:3000/read&lt;/code&gt; with the following headers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Content-Type: application/json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Authorization: JWT_TOKEN&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If successful, that will return as &lt;code&gt;Read Access Granted&lt;/code&gt; as well.&lt;/p&gt;

&lt;p&gt;Finally, let's check a user with the &lt;em&gt;user&lt;/em&gt; role to see if it has write access or not. Make a POST request to &lt;a href="http://localhost:3000/write" rel="noopener noreferrer"&gt;http://localhost:3000/write&lt;/a&gt; with the following headers &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Content-Type: application/json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;`Authorization: JWT_TOKEN&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As expected, we got an &lt;em&gt;unauthorized&lt;/em&gt; response. That means the user doesn’t have access to that route. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we covered the basics of authentication and authorization, and how to integrate JWT authentication and Cerbos authorization into a Node.js application.&lt;/p&gt;

&lt;center&gt;

  &lt;a href="https://cta-service-cms2.hubspot.com/web-interactives/public/v1/track/redirect?encryptedPayload=AVxigLJcZiZ24z6ZSah4IpOn8dABnds9mrKKh6e4PJqvKxet7ffhWKXW0MdjhgVQy4mpPiz%2BmP6afTEqsC16yImlV%2FKtxCF9SLhJub2UaJVdW9FJFbjqw2pDljc4t3o7wysyDZUCo3QHGt4JiG3yBqSqDFxK%2FhbxRSgua197Oqt7wTaa07SsSxBmDYqFpmLr&amp;amp;webInteractiveContentId=168996984756&amp;amp;portalId=20289770" rel="noopener noreferrer"&gt;
    &lt;img alt="BlogCTA - Hub" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fno-cache.hubspot.com%2Fcta%2Fdefault%2F20289770%2Finteractive-168996984756.png" width="538" height="277"&gt;
  &lt;/a&gt;

&lt;/center&gt;

</description>
      <category>authorization</category>
      <category>node</category>
      <category>tutorial</category>
      <category>express</category>
    </item>
    <item>
      <title>We Are Developers World Congress; an Engineer's Travelogue</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Wed, 07 Aug 2024 14:33:53 +0000</pubDate>
      <link>https://forem.com/cerbos/we-are-developers-world-congress-an-engineers-travelogue-3di7</link>
      <guid>https://forem.com/cerbos/we-are-developers-world-congress-an-engineers-travelogue-3di7</guid>
      <description>&lt;p&gt;&lt;em&gt;Written by Cerbos engineer Sam Lock (connect on &lt;a href="https://www.linkedin.com/in/samuellock" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://github.com/Sambigeara" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Thursday
&lt;/h2&gt;

&lt;h3&gt;
  
  
  06:50
&lt;/h3&gt;

&lt;p&gt;My alarm shouts in my ear that it’s time to wake up. I sit up and am momentarily confused, but then remember that I’m in Berlin, in a hotel room, and I’m staffing our company booth at a conference today. My body is aching; I wonder why, but then I remember the 50km I scooter’d across the city the day before. The scooters are electric but the Berlin streets are cobbled and unforgiving. The botanical gardens are nice, though.&lt;/p&gt;

&lt;p&gt;I fall out of bed, stand up, glance at the coffee machine. It looks confusing to my sleep-addled brain. I glance at the time, it’s 6:52; “oh, I have loads of time”. I sit down again to catch my breath. A few seconds later, I glance at the time again: 7:10, “but how?”. I pick myself up and hurl myself into the bathroom.&lt;/p&gt;

&lt;p&gt;The shower is angry and powerful; I desperately swing for the shower curtain as the torrent pushes me backwards with the force of a thousand rivers. Any residual sleepiness is washed away by adrenaline and the desire to live.&lt;/p&gt;

&lt;p&gt;I’m clean and awake now. My bag is packed, I have my ticket ready to go. I glance at the coffee machine again; it looks less intimidating. I fill the reservoir, stab in a capsule, and press the button. It rumbles to life and spits coffee downwards in the general direction of the mug. The table is given a healthy dose, too. I stop briefly to admire the Jackson Pollock-esque artwork adorning the wooden top.&lt;/p&gt;

&lt;h3&gt;
  
  
  07:28
&lt;/h3&gt;

&lt;p&gt;I feel more alert now. The coffee that made it into the mug has further lifted me from my haze and I head downstairs to meet my colleagues. I realise at this point that I forgot to have breakfast. I reason that I could probably do with skipping a meal and push it to the back of my mind. Not today, hunger.&lt;/p&gt;

&lt;p&gt;Our team of four piles into a taxi. I’m kindly offered the front seat. The driver scrambles to clear the newspaper and pastry wrappers before I fold myself in. I’ve been on holiday for a little while, so open up Slack to peruse through the backlog of missed messages from the week prior as we head through the busy roads of rush-hour Berlin.&lt;/p&gt;

&lt;h3&gt;
  
  
  07:51
&lt;/h3&gt;

&lt;p&gt;We arrive at Messe Berlin. Although I’ve been here the year prior, I’m once again impressed by the sheer size of the place. It’s early, but already there are eager crowds forming. We climb out the car and retrieve the various sacks of merch from the boot. We walk down the grand steps towards the entrance to pick up our passes and wristbands. I’m overcome by a feeling of power and belonging.&lt;/p&gt;

&lt;p&gt;I follow my colleagues through the various exhibitor spaces towards our own. My fight-or-flight response kicks in as we pass a booth with a carnival hammer game. The attendee scores well; a couple of our team pledge to better the score later on. We discuss optimal swinging techniques but before we can come to a conclusion, we reach our own booth. Game time.&lt;/p&gt;

&lt;h3&gt;
  
  
  08:04
&lt;/h3&gt;

&lt;p&gt;We pounce into action. One team member volunteers for a hunter-gatherer mission to find coffee. The remaining members start distributing merch around our allotted square of exhibitor space. There are four of us and two chairs. Thankfully, an unused booth behind us presents us with an additional chair. Only one weary stander. Thank you, conference.&lt;/p&gt;

&lt;p&gt;We disappear off to have a swing of the hammer. Our CEO tops the leaderboard early on. Myself and another colleague are less pleased with our results. Probably rigged, I think to myself. Back to the booth.&lt;/p&gt;

&lt;p&gt;With the distant thuds of the hammer ringing out, we settle in and get ready for the day as the first attendees start to appear.&lt;/p&gt;

&lt;p&gt;“Hello! How are you? What’s Cerbos?”&lt;/p&gt;

&lt;p&gt;“Well, tell me what you do, and I’ll see how it could apply…”&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%2F8krxz3roajyr0osyagxu.jpg" 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%2F8krxz3roajyr0osyagxu.jpg" alt="Cerbos Booth with people milling about" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  10:17
&lt;/h3&gt;

&lt;p&gt;The conversations are rich and varied. Some have felt the pain of authorization and eagerly listen as we share the wonders of Cerbos. Others don’t understand authorization, but have seen our Cerbie plushies from afar. “How can I get one of those”, they ask. “You must care about Cerbos, first.” The denials are awkward, but necessary. Cerbies are finite and surprisingly expensive to produce. Some people come up and shout their desire for a Cerbie to my face. I weather the storm and stand my ground. “No”, I say, bravely.&lt;/p&gt;

&lt;p&gt;Talking about authorization is thirsty work. I scour the halls for a water fountain, but alas, no water to be found. I ask a volunteer who offers me no clues but wishes me luck on my search. “Surely, it’s somewhere”. I eventually give up, find a coffee stand, and reluctantly pass over the €4.10 for a small bottle. I get a couple extra for my equally dehydrated colleagues. As I walk back to the stand, I debate with myself whether or not I should tell my boss how much I just spent on water.&lt;/p&gt;

&lt;h3&gt;
  
  
  13:08
&lt;/h3&gt;

&lt;p&gt;Lunch beckons. I step outside and wait for my eyes to adjust to the light. It’s warm in Berlin; almost too warm. I spy my prize, the fabled “hotdog wrap” van from the year prior. Glorious, gravy and mashed potato filled things. I make haste, buy my food, and refuel. Back to the booth.&lt;/p&gt;

&lt;h3&gt;
  
  
  15:22
&lt;/h3&gt;

&lt;p&gt;I’ve been tasked with a mission for doughnut retrieval. I’m briefed by a colleague; the doughnut deliverer has set off to the famous “Brammibal’s” (the best doughnut makers in Berlin?). I make a mental note, then return to authorization conversations and Cerbie denials.&lt;/p&gt;

&lt;h3&gt;
  
  
  16:02
&lt;/h3&gt;

&lt;p&gt;The doughnuts are en route.&lt;/p&gt;

&lt;p&gt;My hips start to get sore because I’m a delicate desk-sitter by profession. I do some ad-hoc yoga to limber up.&lt;/p&gt;

&lt;h3&gt;
  
  
  17:09
&lt;/h3&gt;

&lt;p&gt;Call from the driver. Even closer. I suggest a location and set off across Messe, passing the hammer booth. The exhibitors' faces suggest that they regret their noisy choice of attraction. I continue for about 10 minutes in one direction, find a spot, share my location on Whatsapp, then set up camp.&lt;/p&gt;

&lt;h3&gt;
  
  
  17:27
&lt;/h3&gt;

&lt;p&gt;Call from the driver. They’re nearby. “Did you see my location?”, I ask. “Yes, I’ll see you there soon”, they reply. Excellent.&lt;/p&gt;

&lt;h3&gt;
  
  
  17:31
&lt;/h3&gt;

&lt;p&gt;Call from the driver: “I can’t see you”, they say. “Share your location?”, I suggest. 500 yards away. “Damn you”, I think to myself, before setting off in the opposite direction to meet with the confused driver.&lt;/p&gt;

&lt;p&gt;I eventually find them, state my name, and claim my prize. “Can I go to the toilet?”, they ask. I’m puzzled. I’m not the toilet gatekeeper. “Probably”, I reply.&lt;/p&gt;

&lt;h3&gt;
  
  
  18:00
&lt;/h3&gt;

&lt;p&gt;We officially transition to the “booth crawl” section of the day. A colleague procures some beers. They’re slightly warm but taste like liquid wheaty gold. The doughnuts are revealed. I eat one. They’re light and fluffy and delicious. More conversations are had. More people ask for Cerbies. We give out a few. I eat another doughnut. Then another.&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%2Fs73jwi9ickhqfkoart12.jpg" 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%2Fs73jwi9ickhqfkoart12.jpg" alt="Many colourful doughnuts in a pink box" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  19:30'ish
&lt;/h3&gt;

&lt;p&gt;I feel some regret for the quantity of doughnuts I’ve consumed. I feel a bit poorly as we pack up the booth and head out to find a taxi to get back to the hotel, then each disappear off for a short, much needed rest in our rooms before dinner.&lt;/p&gt;

&lt;h3&gt;
  
  
  21:00'ish
&lt;/h3&gt;

&lt;p&gt;I’m tasked with finding a restaurant so I scour Google maps and find the perfect one nearby. Traditional German food, classic wood furnishings; lovely. I brief my boss that they may be cash-only and he heads off to find some cash. We set off and eventually find the restaurant, but they’ve stopped serving food. I feel ashamed, but thankfully we find a burger joint nearby. They accept card payments.&lt;/p&gt;

&lt;p&gt;The burgers were very good; we finish them off then return to the hotel. No hotel beers for this tired lot – straight off to bed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Friday
&lt;/h2&gt;

&lt;h3&gt;
  
  
  06:50
&lt;/h3&gt;

&lt;p&gt;My alarm shouts at me again. I’m bleary-eyed, but today I’m better prepared for the hell-shower and the over-excited coffee machine. I go about my morning routine and prepare for the day.&lt;/p&gt;

&lt;h3&gt;
  
  
  07:28am
&lt;/h3&gt;

&lt;p&gt;I head downstairs for breakfast. Straight to the cereal bar. I add a spoonful from every jar to my bowl to form a single “super-cereal”. No hungry start for me today. I join my colleague and polish it off before getting some fruit to counteract my thus far beige breakfast.&lt;/p&gt;

&lt;h3&gt;
  
  
  08:00
&lt;/h3&gt;

&lt;p&gt;Into a taxi and off to the conference. We know the drill – a colleague finds us some coffees and we settle down ready for day 2.&lt;/p&gt;

&lt;p&gt;Rumours start to circulate of a little software bug that might be impacting some computers somewhere in the world. Meh – don’t think we need to worry about that.&lt;/p&gt;

&lt;h3&gt;
  
  
  08:07
&lt;/h3&gt;

&lt;p&gt;We definitely do need to worry about that. We all struggle to check in via our airline apps for our various flights home later in the day, and passively watch on different news outlets as a simple (highly privileged) update brings the world to its knees. Oh well, we’ll talk about authorization until then.&lt;/p&gt;

&lt;h3&gt;
  
  
  10:42
&lt;/h3&gt;

&lt;p&gt;It’s been a hectic couple of days and our t-shirt supplies are nearly depleted. Only a handful of size “S” remain.&lt;/p&gt;

&lt;p&gt;I have an in-depth conversation with someone about their authorization needs. We’re both satisfied with the eventual outcome – they will go away and try to implement Cerbos and we will be happy to answer any questions that they might have. Great!&lt;/p&gt;

&lt;p&gt;They ask for a t-shirt. “Sure!”, I say. “Are you [a] small?” I ask. “Yes, I am quite small”, they reply. I curse myself for an unfortunate choice of wording.&lt;/p&gt;

&lt;h3&gt;
  
  
  12:00
&lt;/h3&gt;

&lt;p&gt;It’s raffle time. A crowd gathers around our booth for the chance to win our grand prize: a Super Nintendo System Lego set! My boss throws some Cerbies into the crowd to warm them up, much like a bouquet-toss at a wedding, and people scrap for them with a surprising level of urgency. People really do love our plushies. Thankfully no-one was hurt.&lt;/p&gt;

&lt;p&gt;All the entries were placed into a virtual hat, and a name pulled. A delighted looking recipient came forward on the first draw and we handed it over.&lt;/p&gt;

&lt;h3&gt;
  
  
  14:23
&lt;/h3&gt;

&lt;p&gt;More yoga. I’m no good at standing up it seems.&lt;/p&gt;

&lt;p&gt;The exhibition halls have started to quieten down. People are running out of steam. Not us, though – we’ve depleted our merch-reserves, but the conversations are still flowing.&lt;/p&gt;

&lt;h3&gt;
  
  
  15:48
&lt;/h3&gt;

&lt;p&gt;Time to go. I share a similar timed flight with our CEO, so we pack up together and head off. As we leave, he points out the water fountain just a stone’s throw from our booth. Whoops. We get in our Uber and anxiously make our way to Berlin Brandenburg to see what havoc CrowdStrike has unleashed upon the airport.&lt;/p&gt;

&lt;h3&gt;
  
  
  PM
&lt;/h3&gt;

&lt;p&gt;None, it seems. Security and passport control is seamless. I and other travellers play a small game of plane Hokey Cokey as they struggle to find us one with working air conditioning. But we eventually lift off, and bid farewell to Berlin and to We Are Developers for another year.&lt;/p&gt;

&lt;p&gt;See you all again next time ✌️&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%2Fo1hf9ficeyyixlg7orl2.jpg" 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%2Fo1hf9ficeyyixlg7orl2.jpg" alt="Sam sitting at the Cerbos booth" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;—&lt;/p&gt;

&lt;p&gt;Cerbos is an open-source, scalable authorization layer for software applications. It simplifies access control by separating authorization logic from business logic, allowing developers to define and enforce complex policies with ease. Cerbos integrates seamlessly with existing applications and supports various environments, ensuring secure and efficient permission management.&lt;/p&gt;

&lt;p&gt;If you have any questions or feedback, or to chat to us and other like-minded technologists, please &lt;a href="https://community.cerbos.dev/" rel="noopener noreferrer"&gt;join our Slack community!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>conference</category>
      <category>humour</category>
      <category>authorization</category>
    </item>
    <item>
      <title>Introduction to RBAC in Kubernetes</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Tue, 30 Jul 2024 13:51:52 +0000</pubDate>
      <link>https://forem.com/cerbos/introduction-to-rbac-in-kubernetes-5hh5</link>
      <guid>https://forem.com/cerbos/introduction-to-rbac-in-kubernetes-5hh5</guid>
      <description>&lt;p&gt;&lt;em&gt;Guest article written by &lt;a href="https://www.linkedin.com/in/tania-duggal-07a297220/" rel="noopener noreferrer"&gt;Tania Duggal&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In this article, you will learn what RBAC is, the key challenges and approaches to managing RBAC in Kubernetes, and how Cerbos can help you in your application security.&lt;/p&gt;

&lt;p&gt;In Kubernetes, when a request comes to the API Server to create resources, it processes the request in different steps. It first checks from where a request is made and whether a user is valid or not. This process is called authentication. There are two categories of users: normal users and service accounts. Service accounts are managed internally by Kubernetes, and are used by applications that access the cluster, such as the Monitoring Application. Normal users are external entities that may include administrators, developers, and other humans. &lt;/p&gt;

&lt;p&gt;After authentication, the next process is &lt;a href="https://www.cerbos.dev/blog/authorization-as-a-service" rel="noopener noreferrer"&gt;authorization&lt;/a&gt; for the requested action and permissions. While Kubernetes supports multiple authorization methods, the one we’ll concentrate on in this article is called &lt;a href="https://www.cerbos.dev/features-benefits-and-use-cases/rbac" rel="noopener noreferrer"&gt;RBAC&lt;/a&gt;.&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%2F14ls4ln8chm4osfzj05r.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%2F14ls4ln8chm4osfzj05r.png" alt="A graphical workflow of how a kubectl command is authenticated, authorized, and passed along to action" width="800" height="653"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is RBAC?
&lt;/h2&gt;

&lt;p&gt;RBAC stands for Role Based Access Control. It is a method through which we can control access to resources and actions based on the roles assigned to the users. In Kubernetes, RBAC is how the administrator can control and allow which actions the users can perform on which resources, respectively. RBAC is managed just like everything else in Kubernetes: as objects that can be described via YAML or kubectl. To enable RBAC, the &lt;code&gt;--authorization-mode&lt;/code&gt; flag must be set to RBAC when starting the API server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kube-apiserver &lt;span class="nt"&gt;--authorization-mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;RBAC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Core Objects of Kubernetes RBAC
&lt;/h2&gt;

&lt;p&gt;The RBAC API declares four core objects. These are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Role:&lt;/strong&gt; It is a way of defining what actions users can perform within a namespace. This defines which actions such as get, list, create, delete, etc., can be performed on specific resources like pods, services, and deployments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cluster Role:&lt;/strong&gt; This is similar to the role, but it is used for cluster-wide permissions. It means it is not limited to a specific namespace and can be used in all namespaces of the cluster.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;RoleBinding:&lt;/strong&gt; RoleBinding binds the role with one or more users, groups, and service accounts in a particular namespace. In this way, whatever permissions we have defined in a role get allotted to the users, groups, or service accounts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ClusterRoleBinding:&lt;/strong&gt; ClusterRoleBinding binds the ClusterRole to one or more users, groups, and service accounts throughout the cluster. This allows the permissions defined in ClusterRole to be assigned to users in all namespaces of the cluster.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How RBAC is implemented in Kubernetes
&lt;/h2&gt;

&lt;p&gt;It depends on your requirements and what you want to create for your resources, whether it be a Role or a ClusterRole. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a Role and assign it with RoleBinding&lt;/strong&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="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io/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;Role&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;developer&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiGroups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# "" indicates the core API group&lt;/span&gt;
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pods"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;verbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;list"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;update"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;delete"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;create"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have permitted pods to get, list, update, delete, and create the resources.&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="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io/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;RoleBinding&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;devuser-developer-binding&lt;/span&gt;
&lt;span class="na"&gt;subjects&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&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;User&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;dev-user&lt;/span&gt; &lt;span class="c1"&gt;# "name" is case sensitive&lt;/span&gt;
  &lt;span class="na"&gt;apiGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io&lt;/span&gt;
&lt;span class="na"&gt;roleRef&lt;/span&gt;&lt;span class="pi"&gt;:&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;Role&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;developer&lt;/span&gt;
  &lt;span class="na"&gt;apiGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;RoleBinding binds the &lt;strong&gt;developer&lt;/strong&gt; Role to a user named &lt;strong&gt;dev-user&lt;/strong&gt; in the default namespace.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a ClusterRole and assign it with ClusterRoleBinding&lt;/strong&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="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io/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;ClusterRole&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;cluster-administrator&lt;/span&gt;
&lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiGroups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# "" indicates the core API group&lt;/span&gt;
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nodes"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;verbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;list"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;delete"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;create"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have permitted nodes to get, list, delete, and create the resources.&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="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io/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;ClusterRoleBinding&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;cluster-admin-role-binding&lt;/span&gt;
&lt;span class="na"&gt;subjects&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&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;User&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;cluster-admin&lt;/span&gt;
  &lt;span class="na"&gt;apiGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io&lt;/span&gt;
&lt;span class="na"&gt;roleRef&lt;/span&gt;&lt;span class="pi"&gt;:&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;ClusterRole&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;cluster-administrator&lt;/span&gt;
  &lt;span class="na"&gt;apiGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ClusterRoleBinding binds the &lt;strong&gt;cluster-administrator&lt;/strong&gt; ClusterRole to a user named &lt;strong&gt;cluster-admin&lt;/strong&gt; in all namespaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges in Kubernetes RBAC
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Difficulty in Management:&lt;/strong&gt; It's difficult to manage RBAC in Kubernetes when you have so many roles and permissions. Each user and service requires particular permission, which can be time-consuming and complex. As the number of users, applications, and namespaces grows, it becomes difficult to handle the RBAC configuration.&lt;br&gt;&lt;br&gt;
For example, if you have a team of developers in different namespaces, you must ensure that each developer can only access the resources that they need. Mistakenly, if any developer gets too many permissions, they can unintentionally modify other's resources.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability Issues:&lt;/strong&gt; As the organization grows, so does the number of users and roles. This growth is asymmetrical, and the challenge of scaling RBAC manually can quickly become overwhelming. It becomes a huge task to manage and define permissions for each employee. A minor error can lead to a security breach or any operational issue.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Manual Process:&lt;/strong&gt; When you configure and define RBAC roles and permissions manually, it can be quite dangerous. Even a small mistake can lead to a security breach.&lt;br&gt;&lt;br&gt;
For example, if an administrator has to permit the developer only to read but mistakenly gives permission to him to write as well, then the developer can modify data, which can lead to vulnerabilities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Logs Auditing and Compliance&lt;/strong&gt;: It is necessary to maintain accurate and detailed records for auditing and compliance. To follow standards such as GDPR and HIPAA, you have to maintain detailed logs that show which users performed what actions and when. Kubernetes provides limited tools for RBAC auditing, which makes compliance challenging.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Approaches to Addressing Kubernetes RBAC Challenges
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Implementing Principle of Least Privilege:&lt;/strong&gt; Least Privilege means you have to give minimum permissions to the users they need to do their work. Too many permissions can result in security issues. You should follow the least privilege approach to enhance security.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Policy Management Tools:&lt;/strong&gt; Managing too many policies can be difficult. You can use policy management tools to reduce the burden of managing policies. These tools can create, update, and manage policies for you and ensure RBAC policies are up-to-date and secure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Namespaced Roles:&lt;/strong&gt; You should use namespace roles to limit the scope of your resources. With a namespaced role, you can ensure that a user or service only gets access to the resources in that namespace that are necessary for their function. This isolation helps us prevent accidental access.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Auditing RBAC regularly:&lt;/strong&gt; You should audit your RBAC configuration regularly. With regular lookups on these configurations, you can timely identify issues and fix them.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's clear that managing Kubernetes access and permissions is quite complex, but it provides a robust security feature at the infrastructure level, and is well worth considering for your future deployments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bring powerful RBAC to your applications
&lt;/h3&gt;

&lt;p&gt;Finally, if you're looking to bring that same infrastructure-level power to the application layer, you should check out Cerbos. The &lt;a href="https://www.cerbos.dev/product-cerbos-pdp?utm_campaign=topic_authorization&amp;amp;utm_source=dev.to&amp;amp;utm_medium=text&amp;amp;utm_content=&amp;amp;utm_term="&gt;Cerbos Policy Decision Point (PDP)&lt;/a&gt; is the scalable, open source authorization layer for implementing roles and permissions at the application layer. It can be deployed easily as a sidecar alongside your Kubernetes-managed applications. Try it today!&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>rbac</category>
      <category>authorization</category>
      <category>authz</category>
    </item>
    <item>
      <title>Cerbos Hub: A complete authz management system</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Thu, 25 Jul 2024 09:45:02 +0000</pubDate>
      <link>https://forem.com/cerbos/cerbos-hub-a-complete-authz-management-system-4a3e</link>
      <guid>https://forem.com/cerbos/cerbos-hub-a-complete-authz-management-system-4a3e</guid>
      <description>&lt;p&gt;Good news everyone: &lt;a href="https://www.cerbos.dev/news/cerbos-hub-is-now-generally-available?utm_campaign=cerbos_hub_ga&amp;amp;utm_source=dev.to&amp;amp;utm_medium=text&amp;amp;utm_content=&amp;amp;utm_term="&gt;Cerbos Hub&lt;/a&gt; is now generally available! In this post, we’re going to explain what Cerbos Hub is, why it's useful, and how it solves some of the hardest challenges with externalizing authorization. &lt;/p&gt;

&lt;h1&gt;
  
  
  Cerbos: Fine-grained authorization and access control
&lt;/h1&gt;

&lt;p&gt;New to all of this? No problem. Cerbos is a scalable and extensible authorization service for developer, product and security teams. It enables teams to implement fine-grained authorization and access control in their applications, services, and infrastructure in an auditable, programmatic, and scalable way. Maybe you’ve heard of RBAC, ABAC, ReBAC, PBAC and so forth? That’s what Cerbos is all about.&lt;/p&gt;

&lt;p&gt;The Cerbos &lt;a href="https://www.cerbos.dev/product-cerbos-pdp?utm_campaign=cerbos_hub_ga&amp;amp;utm_source=dev.to&amp;amp;utm_medium=text&amp;amp;utm_content=&amp;amp;utm_term="&gt;open source Policy Decision Point&lt;/a&gt; (PDP) is a popular solution for technical teams who’ve made the decision to separate the authorization process from their core application code, freeing them up to concentrate on their core business. It can be deployed as a binary on metal, in a sidecar, as a service in a VM—anywhere on your infrastructure, any way you want.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cerbos Hub: manage centrally, deploy anywhere
&lt;/h1&gt;

&lt;p&gt;One of the great things about the PDP is how powerful and extensible it is. &lt;a href="https://www.cerbos.dev/product-cerbos-hub?utm_campaign=cerbos_hub_ga&amp;amp;utm_source=dev.to&amp;amp;utm_medium=text&amp;amp;utm_content=&amp;amp;utm_term="&gt;Cerbos Hub&lt;/a&gt; is designed from the ground up to help you harness that power and control that extensibility. The industry term is Policy Administration Point (PAP), but it can be thought of as a control plane. Cerbos Hub is all about unlocking the full potential of the PDPs by providing an intuitive user interface, collaborative policy management, and a powerful testing and deployment pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simplified policy management
&lt;/h2&gt;

&lt;p&gt;Cerbos Hub centralizes policy management no matter where or how your PDPs are deployed. With a managed CI/CD pipeline, you can deploy and test policies seamlessly across development, testing, and production environments. No more juggling tools and processes—Cerbos Hub coordinates the rollout of authorization policies across your apps, APIs, and infrastructure.&lt;/p&gt;

&lt;p&gt;Whether your infrastructure is on-premise, cloud-based, or serverless, Cerbos adapts to your needs. It supports edge devices, security hardware, and even in-browser runtimes for frameworks like React and Angular through its Embedded Policy Decision Point capability. This means you can authorize anywhere, keeping your policies in sync regardless of the environment. And with Cerbos Hub, managing that synchronization is easier than ever!&lt;/p&gt;

&lt;h2&gt;
  
  
  Embedded PDP
&lt;/h2&gt;

&lt;p&gt;As one of our engineers so eloquently put it: “This requires some explanation.” Traditionally, when you’re thinking about service delivery, you’re thinking about a binary running in a container or sitting on a virtual machine somewhere. That’s fine, but it’s not the only model.&lt;/p&gt;

&lt;p&gt;If you want to perform authorization checks directly from the end-user device, that would mean both exposing your PDP to the Internet and inviting network latency with every call. Another approach is to run those authorization checks on the device, in the browser, or from the edge—that’s where Embedded PDP comes into play.&lt;/p&gt;

&lt;p&gt;The Cerbos Embedded Policy Decision Point is a WebAssembly module that runs right in your application, putting authorization checks as close to the user as possible. This reduces your security footprint, improves latency, and unlocks powerful functionality; for example, you can embed authorization checks in your user interface to only render the buttons they actually need to see!&lt;/p&gt;

&lt;p&gt;When you update your policies in Cerbos Hub, Embedded PDPs are automatically compiled and distributed to your end-users via global CDN. This simplifies updates and streamlines management of your policies no matter where your end users are.&lt;/p&gt;

&lt;h2&gt;
  
  
  Robust policy authoring and testing
&lt;/h2&gt;

&lt;p&gt;Cerbos Hub's web IDE lets you collaboratively build and test policies right in your browser! Create policies in YAML with our useful templates, then use the playground to refine, validate, and test those authorization rules. And since everything is ultimately code, this can be tied into your existing deployment workflow, meaning that the validation and deployment of your policies becomes another step in your application management lifecycle. Git actions, artifact generation, automated build and deployment pipelines—it all fits!&lt;/p&gt;

&lt;p&gt;However, authorization is more than just code—it’s a representation of how your business functions. Who can access what, where, when, and how, goes beyond deploying your stack. Cerbos Hub is the best way to get everybody involved; from operations, to HR, to accounts payable (and even your CISO), Hub’s collaborative policy-building tools give everybody the opportunity to speak the same language and concentrate on their requirements and business cases.&lt;/p&gt;

&lt;h1&gt;
  
  
  Get started today!
&lt;/h1&gt;

&lt;p&gt;Ready to level up your authorization game? &lt;a href="https://hub.cerbos.cloud?utm_campaign=cerbos_hub_ga&amp;amp;utm_source=dev.to&amp;amp;utm_medium=text&amp;amp;utm_content=&amp;amp;utm_term="&gt;Try Cerbos Hub&lt;/a&gt; and experience the future of authorization management.&lt;/p&gt;

</description>
      <category>authz</category>
      <category>webassembly</category>
      <category>yaml</category>
      <category>accesscontrol</category>
    </item>
    <item>
      <title>Easily keep your local git repo up to date</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Fri, 12 Jul 2024 12:10:25 +0000</pubDate>
      <link>https://forem.com/phrawzty/easily-keep-your-local-git-repo-up-to-date-l52</link>
      <guid>https://forem.com/phrawzty/easily-keep-your-local-git-repo-up-to-date-l52</guid>
      <description>&lt;p&gt;Here's how to keep your clone of a Git repository current with upstream quickly and efficiently. Just pop this snippet into the &lt;code&gt;.git/config&lt;/code&gt; of your local checkout and you're good to go (some assembly required).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[remote "upstream"]&lt;/span&gt;
    &lt;span class="py"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;http url&amp;gt;&lt;/span&gt;
    &lt;span class="py"&gt;fetch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;+refs/heads/*:refs/remotes/upstream/*&lt;/span&gt;
&lt;span class="nn"&gt;[alias]&lt;/span&gt;
    &lt;span class="py"&gt;refresh&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"!git checkout main &amp;amp;&amp;amp; git fetch upstream &amp;amp;&amp;amp; git merge upstream/main main"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;git refresh&lt;/code&gt; before you branch locally, and just like magic, you'll avoid merge conflicts and other irritating side effects. It's a bit dirty, but it'll do the job in most cases. 😉&lt;/p&gt;

&lt;p&gt;Want to know more about what's going on here? Great!&lt;/p&gt;




&lt;p&gt;First: &lt;em&gt;why?&lt;/em&gt; A few of the open source projects I work on have very active repositories, and since they all favour trunk-based development, that means &lt;code&gt;main&lt;/code&gt; gets updated frequently. Furthermore, they all prefer pull requests to be proposed from clones, as humans don't touch the primary repository directly.&lt;/p&gt;

&lt;p&gt;This is a really common model, so nothing special; however I &lt;em&gt;always&lt;/em&gt; forgot to rebase before branching, except when I didn't forget to rebase, because I'd forgotten &lt;em&gt;how&lt;/em&gt; to rebase. (&lt;a href="https://jvns.ca/blog/2024/01/26/inside-git/" rel="noopener noreferrer"&gt;Git is fun!&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;So instead of having to do a little dance every time, I figured: 💭 &lt;em&gt;let the computer do the work&lt;/em&gt;. And while incantations are great, I'm cranky enough to want to know what it is the computer is doing on my behalf, so let's break it down:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[remote "upstream"]&lt;/span&gt;
    &lt;span class="py"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;http url&amp;gt;&lt;/span&gt;
    &lt;span class="py"&gt;fetch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;+refs/heads/*:refs/remotes/upstream/*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;[remote]&lt;/code&gt; block defines a &lt;em&gt;remote&lt;/em&gt; repository, i.e. a repo that isn't on your computer. Here I've given it an arbitrary name (&lt;code&gt;upstream&lt;/code&gt;). Arbitrary because it's only used in &lt;em&gt;this&lt;/em&gt; configuration context, so go with your heart on this one.&lt;/p&gt;

&lt;p&gt;Inside that block there's &lt;code&gt;url = &amp;lt;http url&amp;gt;&lt;/code&gt;, which—you guessed it—defines the URL where the remote repository lives. This could be a link to &lt;a href="https://codeberg.org/" rel="noopener noreferrer"&gt;Codeberg&lt;/a&gt;, GitHub, GitLab, or whatever y'all got going on.&lt;/p&gt;

&lt;p&gt;Next is &lt;code&gt;fetch&lt;/code&gt;, which literally tells git how to &lt;em&gt;fetch&lt;/em&gt; updates from that remote repository. That's the easy part. What do those other bits mean?&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;+&lt;/code&gt; tells git to "force" update the references. If you're familiar with Git, this means forcing the references even if the result is a non-fast-forward update. Remember at the top of the post when I  said "It's a bit dirty"? This is what I'm talking about. But here's the thing: it's &lt;em&gt;probably&lt;/em&gt; what you want anyway. 😇&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;refs/heads/*&lt;/code&gt; part just tells git to get all the branches from the remote repo. Again: it's &lt;em&gt;probably&lt;/em&gt; what you want.&lt;/p&gt;

&lt;p&gt;Finally, &lt;code&gt;:refs/remotes/upstream/*&lt;/code&gt; specifies where those fetched branches are going to be stored locally. There's a whole different blog post to be written about &lt;em&gt;just this&lt;/em&gt;, but the tl;dr is we want to keep the upstream branches separate from the local branches, because things get crazy graph-theory style if we don't. 😝&lt;/p&gt;

&lt;p&gt;OK, now the part you've all been waiting for: the &lt;em&gt;actual command&lt;/em&gt;!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[alias]&lt;/span&gt;
    &lt;span class="py"&gt;refresh&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"!git checkout main &amp;amp;&amp;amp; git fetch upstream &amp;amp;&amp;amp; git merge upstream/main main"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;[alias]&lt;/code&gt; block defines, well, an alias. It's basically a shortcut that lets us run arbitrary commands or sequences (including, notably, shell commands) so that we don't have to write them out by hand each time. In this case, the alias is &lt;code&gt;refresh&lt;/code&gt;;  the idea here being that we can type &lt;code&gt;git refresh&lt;/code&gt; on the shell and it &lt;em&gt;runs the command sequence&lt;/em&gt;, thus simplifying our lives somewhat. And some is better than none.&lt;/p&gt;

&lt;p&gt;Also: remember at the top of the post when I  said "It's a bit dirty"? This shell command is &lt;em&gt;actually&lt;/em&gt; what I'm talking about. 🥸 Let's be legends…&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;!&lt;/code&gt; right at the start of the sequence tells git to treat the whole thing as a shell command, so whatever comes next will just be executed like we typed it out.&lt;/p&gt;

&lt;p&gt;First we make sure that we're on the &lt;code&gt;main&lt;/code&gt; branch in our local repo by running &lt;code&gt;git checkout main&lt;/code&gt;. It's possible that your repo uses a different name for trunk ("master" was popular for a long time), but "main" is common.&lt;/p&gt;

&lt;p&gt;Then we &lt;code&gt;git fetch upstream&lt;/code&gt; to nab that fresh upstream data from the remote repository. Remember &lt;code&gt;upstream&lt;/code&gt;? It's the remote repository we defined previously. Ah what fun we had.&lt;/p&gt;

&lt;p&gt;Finally, we &lt;em&gt;merge&lt;/em&gt; the changes from the &lt;code&gt;main&lt;/code&gt; branch of &lt;code&gt;upstream&lt;/code&gt; into the &lt;code&gt;main&lt;/code&gt; branch of our local repository. That's literally how to read &lt;code&gt;git merge upstream/main main&lt;/code&gt;. 🧠&lt;/p&gt;

&lt;p&gt;And that's it! A couple of lines gets us a quick, reusable, fairly reliable method of keeping our local repo up to date. &lt;/p&gt;

&lt;p&gt;Hope that helps! Let me know!&lt;/p&gt;




&lt;p&gt;BONUS: You might also be wondering what those &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; are for in between each of the commands. The Very Correct Definition is that &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; is a "logical AND operator". What it's used for in this case is a way to chain a series of shell commands into a sequence, whereby the &lt;em&gt;next&lt;/em&gt; command will only be called if the &lt;em&gt;current&lt;/em&gt; one was successful. This way, we don't end up doing horrible things to our local repo &lt;del&gt;if&lt;/del&gt; when things go wrong.&lt;/p&gt;

</description>
      <category>git</category>
      <category>shell</category>
      <category>programming</category>
    </item>
    <item>
      <title>Microsoft Entra External ID &amp; Cerbos ✨</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Wed, 26 Jun 2024 13:18:37 +0000</pubDate>
      <link>https://forem.com/cerbos/microsoft-entra-external-id-cerbos-ccp</link>
      <guid>https://forem.com/cerbos/microsoft-entra-external-id-cerbos-ccp</guid>
      <description>&lt;p&gt;👋 Looking to level up your authentication (authn) and authorization (authz) game? Here's a great tutorial that dives into integrating Microsoft Entra External ID for seamless external authentication and Cerbos for top-notch, fine-grained authorization. You’ll learn about adding authentication to your external-facing apps, how to write policies, and what a policy decision point is. With clear steps, sample code, and just enough YAML to meet your daily quota, you'll learn to create secure and scalable solutions that are actually usable in the real world. Check out the &lt;a href="https://bit.ly/45FdSGu" rel="noopener noreferrer"&gt;full guide here&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;As an added bonus, this is actually part two of a three-part series. If you’re not entirely sure what authentication and authorization are (or just want a refresher before diving into the tutorial), you should definitely check out the &lt;a href="https://devblogs.microsoft.com/identity/extneral-id-and-cerbos/" rel="noopener noreferrer"&gt;first part&lt;/a&gt;, too. 😄&lt;/p&gt;

&lt;p&gt;Questions? Comments? Hit us up in our &lt;a href="https://go.cerbos.io/slack" rel="noopener noreferrer"&gt;Community Slack&lt;/a&gt;—let's get that conversation going!&lt;/p&gt;

</description>
      <category>authz</category>
      <category>tutorial</category>
      <category>cerbos</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Behind the Helm (September 2023)</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Mon, 08 Jan 2024 09:01:29 +0000</pubDate>
      <link>https://forem.com/phrawzty/behind-the-helm-september-2023-905</link>
      <guid>https://forem.com/phrawzty/behind-the-helm-september-2023-905</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the web edition of the &lt;strong&gt;Behind the Helm&lt;/strong&gt;, Scaleway's monthly Kubernetes newsletter. For the best Kubernetes news in your inbox every month, &lt;a href="https://www.scaleway.com/en/kubernetes-newsletter/" rel="noopener noreferrer"&gt;subscribe today&lt;/a&gt;!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hello lovely subscribers!&lt;/p&gt;

&lt;p&gt;September is wrapping up, and autumn is fast approaching. This month’s edition of Behind The Helm is here with its usual round-up of blog posts, podcasts and events news to keep you up to date with the cloud native world.&lt;/p&gt;

&lt;h4&gt;
  
  
  Blogs &amp;amp; news
&lt;/h4&gt;

&lt;p&gt;The legacy K8s repositories installable through yum and apt are now &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-0m4q-1xqk-!3qql" rel="noopener noreferrer"&gt;frozen as of September 13th&lt;/a&gt;; for new updates to these repositories you’ll need to pull from the new registry at &lt;a href="http://k8s.io/" rel="noopener noreferrer"&gt;k8s.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Author Eyal Bukchin has written an &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-0m4e-1xqk-!3qql" rel="noopener noreferrer"&gt;excellent blog post&lt;/a&gt; comparing three local development tools for Kubernetes: Telepresence, Gefyra, and mirrord. Check it out to learn all about these tools and how they can improve your development experience!&lt;/p&gt;

&lt;h4&gt;
  
  
  Podcast episodes
&lt;/h4&gt;

&lt;p&gt;The Kubernetes Podcast has a couple of excellent episodes out this month, including an &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-0m4f-1xqk-!3qql" rel="noopener noreferrer"&gt;interview with Grace Nguyen&lt;/a&gt; about the 1.28 release. Grace was the release lead for this version, so if you want a peek behind the scenes at what actually goes into a release cycle, be sure to give it a listen!&lt;/p&gt;

&lt;h4&gt;
  
  
  Events
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-0m4s-1xqk-!3qql" rel="noopener noreferrer"&gt;Kubernetes Community Days UK&lt;/a&gt; is happening on the 17th and 18th October. If you’ll be near London around then, definitely consider attending!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;May your deployments be smooth and your pipelines never fail.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Eli &amp;amp; the Scaleway team&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>news</category>
      <category>community</category>
    </item>
    <item>
      <title>Behind the Helm (August 2023)</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Mon, 04 Sep 2023 09:36:22 +0000</pubDate>
      <link>https://forem.com/scaleway/behind-the-helm-august-2023-3o6d</link>
      <guid>https://forem.com/scaleway/behind-the-helm-august-2023-3o6d</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the web edition of the Behind the Helm, Scaleway's monthly Kubernetes newsletter. For the best Kubernetes news in your inbox every month, &lt;a href="https://www.scaleway.com/en/kubernetes-newsletter/" rel="noopener noreferrer"&gt;subscribe today&lt;/a&gt;!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hello lovely subscribers!&lt;/p&gt;

&lt;p&gt;I hope you’ve had a great summer so far. At Scaleway, the latest additions to our &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-02w4-mi1-!3qql" rel="noopener noreferrer"&gt;changelog&lt;/a&gt; have all been about databases; it’s clearly the summer of data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-02w1-mi1-!3qql" rel="noopener noreferrer"&gt;Kubernetes 1.28 is out&lt;/a&gt;! This edition brings us better recovery from unexpected node shutdown, longer lead times between API server and node version updates, and a whole host of features entering the alpha phase.&lt;/p&gt;

&lt;p&gt;Marino Wijay and Matt Turner joined David Flanagan and Laura Sanatamaria for another episode of &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-02wx-mi1-!3qql" rel="noopener noreferrer"&gt;Cloud Native Compass&lt;/a&gt;, this time around Istio’s new Ambient Mesh offering. Give it a listen if you want to stay on the cutting edge of the service mesh world!&lt;/p&gt;

&lt;p&gt;Last week’s edition of the &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-02am-mi1-!3qql" rel="noopener noreferrer"&gt;Scaleway Sessions&lt;/a&gt; featured Thibault Lengagne from &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-02al-mi1-!3qql" rel="noopener noreferrer"&gt;Padok&lt;/a&gt;, taking us through two different attack scenarios on a K8s cluster used to deploy a vulnerable web app. We had an absolute blast chatting with Thibault; you can &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-02a5-mi1-!3qql" rel="noopener noreferrer"&gt;check out the recording here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On that episode we also talked about a number of tools that are out there to help developers keep their clusters safe, including using &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-02ak-mi1-!3qql" rel="noopener noreferrer"&gt;Kyverno&lt;/a&gt; to double check that your pods really do only have the permissions they need. If you’ve watched the latest Scaleway Sessions linked above, read &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-02ai-mi1-!3qql" rel="noopener noreferrer"&gt;this blog post from Kyverno&lt;/a&gt; to know more about how to mitigate one of the vulnerabilities we exploited!&lt;/p&gt;

&lt;p&gt;Lastly, we at Scaleway would like to note with great sadness the passing of &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-02a0-mi1-!3qql" rel="noopener noreferrer"&gt;Kris Nóva&lt;/a&gt;, a trailblazing developer, community builder and Kubernetes contributor. Her work in distributed systems and open-source development has left an enormous legacy, and she will be much missed.&lt;/p&gt;

&lt;p&gt;May your deployments be smooth and your pipelines never fail,&lt;/p&gt;

&lt;p&gt;Eli &amp;amp; the &lt;a href="https://twitter.com/Scaleway_devs" rel="noopener noreferrer"&gt;Scaleway&lt;/a&gt; team&lt;/p&gt;

&lt;p&gt;PS. I’ve been on vacation this month, so there’s no crossword this time around—stay tuned for the next edition!&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>news</category>
      <category>community</category>
    </item>
    <item>
      <title>Behind the Helm (July 2023)</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Thu, 03 Aug 2023 22:00:00 +0000</pubDate>
      <link>https://forem.com/scaleway/behind-the-helm-july-2023-545j</link>
      <guid>https://forem.com/scaleway/behind-the-helm-july-2023-545j</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the web edition of the Behind the Helm, Scaleway's monthly Kubernetes newsletter. For the best Kubernetes news in your inbox every month, &lt;a href="https://www.scaleway.com/en/kubernetes-newsletter/" rel="noopener noreferrer"&gt;subscribe today&lt;/a&gt;!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hi, lovely subscribers!&lt;/p&gt;

&lt;p&gt;I hope you’ve had a great summer so far. At Scaleway, we’ve been hard at work releasing new features - check out our &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-qeec-lk4-!3qql" rel="noopener noreferrer"&gt;changelog&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Argonaut have released &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-qee1-lk4-!3qql" rel="noopener noreferrer"&gt;a technical exploration of their CI pipelines&lt;/a&gt;, which is absolutely fascinating. If you’d like a peek under the hood of one of the most popular deployment tools for K8s, this is a must-read.&lt;/p&gt;

&lt;p&gt;IstioCon will be happening on &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-qeex-lk4-!3qql" rel="noopener noreferrer"&gt;the 25th &amp;amp; 26th of September&lt;/a&gt;, with a mix of virtual and in-person content scheduled. If you want to keep up with the movers and shakers in the service mesh world, give it a look. In the meantime, you can read about Istio’s authentication and authorization policies in &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-qefm-lk4-!3qql" rel="noopener noreferrer"&gt;this cool article&lt;/a&gt; from InfraCloud!&lt;/p&gt;

&lt;p&gt;Also from InfraCloud is &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-qefl-lk4-!3qql" rel="noopener noreferrer"&gt;this primer on MLOps&lt;/a&gt; - if you’ve been wondering about whether machine learning technology has a place in your workflow, now is the time to find out.&lt;/p&gt;

&lt;p&gt;Our Kubernetes meetup, KubeTalks, is taking a summer break - the &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-qef5-lk4-!3qql" rel="noopener noreferrer"&gt;next edition&lt;/a&gt; will be on the 28th September at our Paris office!&lt;/p&gt;

&lt;p&gt;Finally, if your work is slowing down over the summer, and you find yourself with some time spare to catch up on everything cloud-native, you can never go wrong with the CNCF’s &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-qefk-lk4-!3qql" rel="noopener noreferrer"&gt;excellent course of Online Programs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;May your deployments be smooth and your pipelines never fail,&lt;br&gt;
&lt;a href="https://twitter.com/eliholderness" rel="noopener noreferrer"&gt;Eli&lt;/a&gt; &amp;amp; the rest of the &lt;a href="https://twitter.com/Scaleway_devs" rel="noopener noreferrer"&gt;Scaleway team&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;p.s. It’s too warm to think very hard right now, so this month’s crossword isn’t cryptic! Enjoy 🙂&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%2Fuj53rhks1n626po5v3w3.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%2Fuj53rhks1n626po5v3w3.png" alt="A Kubernetes-themed crossword puzzle" width="800" height="737"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>news</category>
      <category>kubernetes</category>
      <category>community</category>
      <category>crossword</category>
    </item>
    <item>
      <title>Behind the Helm (June 2023)</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Thu, 29 Jun 2023 22:00:00 +0000</pubDate>
      <link>https://forem.com/scaleway/behind-the-helm-june-2023-1i4o</link>
      <guid>https://forem.com/scaleway/behind-the-helm-june-2023-1i4o</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the web edition of the Behind the Helm, Scaleway's monthly Kubernetes newsletter. For the best Kubernetes news in your inbox every month, &lt;a href="https://www.scaleway.com/en/kubernetes-newsletter/" rel="noopener noreferrer"&gt;subscribe today&lt;/a&gt;!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Hello lovely subscribers!
&lt;/h2&gt;

&lt;p&gt;It’s June, and with the new month comes a new edition of Behind The Helm. We’ve got our usual round-up of blog posts, podcasts and events news to keep you up to date with the cloud native world.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blogs &amp;amp; news
&lt;/h2&gt;

&lt;p&gt;First up, we’ve got some tooling news: Red Hat has &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-ek!2-5fe-!3qql" rel="noopener noreferrer"&gt;brought Podman to the desktop&lt;/a&gt; with version 1.0 of their Community Edition! This release can help businesses streamline OpenShift workflows, and swiftly onboard developers who are new to cloud native.&lt;/p&gt;

&lt;p&gt;Next is a fascinating read by the folks at OpenTelemetry, focusing on runtime observability in K8s. &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-ek!8-5fe-!3qql" rel="noopener noreferrer"&gt;Check it out&lt;/a&gt;, and bring your debugging to the next level with your newly acquired tracing superpowers.&lt;/p&gt;

&lt;p&gt;The awesome folks over at Inheaden connected 250,000 IoT devices to the cloud using K8s; &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-ek!8-5fe-!3qql" rel="noopener noreferrer"&gt;read the deep dive on our blog&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Podcast episodes
&lt;/h2&gt;

&lt;p&gt;The Changelog podcast covered the hallway track at the Linux Foundation’s Open Source Summit last month, and this month they’ve released their &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-ek!z-5fe-!3qql" rel="noopener noreferrer"&gt;last episode&lt;/a&gt; of that coverage — including some very cool guests.&lt;/p&gt;

&lt;p&gt;If you want to keep up to date with all the WASM hype, check out &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-ek!4-5fe-!3qql" rel="noopener noreferrer"&gt;this episode&lt;/a&gt; of the Kubernetes Podcast with Justin Cormack, the CTO of Docker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Events
&lt;/h2&gt;

&lt;p&gt;With summer coming, our Lille office is in full bloom. We’ll take advantage of its gorgeous terrace to host an edition of KubeTalks, our K8s-focused meetup. This event will be in French, and we’ll welcome Stephane Dessein, CTO of &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-ek!c-5fe-!3qql" rel="noopener noreferrer"&gt;Le Fourgon&lt;/a&gt;, along with Bruno Flament, DevSecOps Kubernetes at &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-ek!1-5fe-!3qql" rel="noopener noreferrer"&gt;Whispeak&lt;/a&gt;, who’ll discuss Kubernetes service traceability. &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-ek!x-5fe-!3qql" rel="noopener noreferrer"&gt;Save your spot&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-ek2m-5fe-!3qql" rel="noopener noreferrer"&gt;Registration is now open&lt;/a&gt; for KubeCon + CloudNativeCon in Chicago this November! Book your tickets, book your hotel—get hype.&lt;/p&gt;

&lt;p&gt;Finally, our &lt;a href="https://twitter.com/Scaleway_devs" rel="noopener noreferrer"&gt;DevRel team&lt;/a&gt; will also be attending &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-ek2l-5fe-!3qql" rel="noopener noreferrer"&gt;DevOpsDays Amsterdam&lt;/a&gt; if any of you are there, we’d love to hang out! Come grab us for a chat and a coffee.&lt;/p&gt;

&lt;p&gt;That’s all for now (apart from the crossword, of course) — see you all in July!&lt;/p&gt;

&lt;p&gt;Yours,&lt;br&gt;
&lt;a href="https://twitter.com/eliholderness" rel="noopener noreferrer"&gt;Eli&lt;/a&gt; &amp;amp; the Scaleway &lt;a href="https://twitter.com/Scaleway_devs" rel="noopener noreferrer"&gt;team&lt;/a&gt;&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%2Fpawdmgntgqscd8yrovf2.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%2Fpawdmgntgqscd8yrovf2.png" alt="A crossword puzzle" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>news</category>
      <category>kubernetes</category>
      <category>crossword</category>
      <category>community</category>
    </item>
    <item>
      <title>Behind the Helm (May 2023)</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Thu, 08 Jun 2023 07:00:00 +0000</pubDate>
      <link>https://forem.com/scaleway/behind-the-helm-may-2023-1ehj</link>
      <guid>https://forem.com/scaleway/behind-the-helm-may-2023-1ehj</guid>
      <description>&lt;p&gt;&lt;em&gt;This is the web edition of the Behind the Helm, Scaleway's monthly Kubernetes newsletter. For the best Kubernetes news in your inbox every month, &lt;a href="https://www.scaleway.com/en/kubernetes-newsletter/" rel="noopener noreferrer"&gt;subscribe today&lt;/a&gt;!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hello lovely subscribers!&lt;/p&gt;

&lt;p&gt;It’s been something of a quiet month in the Kubernetes world (is such a thing even possible?) as we all recover from a hectic April. Nonetheless, we’ve got a round-up of news and tidbits for you to enjoy on your coffee break.&lt;/p&gt;

&lt;p&gt;With version 1.27 having been released last month, Google’s Kubernetes Podcast &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-e8ak-ki4-!3qql" rel="noopener noreferrer"&gt;interviewed Xander Grzywisnk&lt;/a&gt;, the release lead for 1.27. If you want to know all about the ins and outs of complex software releases, give it a listen.&lt;/p&gt;

&lt;p&gt;Kubernetes &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-e8ai-ki4-!3qql" rel="noopener noreferrer"&gt;v1.27.2&lt;/a&gt; was released on the 17th March! As a patch, it’s mostly bug fixes and error handling updates; no major feature releases, but plenty of quality-of-life upgrades. You can read about each of them in more detail on the &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-e8a0-ki4-!3qql" rel="noopener noreferrer"&gt;official K8s blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Toronto celebrated its &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-e8wa-ki4-!3qql" rel="noopener noreferrer"&gt;first KubeHuddle&lt;/a&gt; on the 17th and 18th, bringing together speakers and community members from around the world. KubeHuddle is a community-run conference series which began in Edinburgh last year, aiming to provide a space for beginners and experts alike to share knowledge and make connections.&lt;/p&gt;

&lt;p&gt;For anyone who’d like to get in on all the conference hype without leaving the comfort of your own home, &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-e8w9-ki4-!3qql" rel="noopener noreferrer"&gt;PlatformCon&lt;/a&gt; is fast approaching! On the 8th and 9th of June you’ll be able to see talks from DevOps and platform engineering leaders; it’s completely free and completely virtual. What’s not to love?&lt;/p&gt;

&lt;p&gt;As for in-person conferences, our very own Devrel team will be off to &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-e8w!-ki4-!3qql" rel="noopener noreferrer"&gt;DevOpsDays Amsterdam&lt;/a&gt; in June! We’re looking forward to seeing some awesome talks, meeting colleagues from across the industry, and making new friends. If you’ll be there, &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-e8w2-ki4-!3qql" rel="noopener noreferrer"&gt;let us know&lt;/a&gt; so we can keep an eye out!&lt;/p&gt;

&lt;p&gt;As always, we’ve attached this month’s crossword. This one is cryptic, but you can pester me &lt;a href="https://t.elements.scaleway.com/c/?t=b15feda-4mc-e8w2-ki4-!3qql" rel="noopener noreferrer"&gt;on Twitter&lt;/a&gt; for hints!&lt;/p&gt;

&lt;p&gt;May your CI pipelines never fail,&lt;/p&gt;

&lt;p&gt;Yours,&lt;/p&gt;

&lt;p&gt;Eli &amp;amp; the rest of the Scaleway team&lt;/p&gt;

&lt;p&gt;p.s. Here’s this month’s cryptic crossword!&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%2F975mictoxc3f4nx8eadt.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%2F975mictoxc3f4nx8eadt.png" alt=" " width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>news</category>
      <category>kubernetes</category>
      <category>crossword</category>
      <category>community</category>
    </item>
  </channel>
</rss>
