<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gabriel L. Manor</title>
    <description>The latest articles on DEV Community by Gabriel L. Manor (@gemanor).</description>
    <link>https://dev.to/gemanor</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%2F221980%2F3b7b80e4-9264-454a-bd57-c9490d97f1a4.jpg</url>
      <title>DEV Community: Gabriel L. Manor</title>
      <link>https://dev.to/gemanor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gemanor"/>
    <language>en</language>
    <item>
      <title>Building a Secure Flight Booking System with LLM Agent in Langflow</title>
      <dc:creator>Gabriel L. Manor</dc:creator>
      <pubDate>Mon, 10 Mar 2025 18:00:00 +0000</pubDate>
      <link>https://dev.to/permit_io/building-a-secure-flight-booking-system-with-llm-agent-in-langflow-3ml</link>
      <guid>https://dev.to/permit_io/building-a-secure-flight-booking-system-with-llm-agent-in-langflow-3ml</guid>
      <description>&lt;p&gt;LangFlow allows developers and non-developers alike to build AI applications through a visual, drag-and-drop interface. It makes it easier to work with LLMs in workflows and, therefore, serves as the primary tool for developing AI applications.&lt;/p&gt;

&lt;p&gt;When these applications handle sensitive data such as financial details, security becomes a top priority. Without proper safeguards, there’s a risk of unauthorized access to personal information or critical operations, which could erode user trust and compromise the system.&lt;/p&gt;

&lt;p&gt;There are four key perimeters to implement this type of protection in LangFlow applications. Those are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prompt Filtering&lt;/strong&gt; : Ensures user inputs align with predefined access policies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAG Protection&lt;/strong&gt; : Controls who can access retrieved data based on their permissions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure External Access&lt;/strong&gt; : Limits interactions with external APIs to authorized users only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response Enforcement&lt;/strong&gt; : Guarantees that users only see the information they’re permitted to view.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this guide, we’ll use these perimeters to build a secure &lt;strong&gt;flight booking system&lt;/strong&gt; from the ground up. To do that, we’ll use &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;, an authorization service, to enforce access controls at every stage. The tutorial will cover creating AI-based workflows for searching flights, checking travel policies, and booking trips, all while keeping sensitive data safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tool Overview
&lt;/h2&gt;

&lt;p&gt;Before we get our hands dirty, let’s examine the tools we will use to build this application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.langflow.org/" rel="noopener noreferrer"&gt;Langflow&lt;/a&gt; is a low-code framework that enables developers to visually design and deploy AI apps with LLMs. It simplifies the integration of AI components by allowing you to create complex workflows via a drag-and-drop interface. In our project, we’ll use Langflow to build three workflows: flight search, information queries, and booking operations, connecting our LLM components with security layers.&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt; is an authorization-as-a-service that helps developers implement &lt;a href="https://www.permit.io/blog/what-is-fine-grained-authorization-fga" rel="noopener noreferrer"&gt;fine-grained access control&lt;/a&gt; in their application. In our system, it will handle access control by protecting sensitive flight data and implementing rules like “only verified users can book flights” or “premium members can access special rates.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, these two tools help us create a secure flight booking pipeline: managing workflows and ensuring every operation follows security rules from search to booking.&lt;/p&gt;

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

&lt;p&gt;This tutorial assumes you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic knowledge of &lt;a href="https://www.permit.io/blog/what-is-abac" rel="noopener noreferrer"&gt;Attribute Based Access Control&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;An &lt;a href="https://platform.openai.com/" rel="noopener noreferrer"&gt;OpenAI API key&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An Astra DB vector database with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An Astra &lt;a href="https://docs.datastax.com/en/astra-db-serverless/get-started/quickstart.html" rel="noopener noreferrer"&gt;DB application token&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://docs.datastax.com/en/astra-db-serverless/databases/manage-collections.html#create-collection" rel="noopener noreferrer"&gt;collection&lt;/a&gt; in Astra&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuring Attribute-Based Access Control Policies
&lt;/h2&gt;

&lt;p&gt;Before we start building our AI agent flow, let’s configure our authorization model in &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s what we want our policy to restrict:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regular users should be able to search for flights but not see sensitive details like seat availability or pricing.&lt;/li&gt;
&lt;li&gt;Premium members should get extra privileges, like booking, modifying, and accessing detailed flight data.&lt;/li&gt;
&lt;li&gt;Regional users should only be able to search for flights in their allowed area.&lt;/li&gt;
&lt;li&gt;Unverified users should have very limited access—they’ll see basic flight info but can’t book or modify anything.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To enforce these rules, we’ll need to create the following &lt;strong&gt;resources&lt;/strong&gt; , &lt;strong&gt;actions&lt;/strong&gt; , &lt;strong&gt;attributes&lt;/strong&gt; , and &lt;strong&gt;condition sets&lt;/strong&gt; :&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Flight&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Available Actions: &lt;code&gt;search&lt;/code&gt;, &lt;code&gt;info&lt;/code&gt; , &lt;code&gt;viewprice&lt;/code&gt;, &lt;code&gt;viewavailability&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Attributes:
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;type&lt;/code&gt; (String) – Specifies the type of operation (info, search, booking).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sensitivity&lt;/code&gt; (String) – Defines data sensitivity (public, protected, private).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;Booking&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Available Actions: &lt;code&gt;create&lt;/code&gt;, &lt;code&gt;modify&lt;/code&gt;, &lt;code&gt;cancel&lt;/code&gt;, &lt;code&gt;view&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Attributes:
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;type&lt;/code&gt; (String) – Defines booking operation types.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sensitivity&lt;/code&gt; (String) – Controls access to booking data based on its sensitivity.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  User Attributes
&lt;/h3&gt;

&lt;p&gt;User access is determined by three key attributes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;membership_tier&lt;/code&gt; (Array) – Defines a user's access level (e.g., &lt;code&gt;basic&lt;/code&gt;, &lt;code&gt;premium&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;region&lt;/code&gt; (String) – Specifies the user’s geographical location (&lt;code&gt;domestic&lt;/code&gt;, &lt;code&gt;international&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;verified&lt;/code&gt; (Boolean) – Indicates if the user’s identity has been confirmed (&lt;code&gt;true&lt;/code&gt;/&lt;code&gt;false&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Condition Sets
&lt;/h3&gt;

&lt;p&gt;These condition sets define who can access what, controlling how users interact with resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Membership Tier Access:&lt;/strong&gt;
&lt;code&gt;user.membership_tier&lt;/code&gt; includes &lt;code&gt;resource.class&lt;/code&gt; AND 
&lt;code&gt;user.verified == true&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regional Restrictions:&lt;/strong&gt;
&lt;code&gt;user.region == "domestic"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sensitive Data Access:&lt;/strong&gt;
&lt;code&gt;user.membership_tier&lt;/code&gt; includes &lt;code&gt;"premium"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s set up attribute-based (ABAC) policies using the &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt; dashboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup a New Project and Credentials
&lt;/h3&gt;

&lt;p&gt;To get started, let’s set up a new project and get credentials to connect Permit SDK to our project. To do that, follow the steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt; account if you haven’t already&lt;/li&gt;
&lt;li&gt;Create a new project named &lt;code&gt;flight-booking&lt;/code&gt; in the dashboard&lt;/li&gt;
&lt;li&gt;Select your preferred environment (Development/Production) and copy your API Key
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836kjomilyg07lrjdu0zuts" title="image.png" alt="image.png" width="800" height="309"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Define Resources
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Policy → Resources&lt;/strong&gt; in your &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt; dashboard.&lt;/li&gt;
&lt;li&gt;
First, let’s create a &lt;code&gt;flight&lt;/code&gt; resource. This will handle everything related to flight information and searches:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  {
    "actions": [
      "search", // Search for available flights
      "info", // Get flight details
      "viewprice", // Access pricing information
      "viewavailability" // Check seat availability
    ],
    "attributes": {
      "type": "String", // Controls the type of operation ("info", "search", "booking")
      "sensitivity": "String" // Defines data sensitivity ("public", "protected", "private")
    }
  }
&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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836ng0t01ah07n3xel6zz2k" 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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836ng0t01ah07n3xel6zz2k" title="image.png" alt="image.png" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Next, create a booking resource for managing actual flight bookings:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  {
    "actions": [
    "create", // Create new bookings
    "modify", // Change existing bookings
    "cancel", // Cancel bookings
    "view" // View booking details
  ],
  "attributes": {
    "type": "String", // Defines booking operation types
    "sensitivity": "String" // Controls booking data sensitivity
    }
  }
&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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836nqd101z608lsokmbr1b5" 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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836nqd101z608lsokmbr1b5" title="image.png" alt="image.png" width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  User Attributes
&lt;/h3&gt;

&lt;p&gt;Now, let’s define user attributes to enable fine-grained access control based on user properties like membership tier, region, and verification status.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Directory → Users → Settings&lt;/strong&gt; page, define the following user attributes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "membership_tier": "Array", "region": "String", "verified": "Boolean"}
&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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836nzql023i08lsd5pbk0c2" 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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836nzql023i08lsd5pbk0c2" title="image.png" alt="image.png" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Condition Sets
&lt;/h3&gt;

&lt;p&gt;Now let’s configure the condition sets for our flight booking system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
Navigate to &lt;strong&gt;Policy → ABAC Rules&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
Click &lt;strong&gt;ABAC User Sets&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
Create the following sets:
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;For membership tier access:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  user.membership_tier includes resource.class AND
user.verified == true
&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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836odns020107n3i40yutek" 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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836odns020107n3i40yutek" title="image.png" alt="image.png" width="800" height="697"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For regional restrictions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user.region == "domestic"
&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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836omyv028g07n3g3xjc4cs" 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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836omyv028g07n3g3xjc4cs" title="image.png" alt="image.png" width="800" height="698"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For sensitive data access:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user.membership_tier includes "premium"
&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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836oybs02vf08lsrbald3x4" 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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836oybs02vf08lsrbald3x4" title="image.png" alt="image.png" width="800" height="707"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Enforcing Policies
&lt;/h3&gt;

&lt;p&gt;Now we’ll use the policy editor to enforce our access control rules. In the policy matrix, you’ll see our resources and actions with checkboxes for each condition set at the top:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;For the &lt;code&gt;booking&lt;/code&gt; resource:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  cancel:
  - ✓ members □ regional □ sensitive

  create:
  - ✓ members ✓ regional ✓ sensitive

  modify:
  - ✓ members □ regional ✓ sensitive

  view:
  - ✓ members □ regional □ sensitive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;For the &lt;code&gt;flight&lt;/code&gt; resource:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  info:
  - □ members □ regional □ sensitive (public access)

  search:
  - □ members ✓ regional □ sensitive

  viewavailability:
  - ✓ members □ regional □ sensitive

  viewprice:
  - ✓ members □ regional ✓ sensitive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These checkboxes enforce our conditions, when multiple boxes are checked for an action, all conditions must be satisfied for the action to be allowed.&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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836pd1k02sf07n3tqcmlef5" 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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836pd1k02sf07n3tqcmlef5" title="image.png" alt="image.png" width="800" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now our access control infrastructure is properly configured, let’s start building our flows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Flows
&lt;/h2&gt;

&lt;p&gt;Now that we’ve set up our access control infrastructure, let’s build our Flight Booking Agent! We’ll create three flows that demonstrate how to implement security while providing a great user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up local PDP container
&lt;/h3&gt;

&lt;p&gt;First, you’ll need to run your local PDP container for Permit’s ABAC policies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker pull permitio/pdp-v2:latest

docker run -it -p 7766:7000 \\
    --env PDP_DEBUG=True \\
    --env PDP_API_KEY=&amp;lt;YOUR_API_KEY&amp;gt; \\
    permitio/pdp-v2:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;&amp;lt;YOUR_API_KEY&amp;gt;&lt;/code&gt; with your Permit API Key. If you don’t have Docker, install it from &lt;a href="https://docs.docker.com/get-docker/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flight Search Flow
&lt;/h3&gt;

&lt;p&gt;Let’s build our first and most fundamental flow the flight search. This flow will help users find available flights while ensuring they only see what they’re authorized to access.&lt;/p&gt;

&lt;p&gt;First, we’ll gather all the components we need. Open your Langflow canvas and from the components panel, drag over a &lt;strong&gt;Text Input&lt;/strong&gt; (we’ll use this for the JWT token), a &lt;strong&gt;Chat Input&lt;/strong&gt; (for the actual search queries), and a &lt;strong&gt;JWT Validator&lt;/strong&gt;. You’ll also need a &lt;strong&gt;Permission Check&lt;/strong&gt; component. This is important for our security layer. Add an &lt;strong&gt;If-Else Router&lt;/strong&gt; , City Selection Agent, &lt;strong&gt;Astra DB&lt;/strong&gt; , &lt;strong&gt;Parse Data&lt;/strong&gt; , and two &lt;strong&gt;Chat Output&lt;/strong&gt; components.&lt;/p&gt;

&lt;p&gt;Now, let’s set up each component carefully. Start with the &lt;strong&gt;Text Input&lt;/strong&gt; , this is where you enter your JWT token. Next, configure your &lt;strong&gt;JWT Validator&lt;/strong&gt; with your JWKS URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JWKS URL: "&amp;lt;https://test.com/.well-known/jwks.json&amp;gt;"  
// Replace with your actual JWKS URL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the &lt;strong&gt;Permission Check&lt;/strong&gt; component, you’ll need to input your &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt; credentials and specify what resource we’re protecting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PDP URL: "&amp;lt;http://localhost:7766&amp;gt;" // Your local PDP endpoint
API Key: "your-permit-api-key" // Your Permit.io API key
Resource: "flight"
Action: "search"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The City Selection Agent is where things get interesting. This is our intelligent assistant that will parse user queries and format them properly. Configure it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Model: gpt-4o-mini
Agent Instructions: "You are a flight search assistant. Your job is to:
1. Extract departure and arrival cities from user queries
2. Validate that these are real cities with airports
3. Format the search request for our database
4. Handle cases where cities are unclear or invalid"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the database interaction, set up your &lt;strong&gt;Astra DB&lt;/strong&gt; component with your database details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Collection Name: "flights"
Database: "flight_db" // Your database name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the &lt;strong&gt;Parse Data&lt;/strong&gt; component will format our results nicely for users:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Template: 
"""
Flight {row_number}: {departure_city} to {arrival_city}
Departure: {departure_time}
Airline: {airline}
Flight Number: {flight_number}
Price: ${price}
Available Seats: {seats}
"""
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now comes the important part - connecting everything together. Start by connecting your Text Input’s &lt;strong&gt;Message&lt;/strong&gt; output to the JWT Validator’s &lt;strong&gt;JWT Token&lt;/strong&gt; input. The Chat Input’s “Message” output should go to the If-Else Router’s &lt;strong&gt;True Input&lt;/strong&gt; input.&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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836pz1c03u608lsx7eiulx7" 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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836pz1c03u608lsx7eiulx7" title="image.png" alt="image.png" width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now click the &lt;strong&gt;Playground&lt;/strong&gt; and try some realistic search queries like “Find flights from New York to London next week” or “Show me flights from SFO to JFK tomorrow morning”. If everything is working correctly, you’ll either see a nicely formatted list of flights (for authorized users) or an access denied message (for unauthorized users).&lt;/p&gt;

&lt;h3&gt;
  
  
  Flight Information Flow
&lt;/h3&gt;

&lt;p&gt;Next, let’s create a flow that handles flight policy and information queries. This flow is a bit different from our search flow, instead of searching flight schedules, it helps users understand policies, baggage rules, and other travel information.&lt;/p&gt;

&lt;p&gt;Start by gathering your components. Like before, you’ll need some familiar components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Text Input&lt;/strong&gt; for the JWT token&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chat Input&lt;/strong&gt; for questions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JWT Validator&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permission Check&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we’re also adding a &lt;strong&gt;Local Expert Agent&lt;/strong&gt; who will be our knowledge base expert, along with a &lt;strong&gt;URL Component&lt;/strong&gt; to fetch policy information. Don’t forget the &lt;strong&gt;Parse Data component&lt;/strong&gt; and two &lt;strong&gt;Chat Outputs&lt;/strong&gt; for handling both successful and denied requests.&lt;/p&gt;

&lt;p&gt;The JWT Validator setup remains the same as our search flow, no need to change that configuration. For the Permission Check, we’ll adjust it slightly for information access:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PDP URL: "&amp;lt;http://localhost:7766&amp;gt;"
API Key: "your-permit-api-key"
Resource: "flight"
Action: "info"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s where it gets interesting, our Local Expert Agent. This is the brain of our information flow, so let’s configure it carefully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mode: gpt-4o-mini
Instructions: "You are a knowledgeable Local Expert that provides accurate flight policy and service information. You should:
1. Answer questions about baggage policies
2. Explain flight rules and restrictions
3. Provide information about services and amenities
4. Always maintain privacy by not revealing sensitive pricing or route details without authorization"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To give our Expert Agent access to accurate information, set up the URL Component with our policy endpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;URLs: ["&amp;lt;https://api.flightpolicies.com/baggage&amp;gt;", "&amp;lt;https://api.flightpolicies.com/services&amp;gt;"]
Output Format: "Text"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To present the information clearly, configure the &lt;strong&gt;Parse Data&lt;/strong&gt; component with this template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Template: 
"""
Policy Information:
------------------
{policy_title}

Details:
{policy_details}

Additional Information:
{additional_info}
------------------
"""
&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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836qi1l04bf08lszb24n819" 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%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836qi1l04bf08lszb24n819" title="image.png" alt="image.png" width="800" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The connections here create a flow of information from user query to expert response. Connect your &lt;strong&gt;Text Input&lt;/strong&gt; to the &lt;strong&gt;JWT Validator and&lt;/strong&gt; then the &lt;strong&gt;Chat Input&lt;/strong&gt; to the &lt;strong&gt;If-Else Router&lt;/strong&gt; ’s &lt;strong&gt;True Input&lt;/strong&gt;. The &lt;strong&gt;JWT Validator&lt;/strong&gt; feeds into the Permission Check, which determines if the user can access the information.&lt;/p&gt;

&lt;p&gt;When testing this flow, try asking natural questions like “What’s the baggage allowance for international flights?” or “Tell me about your pet travel policy.” The Expert Agent will provide detailed, accurate responses while respecting security boundaries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flight Booking Flow
&lt;/h3&gt;

&lt;p&gt;Let’s build our most secure flow - the booking system. Looking at the components in the screenshot, we’ll need both standard security components and some specialized ones for handling bookings.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add these components to your canvas:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text Input &amp;amp; Chat Input (for token and booking requests)&lt;/li&gt;
&lt;li&gt;JWT Validator (for authentication)&lt;/li&gt;
&lt;li&gt;Data Protection (for securing resources)&lt;/li&gt;
&lt;li&gt;Permission Check (for booking authorization)&lt;/li&gt;
&lt;li&gt;If-Else Router (for routing based on permissions)&lt;/li&gt;
&lt;li&gt;API Request (for making bookings)&lt;/li&gt;
&lt;li&gt;OpenAI &amp;amp; Data to Message (for handling responses)&lt;/li&gt;
&lt;li&gt;Filter Data (for processing results)&lt;/li&gt;
&lt;li&gt;Astro Assistant Agent (for managing booking interactions)&lt;/li&gt;
&lt;li&gt;Chat Output (for user responses)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Let’s configure the components:&lt;br&gt;
JWT Validator settings:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  JWKS URL: "&amp;lt;https://test.com/.well-known/jwks.json&amp;gt;"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Data Protection and Permission Check settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  PDP URL: "&amp;lt;http://localhost:7766&amp;gt;"
  API Key: "your-permit-api-key"
  Resource Type/Resource: "booking"
  Action: "create"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;API Request settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  URL: "&amp;lt;https://api.flights.com/v1/bookings&amp;gt;"
  Method: "POST"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OpenAI settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Model Name: gpt-4o-mini
  Temperature: 0.15
  Stream: off
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If-Else Router settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Match Text: "True"
  Operator: "equals"
  Case Sensitive: off
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assistant Agent settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Model: gpt-4o-mini
  Agent Instructions: "You are a booking assistant that helps  process flight booking requests..."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Looking at the screenshot, connect the components this way:

&lt;ul&gt;
&lt;li&gt;Text Input connects to the JWT Validator&lt;/li&gt;
&lt;li&gt;Chat Input splits to OpenAI and Permission Check&lt;/li&gt;
&lt;li&gt;JWT Validator links to both Permission Check and Data Protection&lt;/li&gt;
&lt;li&gt;Permission Check’s “Allowed” output goes to the API Request&lt;/li&gt;
&lt;li&gt;Data Protection connects to Filter Data&lt;/li&gt;
&lt;li&gt;API Request feeds into the Assistant Agent&lt;/li&gt;
&lt;li&gt;Everything routes to appropriate Chat Outputs
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fus-west-2.graphassets.com%2FAuGrs0mztRH6ldTYKJkSAz%2Fcm836r202048l07n39q031t6l" title="image.png" alt="image.png" width="800" height="553"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When testing, try some booking requests and watch how each security layer validates the request before allowing the booking to proceed.&lt;/p&gt;

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

&lt;p&gt;We’ve built a secure flight booking system that demonstrates all four Langflow security perimeters. The &lt;strong&gt;JWT Validator&lt;/strong&gt; handles &lt;strong&gt;Prompt Filtering&lt;/strong&gt; by validating JWTs and extracting user IDs, ensuring only authorized inputs like flight searches or booking requests move forward. &lt;strong&gt;RAG Protection&lt;/strong&gt; is powered by the &lt;strong&gt;Data Protection&lt;/strong&gt; component, which restricts retrieved data to allowed resource IDs, keeping sensitive flight and booking details safe. The &lt;strong&gt;Permissions Check&lt;/strong&gt; component enforces &lt;strong&gt;Secure External Access&lt;/strong&gt; , checking if users can perform actions like accessing APIs for bookings, with distinct outputs for allowed or denied requests. Finally, &lt;strong&gt;Response Enforcement&lt;/strong&gt; is achieved through the combined efforts of &lt;strong&gt;Permissions Check&lt;/strong&gt; and &lt;strong&gt;Data Protection&lt;/strong&gt; , shaping what users see, such as tailored flight lists or policy info based on their permissions and authorized data.&lt;/p&gt;

&lt;p&gt;By integrating Langflow’s AI prowess with &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;’s access control, we’ve created a system that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Protects sensitive travel data&lt;/li&gt;
&lt;li&gt;Enforces appropriate access levels&lt;/li&gt;
&lt;li&gt;Maintains security across all operations&lt;/li&gt;
&lt;li&gt;Provides a smooth user experience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Security in AI applications goes beyond data protection—it’s about building trust while delivering what users need. As you craft your own projects, consider adapting these perimeters to your goals.&lt;/p&gt;

&lt;p&gt;Happy building! Got questions? Need help? Join our &lt;a href="https://io.permit.io/permitslack" rel="noopener noreferrer"&gt;&lt;strong&gt;Slack community&lt;/strong&gt;&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>DeepSeek Completely Changed How We Use Google Zanzibar</title>
      <dc:creator>Gabriel L. Manor</dc:creator>
      <pubDate>Thu, 06 Mar 2025 11:00:00 +0000</pubDate>
      <link>https://dev.to/permit_io/deepseek-completely-changed-how-we-use-google-zanzibar-219l</link>
      <guid>https://dev.to/permit_io/deepseek-completely-changed-how-we-use-google-zanzibar-219l</guid>
      <description>&lt;p&gt;&lt;a href="https://www.permit.io/blog/what-is-google-zanzibar" rel="noopener noreferrer"&gt;Google Zanzibar&lt;/a&gt; is one of the most well-known &lt;a href="https://www.permit.io/blog/what-is-fine-grained-authorization-fga" rel="noopener noreferrer"&gt;fine-grained authorization&lt;/a&gt; systems, enabling large-scale applications to define and enforce access control through Policy-as-Graph structures. While powerful, Zanzibar requires a lot of data to sync, yet its implementations lack built-in automation tools. This requires manual management of &lt;a href="https://www.permit.io/blog/what-is-rebac" rel="noopener noreferrer"&gt;relationship-based access control (ReBAC) tuples&lt;/a&gt;, a process that can easily become tedious and error-prone.&lt;/p&gt;

&lt;p&gt;With the rise in popularity and functionality of AI agents, we decided to test an experimental approach: using DeepSeek R1 to &lt;strong&gt;automate Zanzibar tuple generation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Combining Permit.io and DeepSeek R1, we attempted to streamline Zanzibar management by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using Permit.io as a user-friendly policy management layer.&lt;/li&gt;
&lt;li&gt;Using DeepSeek R1 to generate ReBAC tuples from natural language descriptions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While not yet production-ready, we think the idea of using AI agents to assist humans in automating access control might not be too far away - and we’d love to hear your feedback on how this model can be further refined and optimized for real-world production deployments.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What Google Zanzibar is and how it works&lt;/li&gt;
&lt;li&gt;The challenges of maintaining a Policy-as-Graph system&lt;/li&gt;
&lt;li&gt;How Permit.io and DeepSeek R1 can work together&lt;/li&gt;
&lt;li&gt;A step-by-step guide to building an AI-assisted Zanzibar deployment&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What is Google Zanzibar?
&lt;/h2&gt;

&lt;p&gt;Google Zanzibar is an authorization system developed to manage fine-grained access control across Google's services (e.g., Drive, YouTube, Maps). Instead of using traditional role-based access control (RBAC) or access control lists (ACLs), Zanzibar defines permissions as &lt;strong&gt;relationships&lt;/strong&gt; in a &lt;strong&gt;graph&lt;/strong&gt; , allowing for hierarchical and highly granular access control. By handling millions of authorization requests per second, Zanzibar ensures that even at massive scales, access control remains fast, consistent, and secure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Policy-as-Graph?
&lt;/h3&gt;

&lt;p&gt;Policy-as-Graph structures define entities (users, groups, resources) as nodes and relationships as edges. Instead of listing static permissions, Zanzibar allows access control decisions to be traversed dynamically through relationships.&lt;/p&gt;

&lt;p&gt;For example, if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Alice owns a folder&lt;/li&gt;
&lt;li&gt;
That folder contains multiple files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then Alice automatically has access to all the files without explicitly assigning permissions to each one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Relationships?
&lt;/h3&gt;

&lt;p&gt;Google Zanzibar’s Policy-as-Graph enables the creation of Relationship-Based Access Control (ReBAC) policies. ReBAC is an authorization model in which access permissions are determined by the relationships between users and resources rather than static roles or attributes.&lt;/p&gt;

&lt;p&gt;As we’ve seen in the previous section, instead of explicitly granting permissions, ReBAC derives access from relationships. This approach is ideal for hierarchical, social, and organization-based systems where permissions naturally follow structured relationships.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Are Relationship Tuples?
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;relationship tuple&lt;/strong&gt; is a structured way to represent a &lt;strong&gt;user-resource relationship&lt;/strong&gt; in a ReBAC system. Each tuple typically follows this format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource_type:resource_id#relation@subject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, the tuple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document:report123#editor@alice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Means that &lt;code&gt;Alice&lt;/code&gt; has an &lt;code&gt;editor&lt;/code&gt; relationship with the document &lt;code&gt;report123&lt;/code&gt;, granting her access based on the policy. Tuples act as building blocks of ReBAC policies, allowing the system to determine who can access what based on predefined relationships.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge of Maintaining Policy-as-Graph
&lt;/h2&gt;

&lt;p&gt;Understanding ReBAC policies and tuples, we need to discuss the limitations of Zanzibar’s architecture. While extremely powerful, it’s quite difficult to manage at scale.&lt;/p&gt;

&lt;p&gt;As you probably guessed, the biggest pain point in this endeavor is manually defining and updating ReBAC tuples.&lt;/p&gt;

&lt;p&gt;For instance, if an organization changes its team structure, it must manually update thousands of tuples to reflect new permissions. This is quite time-consuming, error-prone, and difficult to audit and maintain. Without automation, managing Zanzibar at scale quickly becomes unmanageable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Management Layer + AI Tuple Generator
&lt;/h2&gt;

&lt;p&gt;To simplify Zanzibar deployments, we propose a hybrid approach in which:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Permit.io&lt;/strong&gt; : Provides a policy management layer to simplify Zanzibar-based authorization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DeepSeek R1&lt;/strong&gt; : An AI-powered ReBAC tuple generator capable of translating natural language into structured authorization rules.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  How Does This Help?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automates tuple generation:&lt;/strong&gt; Instead of manually defining relationships, DeepSeek R1 converts English sentences into structured ReBAC tuples.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduces human effort:&lt;/strong&gt; Developers focus on defining access rules instead of manually writing JSON policies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improves accuracy:&lt;/strong&gt; AI-generated policies reduce the risk of manual errors and inconsistencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Is This Production-Ready?
&lt;/h3&gt;

&lt;p&gt;No. AI-generated data extraction for access control still requires human supervision to ensure correctness and security. However, we think this approach is a promising step toward automated fine-grained authorization management.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are We Going to Build?
&lt;/h2&gt;

&lt;p&gt;To demonstrate this approach, we’ll build a Zanzibar-powered authorization system where:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A user inputs a natural-language relationship rule (e.g., &lt;em&gt;"The enterprise sales team manages all enterprise-level accounts."&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;A Node.js script sends this text to DeepSeek R1, which processes it into a structured ReBAC tuple.&lt;/li&gt;
&lt;li&gt;Permit.io syncs the tuple with its access control graph, making it immediately enforceable.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s dive into the tutorial!&lt;/p&gt;

&lt;h2&gt;
  
  
  Project set-up
&lt;/h2&gt;

&lt;p&gt;To get started, let’s create &lt;strong&gt;a new Node.js project&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I assume you have Node.js installed and can understand JavaScript (don’t worry; the basics are all you need).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a directory where you want to house the project and open it in a terminal.&lt;/li&gt;
&lt;li&gt;Use the following code to create a Node.js app:
&lt;/li&gt;
&lt;/ul&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;Due to DeepSeek’s popularity and increased demand, they’ve had to close their API (At least for now), which is only open for paid and existing customers.&lt;/p&gt;

&lt;p&gt;For this tutorial, we’ll use the DepSeek model from &lt;a href="https://studio.nebius.ai/" rel="noopener noreferrer"&gt;Nebius AI Studio&lt;/a&gt; using OpenAI SDK. It’s the same full-weight DeepSeek model but hosted on EU servers. Nebius AI Studio is a full-stack AI inference platform that provides seamless access to multiple open-source models for anyone to use.&lt;/p&gt;

&lt;p&gt;The OpenAI SDK makes using DeepSeek easy due to its compatibility and zero configuration requirements. We just need to change the &lt;code&gt;baseURL&lt;/code&gt; and our API key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;These are the packages that we’ll be using:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nodemon&lt;/code&gt;, &lt;code&gt;dotenv&lt;/code&gt;, &lt;code&gt;cors&lt;/code&gt;, &lt;code&gt;express&lt;/code&gt;, &lt;code&gt;openai&lt;/code&gt;, and &lt;code&gt;permitio&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Install them using the following command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Now we’re done with the installations, we need to get our API keys.&lt;/p&gt;

&lt;p&gt;We need two API keys: our &lt;strong&gt;Permit API key&lt;/strong&gt; and our &lt;strong&gt;Nebius API key&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get your Permit API key from your Permit.io dashboard. If you don’t have an account yet, you can create one for free &lt;a href="http://app.permit.io/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Get your Nebius API key from the &lt;a href="https://studio.nebius.ai/" rel="noopener noreferrer"&gt;Nebius AI Studio&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Put these API keys into your &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the ReBAC Schema
&lt;/h2&gt;

&lt;p&gt;As mentioned previously, we are going to set up Relationship-Based Access Control (ReBAC) policies in the Permit.io dashboard.&lt;/p&gt;

&lt;p&gt;In your Permit dashboard, click on the “Policy” tab on the left panel and add in your resources by clicking “Add Resource”.&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%2Fmedia.graphassets.com%2FwiUB1MA2QqKxWVansFJd" 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%2Fmedia.graphassets.com%2FwiUB1MA2QqKxWVansFJd" title="image.png" alt="image.png" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Suppose we are building this DeepSeek R1 relationship tuple generator for a product organization. This organization has different teams and accounts, and teams can only manage the accounts associated with them.&lt;/p&gt;

&lt;p&gt;We’ll create two resources: &lt;code&gt;team&lt;/code&gt; and &lt;code&gt;account&lt;/code&gt;. The &lt;code&gt;team&lt;/code&gt; resource will have a &lt;code&gt;manages&lt;/code&gt; relationship with the &lt;code&gt;account&lt;/code&gt; resource.&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%2Fmedia.graphassets.com%2F8Htz4z3TyyBC1gbRMrzg" 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%2Fmedia.graphassets.com%2F8Htz4z3TyyBC1gbRMrzg" title="image.png" alt="image.png" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;account&lt;/code&gt; resource will have a &lt;code&gt;level&lt;/code&gt; attribute:&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%2Fmedia.graphassets.com%2FwQN77w4cTE6HM4kvXMIo" 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%2Fmedia.graphassets.com%2FwQN77w4cTE6HM4kvXMIo" title="image.png" alt="image.png" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating your resources, click on the “Directory” tab on the left panel and add your resource instances.&lt;/p&gt;

&lt;p&gt;In our case, we want to create resource instances of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;team&lt;/code&gt; will represent the users that handle enterprise sales&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;account&lt;/code&gt; will represent the enterprise account where proceeds from enterprise sales are deposited&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add the resource instances: &lt;code&gt;team:enterprise_sales&lt;/code&gt; and &lt;code&gt;account:enterprise&lt;/code&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%2Fmedia.graphassets.com%2FCmFrMh6jTWayhKH9XF3H" 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%2Fmedia.graphassets.com%2FCmFrMh6jTWayhKH9XF3H" title="image.png" alt="image.png" width="800" height="371"&gt;&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%2Fmedia.graphassets.com%2FCPe4CjXyQyGuBtF7Qyco" 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%2Fmedia.graphassets.com%2FCPe4CjXyQyGuBtF7Qyco" title="image.png" alt="image.png" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With all of the different elements that comprise our relationship-based policy, in the next section, we’re going to build out the relationship tuple generator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Node.js + DeepSeek Parser
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Configuring our Node.js application
&lt;/h3&gt;

&lt;p&gt;Create an &lt;code&gt;index.js&lt;/code&gt; file and add the following configuration:&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;Permit&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;permitio&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;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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;OpenAI&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;openai&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;cors&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;cors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;dotenv&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;permit&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;Permit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;pdp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;http://localhost:7766&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;token&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;PERMIT_API_KEY_PROD&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;openai&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;OpenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;https://api.studio.nebius.ai/v1/&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&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;MY_OWN_NEBIUS_API_KEY&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;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="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&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="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="nf"&gt;cors&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;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 running on port &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;In the code above, we’re setting up the configurations of our app, including OpenAI and Permit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt engineering
&lt;/h3&gt;

&lt;p&gt;In this section, we’ll create two functions for generating a prompt and parsing the AI response into an object.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;index.js&lt;/code&gt; file, add the following 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;function&lt;/span&gt; &lt;span class="nf"&gt;generatePrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userInput&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="s2"&gt;`Parse the following sentence into a REBAC relationship tuple for use in Permit.io:

      Sentence: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"

      Identify the following:
      - **Subject:** Include type and instance if available (e.g., "team:enterprise_sales").
      - **Relation:** Extract the main action verb (e.g., "manages").
      - **Object:** Include type and instance if available (e.g., "account:enterprise").
  - **Attributes:** Extract any metadata or qualifiers relevant to the object (e.g., {"level": "enterprise"}). If no attributes exist, return an empty object.

  Return the result in this JSON format:
  &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subject&lt;/span&gt;&lt;span class="dl"&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;type:id&lt;/span&gt;&lt;span class="dl"&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;relation&lt;/span&gt;&lt;span class="dl"&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;verb&lt;/span&gt;&lt;span class="dl"&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;object&lt;/span&gt;&lt;span class="dl"&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;type:id&lt;/span&gt;&lt;span class="dl"&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;attributes&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;key&lt;/span&gt;&lt;span class="dl"&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;value&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="err"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;`

  Ensure that the response remains consistent in format, with exact JSON keys as shown, even if some fields are empty.`&lt;/span&gt;&lt;span class="p"&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;transformJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonString&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;jsonMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/``&lt;/span&gt;&lt;span class="err"&gt;`
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endraw&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="nf"&gt;n&lt;/span&gt;&lt;span class="p"&gt;({[&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;?})&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="s2"&gt;```/);
    const extractedJson = jsonMatch ? jsonMatch[1] : null;
    try {
      const data = JSON.parse(extractedJson);

      // Return the JSON string with correct formatting
      return data;
    } catch (error) {
      console.error("Invalid JSON input:", error);
      return null;
    }
  }

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;generatePrompt&lt;/code&gt; function returns the prompt we will use to prompt the DeepSeek R1 model. We are using a function to get the response to ensure a fairly consistent result for the same input.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;transformJson&lt;/code&gt; function parses the AI response for the generated relationship tuple and returns it as an object.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating ReBAC Relationships
&lt;/h2&gt;

&lt;p&gt;In this section, we will create a relationship tuple in Permit using the Permit SDK and the object returned by &lt;code&gt;transformJson&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Use the following code to create a ReBAC relationship tuple in Permit:&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="cm"&gt;/* example structure:

"rawRebacTuple": {
     "subject": "team:enterprise_sales",
   "relation": "manages",
   "object": "account:enterprise",
   "attributes": {
           "level": "enterprise"
    }
}
*/&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&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;permit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;relationshipTuples&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;subject&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="nx"&gt;rebacTuple&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;subject&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="na"&gt;relation&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="nx"&gt;rebacTuple&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;relation&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="na"&gt;object&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="nx"&gt;rebacTuple&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;object&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;Our final &lt;code&gt;index.js&lt;/code&gt; should look like this:&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;Permit&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;permitio&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;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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;OpenAI&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;openai&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;cors&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;cors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;dotenv&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;permit&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;Permit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;pdp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;http://localhost:7766&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;token&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;PERMIT_API_KEY_PROD&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;openai&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;OpenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;https://api.studio.nebius.ai/v1/&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&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;MY_OWN_NEBIUS_API_KEY&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;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="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&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="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="nf"&gt;cors&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;/generate-rebac&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&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;function&lt;/span&gt; &lt;span class="nf"&gt;generatePrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userInput&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="s2"&gt;`Parse the following sentence into a REBAC relationship tuple for use in Permit.io:

      Sentence: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"

      Identify the following:
      - **Subject:** Include type and instance if available (e.g., "team:enterprise_sales").
      - **Relation:** Extract the main action verb (e.g., "manages").
      - **Object:** Include type and instance if available (e.g., "account:enterprise").
  - **Attributes:** Extract any metadata or qualifiers relevant to the object (e.g., {"level": "enterprise"}). If no attributes exist, return an empty object.

  Return the result in this JSON format:
  &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subject&lt;/span&gt;&lt;span class="dl"&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;type:id&lt;/span&gt;&lt;span class="dl"&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;relation&lt;/span&gt;&lt;span class="dl"&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;verb&lt;/span&gt;&lt;span class="dl"&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;object&lt;/span&gt;&lt;span class="dl"&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;type:id&lt;/span&gt;&lt;span class="dl"&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;attributes&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;key&lt;/span&gt;&lt;span class="dl"&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;value&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="err"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;`

  Ensure that the response remains consistent in format, with exact JSON keys as shown, even if some fields are empty.`&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;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generatePrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&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;transformJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonString&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;jsonMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/``&lt;/span&gt;&lt;span class="err"&gt;`
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endraw&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="nf"&gt;n&lt;/span&gt;&lt;span class="p"&gt;({[&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;?})&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="s2"&gt;```/);
    const extractedJson = jsonMatch ? jsonMatch[1] : null;
    try {
      const data = JSON.parse(extractedJson);

      // Return the JSON string with correct formatting
      return data;
    } catch (error) {
      console.error("Invalid JSON input:", error);
      return null;
    }
  }

  try {
    const response = await openai.chat.completions.create({
      temperature: 0.6,
      messages: [
        {
          role: "system",
          content: prompt,
        },
      ],
      model: "deepseek-ai/DeepSeek-R1",
    });

    const responseText = response.choices[0].message.content;
    const rawRebacTuple = transformJson(responseText);

    const result = await permit.api.relationshipTuples.create({
      subject: `&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rebacTuple&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`,
      relation: `&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rebacTuple&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`,
      object: `&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rebacTuple&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`,
    });

    console.log(result);
    return res.status(200).json({
      success: true,
      responseText,
      rawRebacTuple,
      rebacTuple,
      relationTupleCreated: true,
    });
  } catch (error) {
    console.error(error);
    return res.status(500).json({
      success: false,
      error: error.message,
      relationTupleCreated: false,
    });
  }
});

app.listen(PORT, () =&amp;gt; {
  console.log(`&lt;/span&gt;&lt;span class="nx"&gt;Server&lt;/span&gt; &lt;span class="nx"&gt;running&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="nx"&gt;$&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing and Validation
&lt;/h2&gt;

&lt;p&gt;Now it’s time to test our application. I’ll use the following text: &lt;code&gt;"The enterprise sales team manages all enterprise-level accounts."&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Since our interface is a Node.js application, we’ll use Postman to test our integration.&lt;/p&gt;

&lt;p&gt;Go to the Postman website or use the desktop application (if you have it installed). Add the URL and the prompt (mark it as raw), and send the request.&lt;/p&gt;

&lt;p&gt;You should get something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FVN4qnJMxRIW93ffZ0dTT" 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%2Fmedia.graphassets.com%2FVN4qnJMxRIW93ffZ0dTT" title="image.png" alt="image.png" width="800" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you check the &lt;code&gt;team:enterprise_sales&lt;/code&gt; and &lt;code&gt;account:enterprise&lt;/code&gt; resources in your dashboard, you’ll see that the relationship has been added automatically.&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%2Fmedia.graphassets.com%2FLwg6WnEQOSqKyWfMIMuQ" 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%2Fmedia.graphassets.com%2FLwg6WnEQOSqKyWfMIMuQ" title="image.png" alt="image.png" width="800" height="371"&gt;&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%2Fmedia.graphassets.com%2F7uBbd1wKQfecRweb1QkG" 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%2Fmedia.graphassets.com%2F7uBbd1wKQfecRweb1QkG" title="image.png" alt="image.png" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-world usage
&lt;/h2&gt;

&lt;p&gt;To truly function in a real-world environment, an AI-enhanced access control system must integrate with several additional event-driven workflows, automated access request systems, and AI-driven permission management tools. Below are key integrations that would be required for such a system to operate efficiently in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Event-driven system for syncing relationships
&lt;/h3&gt;

&lt;p&gt;Real-world applications require real-time updates to keep access control policies synchronized with changes in user activity, resource creation, and system events. An event-driven architecture ensures that access control remains up to date without manual intervention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Would it Work?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An event listener detects an event (e.g., a new transaction, resource creation, or user action) when it occurs.&lt;/li&gt;
&lt;li&gt;The system interprets the event and determines whether it requires an update in access control policies.&lt;/li&gt;
&lt;li&gt;A Graph API call is made to Permit.io (or another access control platform) to update relationships dynamically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This type of integration eliminates manual updates, ensuring that access control scales efficiently in dynamic environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI-Powered Permission Bots for Automated Access Requests
&lt;/h3&gt;

&lt;p&gt;A Permission Bot would act as an intelligent assistant that automates access requests and approvals, reducing dependency on IT teams while maintaining security policies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Would it Work?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A user requests access&lt;/strong&gt; using a conversational interface (e.g., Slack, Teams, or a chatbot).

&lt;ul&gt;
&lt;li&gt;Example: &lt;em&gt;“Can I get editor access to the sales dashboard?”&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Natural Language Processing (NLP)&lt;/strong&gt; interprets the request and verifies the user's current permissions.&lt;/li&gt;
&lt;li&gt;If the user is &lt;strong&gt;eligible&lt;/strong&gt; , the bot &lt;strong&gt;grants access automatically&lt;/strong&gt; through the access control system.&lt;/li&gt;
&lt;li&gt;If approval is required, the bot &lt;strong&gt;notifies an admin&lt;/strong&gt; , providing them with a simple way to approve or deny the request.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;AI Agents for Proactive Permission Management&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Rather than waiting for users to request access, AI Agents can anticipate permissions needed and proactively request them on the user's behalf.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Would it Work?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The AI agent monitors user activity and detects when a permission issue is likely to occur.&lt;/li&gt;
&lt;li&gt;If a user attempts to access a restricted resource, the AI automatically initiates a permission request.&lt;/li&gt;
&lt;li&gt;The AI agent can also predict access needs based on behavior, preemptively requesting access before users even realize they need it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario 1: Proactive Permission Requests&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alice tries to access a restricted bug report but lacks the necessary permissions.&lt;/li&gt;
&lt;li&gt;Instead of Alice manually requesting access, the AI agent immediately notifies the admin:

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;“User Alice needs read access to a bug report. Should I grant permission?”.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Scenario 2: Predictive Access Based on Behavior&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A content writer is working on an article and needs access to supporting research files.&lt;/li&gt;
&lt;li&gt;The AI agent detects this activity and automatically grants temporary access to the relevant documents.&lt;/li&gt;
&lt;li&gt;Once the task is completed, access is revoked, ensuring the principle of least privilege compliance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Future of AI-Driven Access Control
&lt;/h2&gt;

&lt;p&gt;This “experiment” demonstrates how AI can assist in automating fine-grained authorization within Google Zanzibar by leveraging DeepSeek R1 and Permit.io. By using natural language processing to generate ReBAC tuples, we eliminate much of the manual overhead typically associated with managing relationship-based access control.&lt;/p&gt;

&lt;p&gt;However, for this approach to be real-world ready, it requires further integrations with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Event-driven systems to ensure real-time synchronization of permissions.&lt;/li&gt;
&lt;li&gt;AI-powered permission bots to automate access requests and approvals.&lt;/li&gt;
&lt;li&gt;Proactive AI agents to predict and preemptively manage permissions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While this solution is not yet production-ready, it signals a shift towards AI-assisted access control, reducing complexity while maintaining security and compliance. As organizations scale, automated, intelligent permission management will become essential to handle the growing complexity of fine-grained authorization at scale.&lt;/p&gt;

&lt;p&gt;We’d love to hear your thoughts on how you would refine this model. What other AI-driven enhancements would make authorization even more seamless?&lt;/p&gt;

&lt;p&gt;Let us know your thoughts in our &lt;a href="https://io.permit.io/permitslack" rel="noopener noreferrer"&gt;&lt;strong&gt;Slack community&lt;/strong&gt;&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>deepseek</category>
      <category>ai</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Building AI Applications with Enterprise-Grade Security Using RAG and FGA</title>
      <dc:creator>Gabriel L. Manor</dc:creator>
      <pubDate>Fri, 08 Nov 2024 07:30:00 +0000</pubDate>
      <link>https://dev.to/permit_io/building-ai-applications-with-enterprise-grade-security-using-rag-and-fga-2g39</link>
      <guid>https://dev.to/permit_io/building-ai-applications-with-enterprise-grade-security-using-rag-and-fga-2g39</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This post is written by &lt;a href="https://www.linkedin.com/in/bpietrucha/?originalSubdomain=pl" rel="noopener noreferrer"&gt;Bartosz Pietrucha&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Building enterprise-grade LLM applications is a necessity in today's business environment. While the accessibility of models and APIs is improving, one significant challenge remains: ensuring their security and effectively managing their permissions.&lt;/p&gt;

&lt;p&gt;To address this, &lt;a href="https://www.permit.io/blog/what-is-fine-grained-authorization-fga" rel="noopener noreferrer"&gt;Fine-Grained Authorization (FGA)&lt;/a&gt; and Retrieval Augmented Generation (RAG) are effective strategies for building secure, context-aware AI applications that maintain strict access control. In this article, we’ll explore how FGA and RAG can be applied in a healthcare setting while safeguarding sensitive data.&lt;/p&gt;

&lt;p&gt;We’ll do this by guiding you through implementing a &lt;a href="https://www.permit.io/blog/what-is-rebac" rel="noopener noreferrer"&gt;Relationship-Based Access Control (ReBAC)&lt;/a&gt;authorization system that supports real-time updates with three tools: &lt;a href="https://www.datastax.com/products/datastax-astra" rel="noopener noreferrer"&gt;AstraDB&lt;/a&gt;, &lt;a href="https://www.langflow.org/" rel="noopener noreferrer"&gt;Langflow&lt;/a&gt;, and &lt;a href="http://permit.io/" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Case Example: Healthcare Applications
&lt;/h2&gt;

&lt;p&gt;To better understand the complexity of authorization in LLM applications, and the solutions offered by FGA and RAG, we can look at the &lt;a href="https://www.permit.io/blog/authorization-in-healthcare" rel="noopener noreferrer"&gt;digital healthcare space&lt;/a&gt; - as it presents a perfect example where both AI capabilities and stringent security are essential. Healthcare providers increasingly want to leverage LLMs to streamline workflows, improve decision-making, and provide better patient care. Doctors and patients alike want easy access to medical records through intuitive AI interfaces such as chatbots.&lt;/p&gt;

&lt;p&gt;However, medical data is highly sensitive and should be carefully regulated. While LLMs can provide intelligent insights, we must ensure that they only access and reveal information that users are authorized to see. Doctors, for example, should only see diagnoses from their assigned medical centers, and patients should only be able to access their own records.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Through Fine-Grained Authorization
&lt;/h2&gt;

&lt;p&gt;Proceeding with the digital healthcare example, let’s look at an example of a medical application.&lt;/p&gt;

&lt;p&gt;This application is comprised of several resources, a couple of roles, and a few relationships between these entities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Resource Types&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Medical Centers (e.g., London, Warsaw)&lt;/li&gt;
&lt;li&gt;Visits (e.g., Morning Visit, Afternoon Visit)&lt;/li&gt;
&lt;li&gt;Diagnoses (e.g., Diabetes, Headache, Virus)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Roles&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Doctors (e.g., Dr Bartosz)&lt;/li&gt;
&lt;li&gt;Patients (e.g., Gabriel, Olga)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Relationships&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Doctors are assigned to Medical Centers&lt;/li&gt;
&lt;li&gt;Visits belong to Medical Centers&lt;/li&gt;
&lt;li&gt;Diagnoses are part of Visits&lt;/li&gt;
&lt;li&gt;Patients are connected to their Visits&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you can see, the hierarchal relationships of our resources mean implementing traditional role-based access control, where permissions are assigned directly, will be insufficient.&lt;/p&gt;

&lt;p&gt;The complexity of this applications authorization will require us to use more fine-grained authorization (FGA) solutions - in this case, Relationship-Based Access Control (ReBAC).&lt;/p&gt;

&lt;p&gt;ReBAC, an authorization model inspired by Google's Zanzibar paper, derives permissions from relationships between entities in the system - unlike traditional &lt;a href="https://www.permit.io/blog/what-is-rbac" rel="noopener noreferrer"&gt;role-based access control (RBAC)&lt;/a&gt;, where permissions are assigned directly.&lt;/p&gt;

&lt;p&gt;The power of ReBAC lies in how permissions are derived through these relationships. Let’s look at a visual representation of our example:&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%2Fmedia.graphassets.com%2F9YMuWp9uRW60crN36pOs" 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%2Fmedia.graphassets.com%2F9YMuWp9uRW60crN36pOs" title="image (69).png" alt="image (69).png" width="800" height="981"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above example, Dr Bartosz has access to the Virus diagnosis not because of a &lt;strong&gt;directly granted permission&lt;/strong&gt; but rather because he is assigned to Warsaw Medical Center, which contains the Afternoon Visit, which contains the diagnosis. Thus, the relationships between these resources form a chain that allows us to derive access permissions.&lt;/p&gt;

&lt;p&gt;There are clear benefits to using this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It models real-world organizational structures naturally&lt;/li&gt;
&lt;li&gt;Permissions adapt automatically as relationships change&lt;/li&gt;
&lt;li&gt;It provides fine-grained control while remaining scalable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the challenge doesn’t end there - as we are building a system that needs to work with LLMs, it needs to have the ability to evaluate these relationship chains in real-time. In the next section, we will learn how to create an implementation that allows that.&lt;/p&gt;

&lt;p&gt;Before we continue, let's quickly review the authorization rules we want to ensure are in place:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Only doctors with valid relationships to a medical center can see its visits&lt;/li&gt;
&lt;li&gt;Access to diagnoses is automatically derived from these relationships&lt;/li&gt;
&lt;li&gt;Changes in relationships (e.g., doctor reassignment) immediately affect access rights&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These requirements can be achieved through the use of Retrieval Augmented Generation (RAG).&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieval Augmented Generation (RAG)
&lt;/h2&gt;

&lt;p&gt;RAG (Retrieval Augmented Generation) is a technique that enhances LLM outputs by combining two key steps: first, retrieving relevant information from a knowledge base, and then using that information to augment the LLM's context for more accurate generation. While RAG can work with traditional databases or document stores, vector databases are particularly powerful for this purpose because they can perform semantic similarity search, finding conceptually related information even when exact keywords don't match.&lt;/p&gt;

&lt;p&gt;In practice, this means that when a user asks about "heart problems," the system can retrieve relevant documents about "cardiac issues" or "cardiovascular disease," making the LLM's responses both more accurate and comprehensive. The "generation" part then involves the LLM synthesizing this retrieved context with its pre-trained knowledge to produce relevant, factual responses that are grounded in your specific data.&lt;/p&gt;

&lt;p&gt;For our implementation, we will use AstraDB as our vector database. AstraDB offers the following benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It efficiently stores and searches through embeddings&lt;/li&gt;
&lt;li&gt;It scales well with growing data&lt;/li&gt;
&lt;li&gt;It integrates well with LLM chains like Langflow (which we will cover later in the article)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To implement our RAG pipeline, we'll also use LangFlow, an open-source framework that makes building these systems intuitive through its visual interface. LangFlow systems can be developed with a Python environment running locally or in the cloud-hosted DataStax platform. In our case, we are choosing the second option by creating a serverless (vector) AstraDB database under: &lt;a href="https://astra.datastax.com" rel="noopener noreferrer"&gt;https://astra.datastax.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our implementation, authorization checks should happen at a crucial moment - after retrieving data from the vector database but &lt;strong&gt;before&lt;/strong&gt; providing it to the LLM as context. This way, we maintain search efficiency by first finding all relevant information and later filtering out unauthorized data before it ever reaches the LLM. The LLM can only use and reveal information the user is authorized to see.&lt;/p&gt;

&lt;p&gt;These security checks are implemented using &lt;a href="http://permit.io/" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;, which provides the infrastructure for evaluating complex relationship chains in real time. As your data grows and relationships become more complex, the system continues to ensure that each piece of information is only accessible to those with proper authorization.&lt;/p&gt;

&lt;p&gt;To get started with Permit, you can easily create a free account by visiting the website at &lt;a href="https://app.permit.io" rel="noopener noreferrer"&gt;https://app.permit.io&lt;/a&gt;. Once your free account is created, you'll have access to Permit's dashboard, where you can set up your authorization policies, manage users and roles, and integrate Permit into your applications. The free tier offers all the necessary features to create a digital healthcare example with relationship-based access control (ReBAC).&lt;/p&gt;

&lt;p&gt;Both LangFlow and Permit offer free accounts to start work, so you don’t have to pay anything to build such a system and see how it works for yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation Guide
&lt;/h2&gt;

&lt;p&gt;Before we dive into the implementation details, it's important to understand the tool we'll be using - Langflow. Built on top of LangChain, Langflow is an open-source framework that simplifies the creation of complex LLM applications through a visual interface. LangChain provides a robust foundation by offering standardized components for common LLM operations like text splitting, embedding generation, and chain-of-thought prompting. These components can be assembled into powerful pipelines that handle everything from data ingestion to response generation.&lt;/p&gt;

&lt;p&gt;What makes Langflow particularly valuable for our use case is its visual builder interface, which allows us to construct these pipelines by connecting components graphically - similar to how you might draw a flowchart. This visual approach makes it easier to understand and modify the flow of data through our application, from initial user input to the final authorized response. Additionally, Langflow's open-source nature means it's both free to use and can be extended with custom components, which is crucial for implementing our authorization checks.&lt;/p&gt;

&lt;p&gt;Our Langflow solution leverages two distinct yet interconnected flows to provide secure access to medical information:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Ingestion Flow
&lt;/h3&gt;

&lt;p&gt;The ingestion flow is responsible for loading diagnoses into AstraDB along with their respective embeddings. We use MistralAI to generate embeddings for each diagnosis, making it possible to perform semantic searches on the diagnosis data later. The key components involved in this flow are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Create List:&lt;/strong&gt; This component is used to create a list of diagnoses to ingest into AstraDB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MistralAI Embeddings&lt;/strong&gt; : This component generates embeddings for each diagnosis, which are stored in AstraDB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AstraDB&lt;/strong&gt; : AstraDB serves as the vector store where the diagnoses and their embeddings are stored for further retrieval.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FxkV2JyBSMW7psRBmWKiB" title="ingestion flow.png" alt="ingestion flow.png" width="800" height="781"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Chat Flow
&lt;/h3&gt;

&lt;p&gt;The chat flow is responsible for interacting with users and serving them the required diagnosis data. The images below are supposed to be read from left to right (the right side of the first one continues as the left side of the second one):&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%2Fmedia.graphassets.com%2FFiB1ChqKSiiWVnKfZelw" 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%2Fmedia.graphassets.com%2FFiB1ChqKSiiWVnKfZelw" title="flow1.png" alt="flow1.png" width="800" height="573"&gt;&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%2Fmedia.graphassets.com%2F4OegdIhSOegjqONOiFfp" 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%2Fmedia.graphassets.com%2F4OegdIhSOegjqONOiFfp" title="flow2.png" alt="flow2.png" width="800" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;There is an additional “&lt;/em&gt;_ &lt;strong&gt;Pip Install”&lt;/strong&gt; _ &lt;em&gt;component that is executed only once to install&lt;/em&gt; &lt;code&gt;permit&lt;/code&gt; &lt;em&gt;module. This is because we are implementing LangFlow on DataStax low-code platform. This step is equivalent to executing&lt;/em&gt; &lt;code&gt;pip install permit&lt;/code&gt; &lt;em&gt;locally.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The sequence of operations in the &lt;strong&gt;Chat Flow&lt;/strong&gt; is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;User Input&lt;/strong&gt; : The user initiates the interaction by typing a query.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Example: "&lt;em&gt;Do we have any patients with diabetes diagnosis?&lt;/em&gt;"&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Retrieve Diagnoses&lt;/strong&gt; : AstraDB is queried for relevant diagnoses based on the user's input.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Example search result (marked with &lt;strong&gt;1&lt;/strong&gt; on the flow image above):&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%2Fmedia.graphassets.com%2FXzQ77XXQBmEv3OD7yA74" 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%2Fmedia.graphassets.com%2FXzQ77XXQBmEv3OD7yA74" title="search result.png" alt="search result.png" width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Filter Data Based on Permissions&lt;/strong&gt; : Before sending the response to the next processing component, creating the context for LLM responding to the initial query, we filter the retrieved diagnoses using a custom &lt;code&gt;PermitFilter&lt;/code&gt; component to ensure the user has the right to view each diagnosis.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Example filtered results (marked with &lt;strong&gt;2&lt;/strong&gt; on the flow image above):&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%2Fmedia.graphassets.com%2F39z76nJYSrK84Z78Uqb4" 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%2Fmedia.graphassets.com%2F39z76nJYSrK84Z78Uqb4" title="filtering result.png" alt="filtering result.png" width="800" height="237"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Generate Response&lt;/strong&gt; : Once filtered, the permitted diagnoses are used as the context to generate a response for the user prompt using MistralAI.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Example prompt with context filtered with authorization step:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Seasonal Migraine
Flu virus with high fever

---
You are a doctor's assistant and help to retrieve information about patients' diagnoses.
Given the patients' diagnoses above, answer the question as best as possible.
The retrieved diagnoses may belong to multiple patients.

Question: list all the recent diagnoses

Answer: 

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  PermitFilter Component
&lt;/h3&gt;

&lt;p&gt;To run the &lt;code&gt;PermitFilter&lt;/code&gt; component, which plays a crucial role in our implementation, we need a running instance of Permit's Policy Decision Point (PDP). The PDP is responsible for evaluating policies and making decisions on whether a given action is permitted for a specific user and resource. By enforcing this permission check &lt;strong&gt;before&lt;/strong&gt; the context reaches the language model, we prevent the leakage of sensitive information and ensure the enforcement of access control policies.&lt;/p&gt;

&lt;h2&gt;
  
  
  See It In Action
&lt;/h2&gt;

&lt;p&gt;The complete implementation is available in our &lt;a href="https://github.com/permitio/permit-langflow" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;, where you'll find:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom LangFlow components&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt; integration code&lt;/li&gt;
&lt;li&gt;Detailed setup instructions&lt;/li&gt;
&lt;li&gt;Example queries and responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To start interacting with our AI assistant with authorization checks implemented we can simply start the LangFlow playground. In the example below, I am authenticated as &lt;code&gt;bartosz@health.app&lt;/code&gt; which means I have access to only &lt;code&gt;Afternoon-Visit&lt;/code&gt; and &lt;code&gt;Evening-Visit&lt;/code&gt; &lt;strong&gt;without&lt;/strong&gt; &lt;code&gt;Morning-Visit&lt;/code&gt; with Diabetes. This means that the LLM does not have the information about diabetes in its context.&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%2Fmedia.graphassets.com%2Fdw5hGdXZTZK9rpuwcWiG" 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%2Fmedia.graphassets.com%2Fdw5hGdXZTZK9rpuwcWiG" title="chat 1.png" alt="chat 1.png" width="776" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Securing access to sensitive healthcare data while leveraging LLM capabilities is both a priority and a challenge. By combining RAG and fine-grained authorization, we can build AI applications that are both intelligent and secure. The key benefits are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Context-aware responses through RAG&lt;/li&gt;
&lt;li&gt;Precise access control through ReBAC&lt;/li&gt;
&lt;li&gt;Natural modeling of organizational relationships&lt;/li&gt;
&lt;li&gt;Scalable security that adapts to changing relationships&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using tools like LangFlow and &lt;a href="http://permit.io/" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;, healthcare providers can implement relationship-based access control systems that respond dynamically to role and relationship changes, ensuring data is accessible only to authorized individuals. By integrating these solutions, healthcare organizations can effectively harness AI to improve patient care without compromising on security.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>python</category>
      <category>langchain</category>
    </item>
    <item>
      <title>How Custom GitHub Actions Enabled Us to Streamline Thousands of CI/CD Pipelines</title>
      <dc:creator>Gabriel L. Manor</dc:creator>
      <pubDate>Wed, 18 Sep 2024 18:50:00 +0000</pubDate>
      <link>https://dev.to/permit_io/how-custom-github-actions-enabled-us-to-streamline-thousands-of-cicd-pipelines-4pb0</link>
      <guid>https://dev.to/permit_io/how-custom-github-actions-enabled-us-to-streamline-thousands-of-cicd-pipelines-4pb0</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Since the early days of &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;, we have understood that building a secure and reliable Authorization service depends on how it integrates with the software development lifecycle. For this reason, besides providing our users with comprehensive authorization as a service product, we invest heavily in solving the challenge of automating CI/CD pipelines while maintaining consistent permission management across various environments.&lt;/p&gt;

&lt;p&gt;Our main goal with this holistic Authorization approach is to ensure these processes are not only seamless but also accessible and efficient for any development team.&lt;/p&gt;

&lt;p&gt;By integrating GitHub Actions with our APIs, we've created a model that supports development organizations at scale. This blog will walk you through how we leveraged these tools to automate environment management in our workspace, making it accessible to CI/CD pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Your Architecture for the CI/CD
&lt;/h2&gt;

&lt;p&gt;The first and (maybe the most important) step in creating a GitHub action is to examine your system’s architecture and understand the structure you aim to streamline in your CI/CD.&lt;/p&gt;

&lt;p&gt;When building &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;, we’ve built a system that allows developers to externalize their authorization to our hybrid cloud service. While the core of the product is, of course, letting the application code decide what users are allowed or not allowed to do, it was also built to support the common hierarchies of software development organizations.&lt;/p&gt;

&lt;p&gt;This is evident in Permit’s workspace hierarchy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Workspace&lt;/strong&gt; - comparable the the whole development organization. You can think of it as a GitHub organization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project&lt;/strong&gt; - a single application that your organization manages. It can be thought of as a code repository, but it is also flexible enough to support either multi- or mono-repo architectures. A workspace can include multiple projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment&lt;/strong&gt; - the silo of policies and configurations inside each project. The environment allows every organization to manage their CI/CD process in the same way they are managing it in their SDLC. It is comparable to a Git branch. Each project has a default of &lt;code&gt;Production&lt;/code&gt; and &lt;code&gt;Development&lt;/code&gt; branches, but a user can create as many as they want.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FWuRLINoaTuaSL4L1YlrF" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FWuRLINoaTuaSL4L1YlrF" title="api-model-f212cef178cf6984bd6009c26d0b62e8.svg" alt="api-model-f212cef178cf6984bd6009c26d0b62e8.svg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Advantages of a CI/CD Structure
&lt;/h3&gt;

&lt;p&gt;Understanding the structure of your CI/CD process is halfway to solving the streamlining process. The environment-project model is built to provide flexibility and control across multiple stages of development. At its core, it allows our users to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create Isolated Environments:&lt;/strong&gt; Each environment is independent yet can replicate production settings, making it ideal for testing and development.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manage Permissions Seamlessly:&lt;/strong&gt; Permission management is consistent across environments, ensuring that your CI/CD process is both secure and reliable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automate Workflows:&lt;/strong&gt; Permit integrates smoothly with CI/CD tools like GitHub Actions, enabling automated environment creation, testing, merging, and cleanup.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As mentioned, this model is especially useful in scenarios where environments need to be dynamically created, tested, and merged—making it perfect for PR-based workflows.&lt;/p&gt;

&lt;p&gt;With this model in mind, let’s identify the automation and streamlining challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow Friction: Identifying the Challenges
&lt;/h2&gt;

&lt;p&gt;To fully support the seamless integration of an authorization service to existing users' environments and architecture, we need to identify the events and connection points of our permissions system with the software development system.&lt;/p&gt;

&lt;p&gt;At the basic level, a new environment needs to be created in Permit for every pull request (PR). This allows isolating configuration from the production and staging environments, running tests to ensure branch and environment protection, and merging changes into production, all with minimal manual intervention.&lt;/p&gt;

&lt;p&gt;This process involves the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Environment Creation:&lt;/strong&gt; We want to let our users automate the process of creating a new Permit environment for each PR. We also understand that not every PR should have an authorization configuration change, so we want to ensure that we are opening new environments only for relevant PRs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment Testing:&lt;/strong&gt; For each PR, we want to run integration and product tests against the relevant environment to ensure the accuracy of permissions and settings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Merging and Cleanup:&lt;/strong&gt; After a PR is approved, we want to merge the Permit environment with the production environment. This will allow us to ensure streamlined deployment and delivery.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Manually managing these tasks can be error-prone and time-consuming, compelling us to find a reliable way to automate them. With CI/CD in mind, we want to streamline the continuous integration of the first two steps and the continuous deployment and delivery of the last.&lt;/p&gt;

&lt;p&gt;Now that we understand the requirements let’s create our GitHub action:&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Custom GitHub Action
&lt;/h2&gt;

&lt;p&gt;As described, our GitHub Action incorporates three workflows that fully automate the environment management process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;new-env.yaml&lt;/code&gt; &lt;strong&gt;:&lt;/strong&gt; Creates a new environment when a PR is opened or updated.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;run-pdp.yaml&lt;/code&gt; &lt;strong&gt;:&lt;/strong&gt; Runs tests in the newly created environment.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;merging.yaml&lt;/code&gt; &lt;strong&gt;:&lt;/strong&gt; Merges the environment changes into production and then deletes the PR-specific environment.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These workflows utilize Permit’s API to dynamically manage environments, providing a streamlined and error-free process. You can see this workflow in action in the following code repository: &lt;a href="https://github.com/permitio/pink-mobile-demo-app/tree/main/.github/workflows" rel="noopener noreferrer"&gt;https://github.com/permitio/pink-mobile-demo-app/tree/main/.github/workflows&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s take a look at the code and understand its steps -&lt;/p&gt;

&lt;h3&gt;
  
  
  Workflow Breakdown
&lt;/h3&gt;

&lt;h3&gt;
  
  
  1. Creating a New Environment (&lt;code&gt;new-env.yaml&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;When a new PR is opened or updated, we trigger a workflow responsible for creating a new environment within Permit. We will create this environment using Permit’s copy environment API to replicate the production settings, ensuring consistency across all environments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trigger the Workflow:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first step of running our workflow is to trigger it as a result of events in our code. We can do this by using the following command:&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;demo-new-env&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;opened&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;reopened&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will ensure our workflow is triggered. In the next step, we’ll set it up with some variables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set up the environment:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Define the project ID as an environment variable. This will be used in subsequent API calls.&lt;br&gt;&lt;br&gt;
This project is the one the environment will be created in. In production, you can get it from a GitHub variable.&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;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;PROJECT_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1238e459351a8470&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Check Creation Relevancy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To ensure we are not opening a redundant environment in Permit for PRs that are not relevant for permissions changes, you’ll need to label PRs with a &lt;code&gt;Permissions&lt;/code&gt; tag. This will serve as a condition for creating an environment:&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;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;demo-new-env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;contains( github.event.pull_request.labels.*.name, 'permissions')&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Extract the Branch Name:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next, extract the branch name. We will need it to name our new environment:&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="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;Extract branch name&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" &amp;gt;&amp;gt; $GITHUB_OUTPUT&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;extract_branch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create the New Environment:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a new environment in Permit. This is done by posting the environment details, including a unique key derived from the branch name:&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="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;Create new environment&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;response=$(curl -X POST \\&lt;/span&gt;
      &lt;span class="s"&gt;&amp;lt;https://api.permit.io/v2/projects/$&amp;gt;{{ env.PROJECT_ID }}/envs \\&lt;/span&gt;
      &lt;span class="s"&gt;-H 'Authorization: Bearer ${{ secrets.PROJECT_API_KEY }}' \\&lt;/span&gt;
      &lt;span class="s"&gt;-H 'Content-Type: application/json' \\&lt;/span&gt;
      &lt;span class="s"&gt;-d '{&lt;/span&gt;
        &lt;span class="s"&gt;"key": "pr-${{ steps.extract_branch.outputs.branch }}",&lt;/span&gt;
        &lt;span class="s"&gt;"name": "pr-${{ steps.extract_branch.outputs.branch }}"&lt;/span&gt;
      &lt;span class="s"&gt;}')&lt;/span&gt;

    &lt;span class="s"&gt;echo "ENV_ID=$(echo "$response" | jq -r '.id')" &amp;gt;&amp;gt; $GITHUB_ENV&lt;/span&gt;
    &lt;span class="s"&gt;echo "New env ID: $(echo "$response" | jq -r '.id')"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fetch the Environment API Key:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The workflow will retrieve the API key for the newly created environment, which will be used in subsequent workflows:&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="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;Fetch API Key of the new environment&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;response=$(curl -X GET \\&lt;/span&gt;
      &lt;span class="s"&gt;&amp;lt;https://api.permit.io/v2/api-key/$&amp;gt;{{ env.PROJECT_ID }}/${{ env.ENV_ID }} \\&lt;/span&gt;
      &lt;span class="s"&gt;-H 'Authorization: Bearer ${{ secrets.PROJECT_API_KEY }}')&lt;/span&gt;

    &lt;span class="s"&gt;ENV_API_KEY=$(echo "$response" | jq -r '.secret')&lt;/span&gt;
    &lt;span class="s"&gt;echo "ENV_API_KEY=$ENV_API_KEY" &amp;gt;&amp;gt; $GITHUB_ENV&lt;/span&gt;
    &lt;span class="s"&gt;echo "New env API key: $ENV_API_KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Running Tests in the New Environment (&lt;code&gt;run-pdp.yaml&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;For our next step in continuous integration, we would like to let our pipeline test the code against the newly created environment. One key aspect of Permit’s architecture is using a local policy decision point (PDP) that runs together with the application.&lt;/p&gt;

&lt;p&gt;In this workflow, we want to run the PDP in the GitHub action. This way, the tests can call it. We’ll also use this step to set up some mock data in the Permit system:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Triggering the Workflow:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This workflow will run whenever a PR is synchronized, ensuring that any updates are tested:&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;demo-run-pdp-and-tests&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;synchronize&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fetching the Environment ID and API Key:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next, we’ll fetch the existing environment ID created in the previous workflow:&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="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;Fetch environment ID and API key&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;response=$(curl -s -X GET &amp;lt;https://api.permit.io/v2/projects/$&amp;gt;{{ env.PROJECT_ID }}/envs \\&lt;/span&gt;
      &lt;span class="s"&gt;-H 'Authorization: Bearer ${{ secrets.PROJECT_API_KEY }}' \\&lt;/span&gt;
      &lt;span class="s"&gt;-H 'Content-Type: application/json')&lt;/span&gt;
    &lt;span class="s"&gt;EXISTING_ID=$(echo "$response" | jq -r '.[] | select(.key == "pr-${{ steps.extract_branch.outputs.branch }}") | .id')&lt;/span&gt;
    &lt;span class="s"&gt;echo "EXISTING_ID=$EXISTING_ID" &amp;gt;&amp;gt; $GITHUB_ENV&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Running the Local PDP Instance:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Then, a local instance of the PDP needs to be spun up using Docker, allowing tests to be run against the newly created environment:&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="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;local PDP running&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker run -d -p 7766:7000 --env PDP_API_KEY=${{ env.ENV_API_KEY }} --env PDP_DEBUG=true permitio/pdp-v2:latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Executing the Tests:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, we can execute tests against the local PDP instance using the environment’s API key:&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="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;Run tests&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PERMIT_TOKEN=${{ env.ENV_API_KEY }} PDP_URL=localhost:7766 npm run test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Merging Changes and Cleanup (&lt;code&gt;merging.yaml&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;The last step of our custom GitHub Action is to ensure an efficient and streamlined deployment and delivery process. This is where we will trigger the merge workflow, which will ensure we are safely integrating the created environment into our production environment in Permit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Triggering the Workflow:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This workflow is triggered when a PR is closed, signaling that it’s time to merge and clean up:&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;demo-merging&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;closed&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fetching Production and PR Environment IDs:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next, fetch the IDs of the production environment and the PR-specific environment:&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="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;Fetch production and PR environment IDs&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;response=$(curl -s -X GET &amp;lt;https://api.permit.io/v2/projects/$&amp;gt;{{ env.PROJECT_ID }}/envs \\&lt;/span&gt;
      &lt;span class="s"&gt;-H 'Authorization: Bearer ${{ secrets.PROJECT_API_KEY }}' \\&lt;/span&gt;
      &lt;span class="s"&gt;-H 'Content-Type: application/json')&lt;/span&gt;
    &lt;span class="s"&gt;PROD_ID=$(echo "$response" | jq -r '.[] | select(.key == "production") | .id')&lt;/span&gt;
    &lt;span class="s"&gt;echo "PROD_ID=$PROD_ID" &amp;gt;&amp;gt; $GITHUB_ENV&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Merging and Deleting the PR Environment:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, merge the PR-specific environment into production and then delete the PR environment, ensuring no residual environments remain:&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="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;Merge and delete PR environment&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;curl -X POST &amp;lt;https://api.permit.io/v2/projects/$&amp;gt;{{ env.PROJECT_ID }}/envs/${{ env.EXISTING_ID }}/copy \\&lt;/span&gt;
      &lt;span class="s"&gt;-H 'Authorization: Bearer ${{ secrets.PROJECT_API_KEY }}' \\&lt;/span&gt;
      &lt;span class="s"&gt;-H 'Content-Type: application/json' \\&lt;/span&gt;
      &lt;span class="s"&gt;-d '{&lt;/span&gt;
        &lt;span class="s"&gt;"target_env": {&lt;/span&gt;
            &lt;span class="s"&gt;"existing": "${{ env.PROD_ID }}"&lt;/span&gt;
        &lt;span class="s"&gt;}&lt;/span&gt;
    &lt;span class="s"&gt;}'&lt;/span&gt;

    &lt;span class="s"&gt;curl -X DELETE \\&lt;/span&gt;
      &lt;span class="s"&gt;&amp;lt;https://api.permit.io/v2/projects/$&amp;gt;{{ env.PROJECT_ID }}/envs/${{ env.EXISTING_ID }} \\&lt;/span&gt;
      &lt;span class="s"&gt;-H 'Authorization: Bearer ${{ secrets.PROJECT_API_KEY }}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Our Custom GitHub Action
&lt;/h2&gt;

&lt;p&gt;Looking at the three steps we just created, we can easily see how this action is streamlined the whole process of our authorization service into our users’ architecture. Here's how we tackled them using our custom GitHub Actions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Environment Creation&lt;/strong&gt;: The process of creating new environments for every pull request (PR) was automated through the &lt;code&gt;new-env.yaml&lt;/code&gt; workflow. This action triggers when a relevant PR is opened or updated, automating the creation of a new environment in Permit. By using Permit’s API, we replicate production settings in the new environment, ensuring consistency across the different stages. A condition was also added to avoid unnecessary environment creation for PRs unrelated to permission changes, using a label system to filter relevant PRs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Environment Testing&lt;/strong&gt;: The &lt;code&gt;run-pdp.yaml&lt;/code&gt; workflow addresses the need to run tests on the newly created environment. Once a new environment is set up, the workflow spins up a local Policy Decision Point (PDP) instance via Docker. This allows integration and product tests to run against the environment, ensuring that permission settings are accurate before merging changes into production. This automated testing prevents errors and guarantees that only well-tested changes move forward.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Merging and Cleanup&lt;/strong&gt;: After a PR is approved and closed, the &lt;code&gt;merging.yaml&lt;/code&gt; workflow merges the PR-specific environment into the production environment, streamlining the deployment process. Following the merge, the workflow deletes the PR-specific environment, ensuring that no unnecessary environments linger, thereby reducing clutter and maintaining a clean development setup.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By automating these steps—environment creation, testing, merging, and cleanup—we significantly reduced manual intervention, minimized errors, and sped up the entire CI/CD process.&lt;/p&gt;

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

&lt;p&gt;By integrating GitHub Actions with &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt; APIs, we were able to streamline our CI/CD process and make our environment model accessible and efficient for development teams. This approach not only reduced manual effort but also minimized the risk of errors, providing a smoother and more reliable deployment process.&lt;/p&gt;

&lt;p&gt;For any team looking to optimize their CI/CD pipeline, &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;’s flexible environment model combined with GitHub Actions offers a powerful solution to automate and secure your development workflows.&lt;/p&gt;

&lt;p&gt;You can read more in our docs about how we handle &lt;a href="https://docs.permit.io/manage-your-account/projects-and-env" rel="noopener noreferrer"&gt;Projects &amp;amp; Environments&lt;/a&gt;, or &lt;a href="http://permit.io" rel="noopener noreferrer"&gt;try out Permit.io for yourself!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have any questions, &lt;a href="https://io.permit.io/permitslack" rel="noopener noreferrer"&gt;join our Slack community&lt;/a&gt;, where there are thousands of devs building and implementing authorization.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>devops</category>
      <category>github</category>
      <category>cloud</category>
    </item>
    <item>
      <title>7 Developer Tools to Prepare Your Stack for the GenAI Era</title>
      <dc:creator>Gabriel L. Manor</dc:creator>
      <pubDate>Wed, 24 Jul 2024 13:01:54 +0000</pubDate>
      <link>https://dev.to/gemanor/7-developer-tools-to-prepare-your-stack-for-the-genai-era-2e6m</link>
      <guid>https://dev.to/gemanor/7-developer-tools-to-prepare-your-stack-for-the-genai-era-2e6m</guid>
      <description>&lt;p&gt;GenAI has completely changed the face of software development, and integrating it into your application is becoming essential rather than optional. Integrating GenAI into your application is not an easy task, but there are some powerful tools that can make the integration of GenAI features into your application easier and, even more importantly, more secure. &lt;/p&gt;

&lt;p&gt;Instead of focusing on the usual AI tools like OpenAI or Cloud APIs, we'll look at traditional developer tools that make adopting GenAI into your application a seamless experience.&lt;/p&gt;

&lt;p&gt;Here are seven powerful developer tools that can streamline the integration of GenAI features into your applications, ensuring they remain secure, efficient, and competitive: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before we dive into the list - Permit.io just launched a new feature on ProductHunt. It’s a set of embeddable access-sharing components for your application. I’d appreciate if you could support it by giving us an upvote or comment ❤️&lt;br&gt;
 &lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://www.producthunt.com/posts/permit-share-if" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--z9pVIgBM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ph-files.imgix.net/1fa73cf8-5d70-406e-9562-92cb5ce478e1.png%3Fauto%3Dformat%26fit%3Dcrop%26frame%3D1%26h%3D512%26w%3D1024" height="400" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://www.producthunt.com/posts/permit-share-if" rel="noopener noreferrer" class="c-link"&gt;
           Permit Share-If - Embeddable access sharing components | Product Hunt
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          “Permit Share-If” is a suite of prebuilt, embeddable UI components that make access sharing in applications a breeze. Designed to provide fully functional access control, they make delegating permission management to your users simple and safe.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--cmeqGyAO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ph-static.imgix.net/ph-favicon-coral.ico" width="240" height="240"&gt;
        producthunt.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  1. &lt;a href="https://arcjet.com/" rel="noopener noreferrer"&gt;Arcjet&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;One of the most challenging aspects of integrating GenAI is managing non-human identities. Traditional methods to block bots, such as using Cloudflare or firewalls, are becoming less and less effective. Arcjet’s advanced security tools are specifically designed to handle this issue. Their bot prevention system ranks bots based on quality, behavior, and availability, allowing for smarter, more nuanced protection.&lt;/p&gt;

&lt;p&gt;This allows you to create a smart layer of security that differentiates between harmful bots and GenAI agents that need access to your application - an approach that ensures malicious bots are blocked, and GenAI can access necessary public data to perform its functions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgaoxa51shwg7q6vlvpc5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgaoxa51shwg7q6vlvpc5.png" alt="Arcjet Bot Protection" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, Arcjet’s tools are designed to integrate seamlessly into your existing security infrastructure, making them easier to implement without significant system overhauls.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;a href="https://gitbutler.com/" rel="noopener noreferrer"&gt;GitButler&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;With AI agents like GitHub Copilot, we can develop applications faster and experiment more with our code. GitButler, developed by one of GitHub's co-founders, is a new Git client designed to increase development velocity. It offers features like virtual branches and auto-commit messages, making local experimentation with your code and data more efficient.&lt;/p&gt;

&lt;p&gt;Using GitButler as your Git client enhances your development process by leveraging AI agents. It simplifies the management of your codebase, allowing for quicker iterations and more productive coding sessions. This efficiency is particularly beneficial when integrating GenAI, as it allows for rapid prototyping and testing.&lt;/p&gt;

&lt;p&gt;Additionally, GitButler’s features support a smoother workflow, enabling you to take full advantage of AI agents in your development environment. This tool helps you streamline your coding process, making it easier to incorporate GenAI capabilities into your applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. DataStax &lt;a href="https://www.datastax.com/products/datastax-astra" rel="noopener noreferrer"&gt;AstraDB&lt;/a&gt; and &lt;a href="https://www.langflow.org/" rel="noopener noreferrer"&gt;Langflow&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Integrating your existing data with large language models and AI agents is essential to truly enable GenAI in your application. DataStax AstraDB, combined with Langflow, actually makes this possible. DataStax’s vector database, based on Apache Cassandra, allows for efficient storage and retrieval of vector data - crucial for AI applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ojuqbjejkmw1vsizan3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ojuqbjejkmw1vsizan3.png" alt="Langflow Demo" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Langflow, a recent acquisition by DataStax, enhances this offering with a low-code UI, making it easy to build GenAI applications. This tool simplifies the process of connecting your data with AI models, enabling even those with limited AI expertise to create sophisticated AI-driven features.&lt;/p&gt;

&lt;p&gt;The combination of AstraDB and Langflow ensures that your application can leverage GenAI to provide advanced user experiences, such as answering user queries with AI-driven responses or offering personalized recommendations.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;a href="https://lunar.dev/" rel="noopener noreferrer"&gt;Lunar.dev&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The implementation of GenAI comes with a surge of API calls for GenAI services, like those to OpenAI. This requires a new layer in our applications. Traditionally, API gateways have focused on inbound calls, but with GenAI, managing outbound calls efficiently is equally important. Lunar.dev introduces the concept of an egress API Gateway, or AI Gateway, to handle this new requirement.&lt;/p&gt;

&lt;p&gt;Lunar.dev acts as an intermediary for outbound API calls, streamlining permissions, limiting calls, and caching responses. This ensures that your GenAI integration is efficient and cost-effective, preventing unnecessary expenditure on excessive API calls.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9hb8pttw3xbfg5t06xp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9hb8pttw3xbfg5t06xp.png" alt="Lunar.dev flow" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Furthermore, by using Lunar.dev, you can ensure that your API usage remains controlled and efficient. This tool provides a way to manage the increased API traffic that comes with integrating GenAI, making it an essential part of a modern developer’s toolkit.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;a href="https://www.buildwithfern.com/" rel="noopener noreferrer"&gt;Fern&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Creating GenAI applications requires state-of-the-art documentation. Writing comprehensive API documentation can be challenging, but it is crucial for enabling users to create programmatic applications based on your APIs. Fern offers an innovative solution to this problem with a CLI tool that helps you generate thorough documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frncofs8fc55737sh59kw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frncofs8fc55737sh59kw.png" alt="Fern API Documentation Flow" width="800" height="622"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fern’s approach to API documentation helps users understand what they can do with your application, enhancing the integration of GenAI features. By providing clear and detailed documentation, Fern ensures that developers can fully utilize your APIs, enabling better GenAI integration.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. &lt;a href="https://www.permit.io/" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;As our applications grow, it’s crucial to decide what users—both human and GenAI—can access once they log-in. Traditional role-based access control often falls short, especially as GenAI introduces numerous bots and unpredictable amount of unstructured data into the system. &lt;/p&gt;

&lt;p&gt;Permit.io offers a comprehensive solution for fine-grained authorization, allowing you to set precise access controls based on various conditions and relationships between data.&lt;/p&gt;

&lt;p&gt;Permit.io provides a simple SDK that makes enforcing these fine-grained models straightforward. With just a small check function, you can determine what a user can or cannot do at any given moment. This capability is crucial in a world where not only humans but also AI agents interact with your application, ensuring secure and efficient access management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fucngr8d73ah8tmehp1d8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fucngr8d73ah8tmehp1d8.jpg" alt="Permit Share-If" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It also supports multiple access control models, including Role-Based Access Control (RBAC), Attribute-Based Access Control (ABAC), and Relationship-Based Access Control (ReBAC). This flexibility ensures that your application can adapt to various access control requirements, making it a vital tool for integrating GenAI securely into your application.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. &lt;a href="https://neon.tech/" rel="noopener noreferrer"&gt;Neon&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;PostgreSQL with vector support is an excellent way to use vector databases in your application infrastructure. Neon provides a robust infrastructure for PostgreSQL, offering features like versioning, branching, and autoscaling. This enables faster investigation and research on integrating your applications and data with GenAI agents.&lt;/p&gt;

&lt;p&gt;Neon’s seamless integration with PostgreSQL ensures that your application can leverage vector databases to provide advanced AI-driven features. By supporting vector data, Neon makes it easier to use GenAI to deliver accurate and relevant responses to user queries.&lt;/p&gt;

&lt;p&gt;Their features simplify database management, allowing for efficient scaling and maintenance. This makes it a valuable tool for developers looking to integrate GenAI and provides a solid foundation for building sophisticated AI-driven experiences.&lt;/p&gt;

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

&lt;p&gt;By leveraging these seven tools, you can integrate GenAI features into your applications with enhanced security and efficiency. These tools are designed to simplify the complex process of GenAI integration, ensuring that your applications not only keep up with the latest advancements but also provide a superior user experience. As GenAI continues to evolve, staying ahead with these essential tools will ensure your applications remain at the forefront of innovation and user satisfaction.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>productivity</category>
      <category>ai</category>
      <category>coding</category>
    </item>
    <item>
      <title>Announcing “Permit Share-If" Embeddable Access Sharing Components</title>
      <dc:creator>Gabriel L. Manor</dc:creator>
      <pubDate>Tue, 23 Jul 2024 15:49:19 +0000</pubDate>
      <link>https://dev.to/permit_io/announcing-permit-share-if-embeddable-access-sharing-components-4pgo</link>
      <guid>https://dev.to/permit_io/announcing-permit-share-if-embeddable-access-sharing-components-4pgo</guid>
      <description>&lt;h2&gt;
  
  
  Never Build Access-Sharing Again
&lt;/h2&gt;

&lt;p&gt;You've seen access-sharing components a million times before. From requesting to edit a document or view a widget in a dashboard to submitting a wire transfer for approval, they’re a must-have feature in almost any modern application.&lt;/p&gt;

&lt;p&gt;Every time you’ve seen this feature, it’s taken an enormous amount of development work to build and maintain over time.&lt;/p&gt;

&lt;p&gt;We kept seeing our customers building these experiences over and over on top of our API, and we decided, as our CEO Or Weis put it, “It was about time someone brought some order to this part of town”.&lt;/p&gt;

&lt;blockquote&gt;

&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://www.producthunt.com/posts/permit-share-if" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--z9pVIgBM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ph-files.imgix.net/1fa73cf8-5d70-406e-9562-92cb5ce478e1.png%3Fauto%3Dformat%26fit%3Dcrop%26frame%3D1%26h%3D512%26w%3D1024" height="400" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://www.producthunt.com/posts/permit-share-if" rel="noopener noreferrer" class="c-link"&gt;
           Permit Share-If - Embeddable Access Sharing Components | Product Hunt
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          “Permit Share-If” is a suite of prebuilt, embeddable UI components that make access sharing in applications a breeze. Designed to provide fully functional access control, they make delegating permission management to your users simple and safe.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--cmeqGyAO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ph-static.imgix.net/ph-favicon-coral.ico" width="240" height="240"&gt;
        producthunt.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is Permit Share-If?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="//www.permit.io/share-if"&gt;&lt;strong&gt;"Permit Share-If"&lt;/strong&gt;&lt;/a&gt; is a suite of prebuilt, embeddable UI components designed to streamline access sharing in applications. These components provide fully functional access control, making it easy and safe for users to manage permissions.&lt;/p&gt;

&lt;p&gt;With just a few clicks, Permit Share-If enables application developers to create and embed custom interfaces such as user management, audit logs, access requests, operation approval flows, and more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h_bUtu1A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/zqSNt9bMR12vWN9bava5" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h_bUtu1A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/zqSNt9bMR12vWN9bava5" title="Untitled (23).png" alt="Untitled (23).png" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Holistic Solution to Fine-Grained Authorization
&lt;/h2&gt;

&lt;p&gt;With the ever-rising importance of security and privacy, secure collaboration through access-sharing is a must-have feature in almost any modern application. Despite how common this problem is, access-sharing features can be very hard to build and maintain.&lt;/p&gt;

&lt;p&gt;These solutions must provide a good experience for end-users (Granting them access to what they need while maintaining the principle of least privilege) and a good access review experience to our users and developers so they don’t end up skipping fine-grained authorization entirely (by giving everyone Super-Admin permissions).&lt;/p&gt;

&lt;p&gt;That was why we created Share-If - a solution that enables developers to implement secure collaboration features into their applications, maintain the principle of least privilege, provide a good access review experience, bring Fine-Grained Authorization to their applications, and maintain scalability and observability—all with zero development time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CD7p2fqV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/2hqV654rQSKRkLW00EZn" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CD7p2fqV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/2hqV654rQSKRkLW00EZn" title="Untitled (24).png" alt="Untitled (24).png" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Share-If Features:
&lt;/h2&gt;

&lt;p&gt;The new Permit Share-If set of components includes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Access Request:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Allow users to request restricted resource access directly from your application (just like the Share functionality in Google Drive / Dropbox). Requests are sent to designated users for approval or denial, simplifying access management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4n-4_6Un--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/LIafugdOTTm3MvlOWev9" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4n-4_6Un--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/LIafugdOTTm3MvlOWev9" title="Untitled (25).png" alt="Untitled (25).png" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operation Approval:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Users can submit approval requests via an embedded component, allowing admins to oversee and control specific actions, such as wire transfers from joint accounts. While Access Requests are intended to provide long-term access to a resource, Operation Approvals allow managing requests to perform a singular action.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tymxDCJo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/OMetij0SS6iugn3C5iYw" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tymxDCJo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/OMetij0SS6iugn3C5iYw" title="Untitled (26).png" alt="Untitled (26).png" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Approval Management:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Allow users to approve/deny operation requests through a friendly UI. A single embedded component where designated users can handle operation approvals efficiently, maintaining strict control over access review functions.&lt;/p&gt;

&lt;p&gt;All Permit Share-If elements also include meta authorization features - allowing your users to decide which of their users can request and approve access and operations - all with proper limitations and within safe interface boundaries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secure, App-Level Collaboration in the AI Era
&lt;/h2&gt;

&lt;p&gt;With the ever-rising importance of security and privacy, secure collaboration through access-sharing is a must-have feature in almost any modern application. This is especially true &lt;strong&gt;with the rise of GenAI integrations and non-human identities in our applications&lt;/strong&gt; - they require a solution that ensures proactive access control management by our users.&lt;/p&gt;

&lt;p&gt;That’s where Permit Share-If comes in. Being the latest addition to the &lt;a href="https://www.permit.io/elements" rel="noopener noreferrer"&gt;Permit-Element suite&lt;/a&gt; of embeddable UI components, it is designed to provide fully functional access control to both your developers and end-users.&lt;/p&gt;

&lt;p&gt;Supporting embeddable components such as User Management and fully-fledged Authorization Audit Logs, and with a strong focus on user experience, they allow you to achieve true fine-grained authorization without the hassle of developing it in-house.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can’t Wait to See What You’ll Build!
&lt;/h2&gt;

&lt;p&gt;Permit Share-If represents a significant advancement in simplifying access-sharing and authorization for application developers. By integrating these prebuilt, embeddable components, developers can ensure secure, efficient, and user-friendly access management without the extensive development time typically required. Permit Share-If not only streamlines the implementation of access controls but also enhances security, maintains the principle of least privilege, and supports seamless collaboration in today's AI-driven applications.&lt;/p&gt;

&lt;p&gt;We invite you to try Permit Share-If and see how it can transform the way you manage access and authorization in your applications. Got questions? Join our &lt;a href="https://io.permit.io/permitslack" rel="noopener noreferrer"&gt;&lt;strong&gt;Slack community&lt;/strong&gt;&lt;/a&gt;, where thousands of devs are building and implementing authorization.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>news</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Protect Your Application from AI Bots</title>
      <dc:creator>Gabriel L. Manor</dc:creator>
      <pubDate>Mon, 08 Jul 2024 16:40:00 +0000</pubDate>
      <link>https://dev.to/permit_io/how-to-protect-your-application-from-ai-bots-49ab</link>
      <guid>https://dev.to/permit_io/how-to-protect-your-application-from-ai-bots-49ab</guid>
      <description>&lt;p&gt;Bots have traditionally been something we try to prevent from entering our applications. There were, of course, always good (or at least useful) bots as well, such as search engines and test automation scripts, but those were always less common compared to malicious ones.&lt;/p&gt;

&lt;p&gt;In the past year, since LLMs and GPT have become a major part of our lives, we’ve found ourselves with a whole new set of bots that don’t really fit the categories previously known to us.&lt;/p&gt;

&lt;p&gt;These machine identities are welcomed into our applications by users who want to get some help from GenAI, but that doesn’t change the fact that they should be a concern for us as developers who are trying to protect our data and users.&lt;/p&gt;

&lt;p&gt;These new entities can be harmful from many security and privacy perspectives, and we need to know how to handle them.&lt;/p&gt;

&lt;p&gt;In this blog, we will evaluate the presence of GenAI identities in our applications and show how to create a smart layer of fine-grained authorization that allows us to integrate bots securely into our applications. To do that, we’ll use two tools: &lt;a href="http://permit.io/" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt; and &lt;a href="https://www.arcjet.com/" rel="noopener noreferrer"&gt;Arcjet&lt;/a&gt;, to model and enforce these security rules in our applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rise of The Machines
&lt;/h2&gt;

&lt;p&gt;We’ve always had a very clear distinction between human and machine identities. The methods used to authenticate, authorize, audit, secure, and manage those identities have been very different. In security, for example, we tried to strengthen human identities against &lt;strong&gt;human error&lt;/strong&gt; (i.e. Phishing, Password Theft), while with machine identities, we mostly dealt with &lt;strong&gt;misconfiguration problems&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The rise of GenAI usage has brought new types of hybrid identities that potentially can suffer from problems in both worlds. These new hybrid identities consist of machine identities that adopt human attributes and human identities that adopt machine identities.&lt;/p&gt;

&lt;p&gt;From the machine side, take Grammarly (or any other grammar AI application) as an example. Grammarly is a piece of software that is supposed to be identified as a machine identity. The problem? It’s installed by the application user without notifying the developers of a new type of machine identity in the system. It gets access to tons of private data and (potentially) can perform actions without letting the developers deal with the usual weaknesses of machine identities.&lt;/p&gt;

&lt;p&gt;On the other hand, from the human identity side, GenAI tools give human identities the possibility of adopting machine power without having the “skills” to use it. Even a conventional subreddit like &lt;a href="https://www.reddit.com/r/prompthacking/" rel="noopener noreferrer"&gt;r/prompthacking&lt;/a&gt; provides people with prompts that can help them use data in a way that no one estimates a human identity can perform. It's a common practice to have less validation and sanitization on API inputs than in the UI, but if users can access those APIs via bots, they can abuse our trust in the API standard.&lt;/p&gt;

&lt;p&gt;These new hybrid identities force us to rethink the way we are handling identity security.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ranking Over Detecting
&lt;/h2&gt;

&lt;p&gt;One of the questions we need to re-ask when securing our applications for such hybrid identities is ‘ &lt;strong&gt;Who is the user?’&lt;/strong&gt;. Traditionally, that was an authentication-only question. The general authorization question of ‘ &lt;strong&gt;What can this user do?’&lt;/strong&gt; fully trusts the answer of the authentication phase. With the new hybrid identities that can easily use a non-native method to authenticate, trusting this binary answer from the authentication service can lead to permission flaws. This means we must find a new way to ask the “Who” question on the authorization side.&lt;/p&gt;

&lt;p&gt;In order to help the authorization service better answer this detailed "Who" question, we need to find a proper method to rank identities by multiple factors. This ranking system will help us make better decisions instead of using a traditional &lt;code&gt;good&lt;/code&gt;/&lt;code&gt;malicious&lt;/code&gt; user ranking.&lt;/p&gt;

&lt;p&gt;When considering the aspects of building such a ranking system, the first building block is to have a method to rank our type of identity somewhere between machine and human. In this article, we will use &lt;a href="https://www.arcjet.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Arcjet&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;,&lt;/strong&gt; an open-source startup that builds application security tools for developers and, more specifically, their ranking system. The following are the different ranks of identities between good and malicious bots, which could help us understand the first aspect of the new &lt;code&gt;Who&lt;/code&gt; question.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;NOT_ANALYZED&lt;/code&gt; - Request analysis failed; might lack sufficient data. Score: 0.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AUTOMATED&lt;/code&gt; - Confirmed bot-originated request. Score: 1.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LIKELY_AUTOMATED&lt;/code&gt; - Possible bot activity with varying certainty, scored 2-29.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LIKELY_NOT_A_BOT&lt;/code&gt; - Likely human-originated request, scored 30-99.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VERIFIED_BOT&lt;/code&gt; - Confirmed beneficial bot. Score: 100.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, each rank level also has a detailed score, so we can detect even more for the levels we want to configure.&lt;/p&gt;

&lt;p&gt;Assuming we can rank our user activity in real-time, we will have the first aspect required to answer the question of “Who is the user?” when we make the decision of “What can they do?” Once we have this ranking, we can also add more dimensions to this decision, making it even more sophisticated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conditions, Ownership, and Relationships
&lt;/h2&gt;

&lt;p&gt;While the first aspect considers only the user and its behavior, the others will help us understand the sensitivity of the particular operation that a user is trying to perform on a resource. Let’s examine three methods that can help us build a comprehensive policy system for ranking hybrid identity operations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Conditions&lt;/strong&gt; : With this method, we use the context of the authorization decisions and the user's bot rank score to build conditions that will help us get better control of these identity operations.
For example, if we want to keep ourselves safe from an injection of vulnerable data by applications that were accessed by a human user, we can use the bot's level plus the characters in the request to verify the level of danger.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ownership&lt;/strong&gt; : With this method, we add the level of ownership to the decision data to give it another dimension.
For example, we can decide that a user can let high-confidence bots modify their own data but not perform changes or read others’ data, while bots with lower ranking do not get access at all.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relationship&lt;/strong&gt; : With this method, we can use the relationship between entities to create another trust dimension in the user's rank.
For example, if we have a folder owned by a user and files in this folder owned by others, we can let the good bot perform operations on the folder but not the files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thinking of our new ranking system as multidimensional ranking can even help us mix and match our ranking systems for a fine-grained answer to the ” &lt;strong&gt;What&lt;/strong&gt; ” question that takes the “ &lt;strong&gt;Who&lt;/strong&gt; ” question into account.&lt;/p&gt;

&lt;p&gt;Let’s model such a simple ranking system in the &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt; fine-grained authorization policy editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modeling a Bot Ranking System
&lt;/h2&gt;

&lt;p&gt;While &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt; allows you to build a comprehensive multi-dimensional system with all the dimensions we mentioned, for the sake of simplicity in this tutorial, we will build a system based only on &lt;em&gt;conditions&lt;/em&gt; and &lt;em&gt;ownership&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For the model, we will use an easily understandable data model of a CMS system, where we have content items with four levels of built-in access: Public, Shared, Private, and Blocked.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public documents are documents that are owned by the user and shared publicly&lt;/li&gt;
&lt;li&gt;Shared documents are documents that are owned by others and shared publicly&lt;/li&gt;
&lt;li&gt;Private documents are documents that are owned by the user and marked as private&lt;/li&gt;
&lt;li&gt;Blocked documents are documents that are owned by others and marked as private&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, we would like to create segments for potential hybrid identities in our application. We will inherit Arcjet's direct model and configure five user sets that correlate to these five types of bots.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Login to Permit at &lt;a href="http://app.permit.io" rel="noopener noreferrer"&gt;app.permit.io&lt;/a&gt; (and create a workspace if you haven’t)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to Policy → Resources and create an Item resource with the following configuration&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BloMVNzT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/uUwNkGuBR9m0634eHonH" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BloMVNzT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/uUwNkGuBR9m0634eHonH" title="resource\_creation\_ai\_bots.png" alt="resource_creation_ai_bots.png" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now, we want to add a user attribute that allows for smart bot detection. Go to the Directory page click the &lt;code&gt;Settings&lt;/code&gt; button on the top-right corner of the page, and choose &lt;code&gt;User Attributes&lt;/code&gt; on the sidebar. Add the following attributes&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ajeDBzaC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/eCQtq0iQoaonKsDsNeWT" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ajeDBzaC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/eCQtq0iQoaonKsDsNeWT" title="user\_attrbute\_\_ai\_bots.png" alt="user_attrbute__ai_bots.png" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go back to the Policy screen, and navigate to ABAC Rules. Enable the ABAC options toggle, and click Create New on the User Set table. Create the following four user sets.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZUXM2S0n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/tVKmxYU3RZe6uVgjlh5A" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZUXM2S0n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/tVKmxYU3RZe6uVgjlh5A" title="user\_sets\_ai\_bots.png" alt="user_sets_ai_bots.png" width="800" height="588"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If we go back to the Policy screen now, we can see that our different user sets allow us to use the first dimensions of protection on our application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n6WRA_3A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/bZH8FtvRu2glffcSo8q4" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n6WRA_3A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/bZH8FtvRu2glffcSo8q4" title="user\_policy\_ai\_bots.png" alt="user_policy_ai_bots.png" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s now create the ranking on the other dimension with conditions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to ABAC Rules → Create Resource Set and create four resource sets, one per item type
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xAGaWbT9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/ewvZzyKNQm2naocnK9PQ" title="resource\_sets\_ai\_bots.png" alt="resource_sets_ai_bots.png" width="800" height="558"&gt;
&lt;/li&gt;
&lt;li&gt;Go back to the Policy screen and ensure the following configuration
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5TLNaYgB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/N30XwarqTmEtwewFnW3A" title="policy\_ai\_bots.png" alt="policy_ai_bots.png" width="800" height="936"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you can easily see, we configured the following rules in the table:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Human users can read Public, Shared, and Private data&lt;/li&gt;
&lt;li&gt;Trusted bots are allowed to read Public and Shared data&lt;/li&gt;
&lt;li&gt;Untrusted bots can read only the Public&lt;/li&gt;
&lt;li&gt;Evil bots (bots that try to hide their automated identity) are blocked for all kinds of data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This configuration actually stretched the “static” question of who to a dynamic multi-dimensional decision. With the policy model in mind, let’s run the project and see the dynamic enforcement in action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running a Demo
&lt;/h2&gt;

&lt;p&gt;In the following Node.js project, we utilized a very simple application where we saved three content items, one for every category we defined. From the user perspective, we haven’t implemented authentication but are using a hardcoded authentication token with the user ID on it.&lt;/p&gt;

&lt;p&gt;All the code is &lt;a href="https://github.com/permitio/fine-grained-bot-protection/tree/main" rel="noopener noreferrer"&gt;available here&lt;/a&gt; - &lt;a href="https://github.com/permitio/fine-grained-bot-protection" rel="noopener noreferrer"&gt;https://github.com/permitio/fine-grained-bot-protection&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To run the project locally in your environment, please follow the steps described in the &lt;a href="https://github.com/permitio/fine-grained-bot-protection/blob/main/README.md" rel="noopener noreferrer"&gt;project’s Readme.md file&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s take a short look at the code to understand the basics of our authorization enforcement.&lt;/p&gt;

&lt;p&gt;First, we have our endpoint to read documents from our “in-memory” database. This endpoint is fairly simple: It takes a hardcoded list of items, filters it by authorization level, and returns them to the user as plain text.&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;ITEMS&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="na"&gt;id&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Public Item&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;owner&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;private&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="p"&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Shared Item&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OTHER_USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;private&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="p"&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Private Item&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;owner&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;private&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="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="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Blocked Item&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OTHER_USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;private&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="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="k"&gt;async &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;=&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;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;authorizeList&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;ITEMS&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;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/plain&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;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&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;name&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&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="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&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="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;r&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;n&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;The authorize function that we are using here enforces permissions in two steps. First, it checks the bot rank of the particular request, and then it calls the &lt;code&gt;check&lt;/code&gt; function on Permit with the real-time data of the Arcjet bot rank and the content item ID. With this context, the Permit’s PDP will return the relevant function.&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;authorizeList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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;list&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="c1"&gt;// Get the bot detection decision from ArcJet&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;aj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;protect&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isBot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;results&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;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isBot&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="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;botType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isBot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Check authorization for each item in the list&lt;/span&gt;
  &lt;span class="c1"&gt;// For each user, we will add the botType attribute&lt;/span&gt;
  &lt;span class="c1"&gt;// For each resource, we will add the item attributes&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authorizationFilter&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;permit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bulkCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&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="na"&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;key&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;attributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;botType&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="na"&gt;action&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="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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content_Item&lt;/span&gt;&lt;span class="dl"&gt;"&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="p"&gt;{&lt;/span&gt;
          &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}))&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;authorizationFilter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&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;To test the application, you can use your local endpoint or use our deployed version at: &lt;a href="https://fga-bot.up.railway.app/" rel="noopener noreferrer"&gt;https://fga-bot.up.railway.app/&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visit the &lt;a href="https://fga-bot.up.railway.app/" rel="noopener noreferrer"&gt;application from the browser&lt;/a&gt;, you can read Public, Private, and Shared the items
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ep5Wbk_m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/WiLzpn6YTHiWM2QtGZlH" title="website\_ai\_bots.png" alt="website_ai_bots.png" width="360" height="151"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Try to run the following curl call from your terminal. Since this is a bot that does not try to pretend it isn't a bot, it will get the result as a trusted bot.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl &amp;lt;https://fga-bot.up.railway.app/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QaYeBNVY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/DDUt1QlTTNuqKcSk0NZp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QaYeBNVY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/DDUt1QlTTNuqKcSk0NZp" title="curl.png" alt="curl.png" width="723" height="215"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now, let's try to run a bot from a cloud-hosted machine that pretends to be human by its user agent. To run the bot, access the following environment and run the code there.&lt;br&gt;
&lt;a href="https://replit.com/@gabriel271/Nodejs#index.js" rel="noopener noreferrer"&gt;https://replit.com/@gabriel271/Nodejs#index.js&lt;/a&gt;&lt;br&gt;
As you can see, this bot will get only the public items&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PXJiWz3i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/xJPEaCfYQ8OL8VHn4BiN" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PXJiWz3i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/xJPEaCfYQ8OL8VHn4BiN" title="cloud\_script\_ai\_bots.png" alt="cloud_script_ai_bots.png" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you can see in this demo, we have a dynamic, context-aware system that ranks our hybrid identity in real-time and returns the relevant permissions as per activity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Experience and GenAI Security Challenges
&lt;/h2&gt;

&lt;p&gt;Security challenges associated with non-human identities are threats that developers need to handle directly. Traditionally, security teams have been responsible for these concerns, but the complexity and nuances of hybrid identities require a developer-centric approach. Developers who understand the intricacies of their applications are better positioned to implement and manage these security measures effectively.&lt;/p&gt;

&lt;p&gt;The only way to ensure our applications’ resilience is to use tools that give the developer an experience that seamlessly integrates into the software developer lifecycle. The tools we used in this article are great examples of how to deliver the highest standards of application security while speaking the language of developers.&lt;/p&gt;

&lt;p&gt;With &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;, developers (and other stakeholders) can easily modify authorization policies to respond to emerging threats or changing requirements. For instance, we can adjust our rules to prohibit bots from reading shared data. This change can be made seamlessly within the &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt; dashboard, instantly affecting the authorization logic without altering the application's codebase. All developers have to do is keep a very low footprint of enforcement functions in their applications.&lt;/p&gt;

&lt;p&gt;With Arcjet, we are taking the usual work of bot protection, which is traditionally part of the environment setup and external to the code itself, into the application code. Using the Arcjet product-oriented APIs, developers can create a dynamic protection layer without the hassle of maintaining another cycle in the software development lifecycle.&lt;/p&gt;

&lt;p&gt;The demo we show demonstrates a better situation where those tools work together without any software setup that is outside the core of product development.&lt;/p&gt;

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

&lt;p&gt;In this article, we explored the evolving landscape of machine identities and the security challenges they present. We discussed the importance of decoupling application decision logic from code to maintain flexibility and adaptability. By leveraging dynamic authorization tools like &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;, we can enhance our application's security without compromising on developer experience.&lt;/p&gt;

&lt;p&gt;To learn more about your possibilities with Permit’s fine-grained authorization, we invite you to take a deeper tour of the Permit UI and documentation and learn how to achieve fine-grained authorization in your application. We also invite you to visit the &lt;a href="https://github.com/arcjet/arcjet-js?tab=readme-ov-file#examples" rel="noopener noreferrer"&gt;Arcjet live demos&lt;/a&gt; to experience the other areas where they can provide great application protection with few lines of code.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>security</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Model Cloud-Native Authorization</title>
      <dc:creator>Gabriel L. Manor</dc:creator>
      <pubDate>Mon, 13 May 2024 12:00:00 +0000</pubDate>
      <link>https://dev.to/permit_io/how-to-model-cloud-native-authorization-aek</link>
      <guid>https://dev.to/permit_io/how-to-model-cloud-native-authorization-aek</guid>
      <description>&lt;p&gt;Creating and managing an effective authorization system is no easy task. Especially when it comes to doing so effectively across distributed cloud-native applications. Working with people who have been building authorization for a long time, we designed our authorization service, &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;, to be cloud native. Throughout this process, we found that there are three crucial key elements to building cloud-native authorization: Proper CI/DC, thorough testing, and precise modeling and implementation of your fine-grained authorization processes.&lt;/p&gt;

&lt;p&gt;This blog will cover these three crucial components for building cloud-native authorization, discuss how they allow you to build reliable and scalable fine-grained authorization, and show you how we implemented them in Permit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Cloud Native Authorization?
&lt;/h2&gt;

&lt;p&gt;In simple terms, Cloud Native Authorization refers to building and managing authorization systems that are fully integrated and operational within a cloud environment, leveraging cloud capabilities to enhance flexibility, scalability, and resilience. The key to achieving effective cloud-native authorization lies in focusing on three primary aspects:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Continuous Integration and Deployment (CI/CD)&lt;/strong&gt;, rigorous &lt;strong&gt;testing&lt;/strong&gt; , and &lt;strong&gt;accurate modeling&lt;/strong&gt; of your authorization processes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD:&lt;/strong&gt; Continuous integration and deployment ensure that your authorization system can adapt quickly to software changes and user requirements. This practice helps automate the update and deployment processes, which minimizes the risk of errors and maximizes operational efficiency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing:&lt;/strong&gt; Thorough testing is crucial to verify that the authorization system works as intended under various scenarios. It involves checking the system's security aspects and functional capabilities to prevent breaches and ensure that policies are enforced correctly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modeling Your Implementation:&lt;/strong&gt; Precise modeling involves outlining and structuring how authorization processes interact within your application. This step is critical because it helps create a clear framework that defines how policies are applied and managed across different application components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s dive into each of these and see how you can utilize them in your own fine-grained authorization system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Policy Lifecycle Management Through CI/CD
&lt;/h2&gt;

&lt;p&gt;Enhancing policy management with Continuous Integration and Continuous Deployment (CI/CD) processes allows us to maintain a consistent and secure authorization layer. Managing and merging policies into various environments while ensuring consistency and compliance, syncing them to Git and deployments, and utilizing the power of policy as code allows us to handle authorization swiftly and effectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automated Policy Updates and Deployments
&lt;/h3&gt;

&lt;p&gt;Automating updates and deployments through CI/CD ensures that changes are applied consistently and without human error across all environments. This automation speeds up the deployment process and enhances security by reducing the risk of misconfigurations. At &lt;a href="http://permit.io/" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;, we primarily manage the policy life cycle as part of a CI process by using &lt;a href="https://docs.permit.io/manage-your-account/projects-and-env" rel="noopener noreferrer"&gt;projects and environments&lt;/a&gt; together with the &lt;a href="https://api.permit.io/v2/redoc#tag/Environments" rel="noopener noreferrer"&gt;Environment API.&lt;/a&gt; By working with Permit environments for CI, CD is automatically achieved using &lt;a href="https://github.com/permitio/opal" rel="noopener noreferrer"&gt;OPAL&lt;/a&gt;, as every environment is automatically deployed to PDPs mapped to them (via their &lt;a href="https://docs.permit.io/manage-your-account/projects-and-env#fetching-and-rotating-the-api-key" rel="noopener noreferrer"&gt;API secret key&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Version Control and Consistency with GitOps
&lt;/h3&gt;

&lt;p&gt;Maintaining version control and ensuring consistency across environments is essential when managing complex systems. Using a Git-like model for environments, where each environment corresponds to a branch, helps teams manage development, staging, and production configurations separately yet consistently. This approach allows for editing, reviewing, and merging policies as code within a Git repository, ensuring transparency and collaboration. At &lt;a href="http://permit.io/" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;, we achieve this by allowing you to automatically map branches when you &lt;a href="https://docs.permit.io/integrations/gitops/github" rel="noopener noreferrer"&gt;connect your Permit Project to a repository&lt;/a&gt;, facilitating efficient lifecycle management and leveraging Git's robust version control system.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Effective Authorization Testing Strategies&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before any policy is deployed to a production environment, it must be thoroughly tested in a controlled setting. Effective testing strategies confirm that the system behaves as expected under various conditions and help catch potential issues before they affect the production environment. Here's how testing should be structured:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Unit Testing&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Unit tests are essential for verifying the individual components of your authorization policies. These tests should be designed to run independently from the rest of the system, allowing for quick checks on the logic and functionality of each policy. At &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;, unit tests can be executed using policy as code, where the policy code is loaded directly onto the policy engine (&lt;a href="https://www.openpolicyagent.org/docs/latest/policy-testing/" rel="noopener noreferrer"&gt;such as via the OPA test command line&lt;/a&gt;), ensuring that each component functions correctly in isolation.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Application and Integration Testing&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Application and integration tests evaluate how well different parts of your application work together under real-world scenarios. This involves deploying a &lt;a href="https://docs.permit.io/overview/how-does-it-work#the-policy-decision-point-pdp" rel="noopener noreferrer"&gt;Policy Decision Point (PDP)&lt;/a&gt; that is synced to the development environment and running tests that simulate actual application queries against the PDP. This method ensures that policies are not only theoretically correct, but are also effectively enforced within the application context. In &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;, we incorporate these tests into our development cycles, allowing for thorough validation of policy implementations in a controlled yet realistic setting.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Automation of Testing Processes&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Automation plays a vital role in maintaining efficiency and consistency in testing. Automated tests can be configured to run as part of the CI/CD pipeline, ensuring that every change is vetted before it goes live. We suggest you consider the following triggers and hooks, which you can mix and match according to your needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The CI system deploys PDPs specifically for testing policy changes.&lt;/li&gt;
&lt;li&gt;Developers can trigger tests automatically through the CI system.&lt;/li&gt;
&lt;li&gt;Tests must pass before environments are merged; if tests fail, the CI system will not proceed with merging changes.&lt;/li&gt;
&lt;li&gt;The CI system uses APIs like Create/Copy-env to establish environments purely for testing purposes, guaranteeing that each test environment mirrors the target deployment scenario accurately.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Modeling and Implementation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Modeling and implementing a cloud-native fine-grained authorization system requires a structured approach. We suggest separating our implementation into a list of several planes, each focused on a different iteration of the SDLC and architecture levels. These planes—Application, Configuration, Data, and Enforcement—serve different functions, from handling user interactions to managing data security and enforcing policies. Let’s dive in -&lt;/p&gt;

&lt;h3&gt;
  
  
  The Application Plane
&lt;/h3&gt;

&lt;p&gt;The Application Plane serves as the foundational layer of the authorization layer, designed to align closely with common product architectures, integrating authorization directly into the software development life cycle (SDLC). Here’s how we modeled the key components of this plane in &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Workspaces/Organizations&lt;/strong&gt; : These act as the main namespace or administrative domain within the authorization system, analogous to a development organization in the SDLC. Generally, each account should have one workspace to maintain a clear organizational structure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Projects&lt;/strong&gt; : Projects within a workspace mirror products and can be thought of as equivalent to code repositories. Each project holds its unique configuration and policies driven by specific product requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environments&lt;/strong&gt; : Similar to branches in a code repository, environments within a project manage the deployment and testing of policies in different stages, such as development or production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Members&lt;/strong&gt; : These are the users involved in managing and operating the authorization system, including developers, security engineers, and product managers, who handle permissions and policy configurations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Flow and User Interaction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the SDLC timeline, the Application Plane is relatively static but critical as it establishes the policy management and deployment structure. Interaction with the Application Plane is facilitated through various methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User Interfaces (UIs)&lt;/strong&gt;: UIs allow non-technical stakeholders, such as product managers, to easily manage and navigate the structure of projects and environments. While costly to create, this type of accessibility is vital for fostering an inclusive environment where project configurations can be adjusted without deep technical knowledge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitOps Workflows&lt;/strong&gt; : GitOps provides a declarative way to manage infrastructure and configurations using Git. It allows for transparent version-controlled environments that align with DevOps practices, making it easier for teams to track changes and roll back if necessary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;APIs&lt;/strong&gt; : APIs offer developers the flexibility to manage projects and environments programmatically, integrate with existing CI/CD pipelines, and automate repetitive tasks. This is particularly useful for dynamically creating environments that align with feature branches or specific testing needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While developing these capabilities in-house can be resource-intensive and complex, our approach at Permit was to provide these capabilities out of the box, ensuring that developers can choose the most suitable method for their needs without the overhead of building and maintaining these systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Configuration Plane
&lt;/h3&gt;

&lt;p&gt;The Configuration Plane is central to defining and managing the rules and policies that govern access within an application. This plane is essentially about translating the complex requirements of permissions and roles into a structured, stateless configuration that integrates seamlessly with the application's codebase. Let’s go over this plane’s components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt;&lt;br&gt;
These are the various types of application assets requiring permission management. Each resource type specifies possible actions that users might undertake.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resource Relationships:&lt;/strong&gt; Descriptions of potential connections between resources to facilitate permission derivation.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Roles:&lt;/strong&gt;&lt;br&gt;
User roles within the application, both at the system and resource levels.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Role Derivations:&lt;/strong&gt; Mechanisms to extend permissions from one role to another by using relationships.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Attributes:&lt;/strong&gt; These are specifications that define the characteristics of resources and users, which can be used to set conditions for access permissions.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Condition sets&lt;/strong&gt;  - the ability to build conditions to match users or resources in a set. These conditions use the attribute configuration to configure &lt;code&gt;match&lt;/code&gt; conditions.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Policy:&lt;/strong&gt; These are the actual rules that determine whether access is allowed or denied based on roles, resources, and condition sets.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Custom Policies:&lt;/strong&gt; Advanced policy declarations using specific policy languages (like Rego or Cedar). Used mostly in very advanced use cases.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Fetchers:&lt;/strong&gt; These synchronize data from the application to the authorization system, crucial for maintaining current and applicable permission settings.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;URL Mapping:&lt;/strong&gt; This feature links API endpoints directly to resource definitions, streamlining the integration of authorization layers with application APIs.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Flow and User Interaction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Managing the Configuration Plane can be approached through multiple methods, each offering distinct advantages and catering to different organizational needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;UI&lt;/strong&gt; : Ideal for non-developer stakeholders such as product managers who need to configure permissions easily and visually. This method enhances accessibility and reduces complexity for users without deep technical knowledge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure as Code&lt;/strong&gt; : Organizations committed to a code-centric SDLC can manage permissions via tools like the Permit Terraform provider, integrating permission management directly into their development processes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raw Policy as Code&lt;/strong&gt; : For scenarios where customization needs exceed what is feasible through the UI, policies can be directly authored and managed in policy code files within version control systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As with the application plane, at &lt;a href="http://permit.io/" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;, we tried to enable developers to adopt the method that best fits their workflow. We support a hybrid approach, recommending the use of the UI for standard role-based and attribute-based access control configurations while accommodating more complex or stringent rules through custom policy code.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Data Plane
&lt;/h3&gt;

&lt;p&gt;As the configuration plane defines the application's authorization layer from the product requirement perspective, the data plane handles the dynamic elements of application data that influence policy decisions. It bridges the static configurations set in the Configuration Plane and the real-time enforcement of those policies in the Enforcement Plane. Let’s go over its components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Users&lt;/strong&gt; : The core element of the Data Plane, representing individuals who interact with the application. User data is often synchronized from identity providers that manage authentication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attributes&lt;/strong&gt; : Attributes associated with users can be pivotal in determining the outcome of policy decisions and influencing access control based on dynamic user data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tenants&lt;/strong&gt; : Representing groups of users, tenants facilitate segmented policy enforcement, similar to organizational units in traditional IAM systems or accounts in cloud-native architectures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role Assignments&lt;/strong&gt; : These define the relationships between users and their roles within the application and can extend to relationships between users and specific resource instances.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Instances&lt;/strong&gt; : These are specific instances of resources defined in the Configuration Plane, typically identified by unique identifiers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relationship Tuples&lt;/strong&gt; : These tuples create a graph of relationships between individual instances, aiding in the derivation of permissions between users and resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Flow and User Interaction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The management and synchronization of data within the Data Plane are continuous processes, tightly integrated with the application's lifecycle. Data can be handled in various ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API/SDK&lt;/strong&gt; : The most straightforward method for syncing data is through the integration of SDKs or direct API calls from within the application code. This approach ensures that data remains consistent with the application's state and development cycle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI&lt;/strong&gt; : Data can also be managed via a user interface, which is especially useful for non-developer stakeholders who need to interact with the data for configuration or testing purposes. However, direct manipulations in the UI should be used judiciously in production environments to maintain data integrity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy Engine APIs&lt;/strong&gt; : For advanced data synchronization scenarios, data fetchers or direct policy engine API calls can be used. These are particularly useful in large-scale environments where data needs to be consistently and automatically updated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="http://permit.io/" rel="noopener noreferrer"&gt;P&lt;/a&gt;&lt;a href="http://ermit.io" rel="noopener noreferrer"&gt;ermit.io&lt;/a&gt; supports API/SDK integrations and provides UI capabilities that allow for easy data manipulation and testing. For environments where data synchronization needs to be automated and consistent, we utilize its OPAL to link data directly with the policy engines, maintaining a single source of truth and enhancing the reliability of policy enforcement.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Enforcement Plane
&lt;/h3&gt;

&lt;p&gt;The Enforcement Plane is where all the preparatory work done in the other planes comes into action. It is the most dynamic aspect of a cloud-native authorization system, responsible for the real-time application of configured policies. This plane ensures that the authorization decisions, such as allowing or denying user actions, are enforced consistently and accurately across the application. Let’s go over how its components are modeled in Permit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check Function(&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;permit.check()&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;):&lt;/strong&gt;&lt;br&gt;
This is the core component of the Enforcement Plane in Permit. It evaluates whether a particular action by a user on a resource should be allowed or denied based on the policies. The function considers several elements to make this decision:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User&lt;/strong&gt; : Includes the user ID and, optionally, user attributes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action&lt;/strong&gt; : Specifies the operation the user is attempting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource&lt;/strong&gt; : Identifies the type or ID of the resource involved and, optionally, resource attributes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context&lt;/strong&gt; : Any additional data that might be relevant for evaluating the policy decision.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Filtering&lt;/strong&gt; : This function assists in filtering data according to the policy evaluation. It is particularly useful in applications where data visibility depends on user permissions, although it typically requires custom policy code to implement.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Local PDP APIs&lt;/strong&gt; : These APIs fetch necessary data from the local policy decision point to aid the application in making informed authorization decisions.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Flow and Integration&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The enforcement logic is embedded within the application code in the software development life cycle. It acts as the gatekeeper, controlling what users can or cannot do within the application based on the policies defined in earlier planes.&lt;/p&gt;

&lt;p&gt;At &lt;a href="http://Permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt;, enforcement is integrated using SDKs or by direct calls to the policy decision point. This integration allows developers to directly incorporate permission checks and data filtering mechanisms into the application flow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2Fresize%3Dwidth%3A3120%2Cheight%3A1960%2F8eN1LtDHTLCZYhVPMzMe" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2Fresize%3Dwidth%3A3120%2Cheight%3A1960%2F8eN1LtDHTLCZYhVPMzMe" title="Compressor.io authentication.png" alt="Cloud Native Authorization Component Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Crafting an effective cloud-native authorization system is a complex yet crucial task. Through our experience dealing with cloud-native authorization in &lt;a href="http://permit.io/" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt; and based on the way we modeled our own system, we have dissected the processes that contribute to building a strong authorization framework that is scalable, flexible, and secure.&lt;/p&gt;

&lt;p&gt;The integration of continuous integration and deployment (CI/CD), meticulous testing, and precise modeling are a must when it comes to developing an authorization system that not only meets the current demands but is also prepared for future challenges. Each component—from the Application Plane through to the Enforcement Plane—plays a vital role in ensuring that the system operates seamlessly and adheres to strict security standards.&lt;/p&gt;

&lt;p&gt;Whether you are a developer, a security engineer, or a product manager, understanding and implementing these facets will empower you to build and maintain a strong system.&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>tooling</category>
      <category>learning</category>
      <category>security</category>
    </item>
    <item>
      <title>45 Questions to Ask Yourself Before Modeling Authorization</title>
      <dc:creator>Gabriel L. Manor</dc:creator>
      <pubDate>Thu, 09 May 2024 13:00:00 +0000</pubDate>
      <link>https://dev.to/permit_io/45-questions-to-ask-yourself-before-modeling-authorization-21kb</link>
      <guid>https://dev.to/permit_io/45-questions-to-ask-yourself-before-modeling-authorization-21kb</guid>
      <description>&lt;p&gt;Authorization is part of every modern application, ensuring users can only access the resources they are permitted to. While this might sound rather straightforward, considering how complex modern applications are, ensuring the right people get the right access to the right places is far from easy.&lt;/p&gt;

&lt;p&gt;Before you start building, whether you are planning to build your own solution from scratch or use an existing authorization as a service solution, there are some crucial questions you must ask yourself when planning your implementation.&lt;/p&gt;

&lt;p&gt;We see these questions being asked repeatedly on Reddit, StackOverflow, and in &lt;a href="https://io.permit.io/permitslack" rel="noopener noreferrer"&gt;our own community&lt;/a&gt; dedicated to helping people build authorization systems. In order to make sure you have everything covered, we gathered them together in one place.&lt;/p&gt;

&lt;p&gt;It doesn't matter whether you're upgrading an existing authorization system (From monolith to microservices-based, for example) or &lt;a href="https://www.permit.io/blog/roll-your-own-rbac" rel="noopener noreferrer"&gt;creating an authorization for a new application from scratch&lt;/a&gt; - these are the most critical questions you should ask yourself before modeling your authorization implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Scope and Granularity (RBAC, ABAC, ReBAC):
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
What types of resources do you need to secure in your application (e.g., data, functions, services, APIs)?&lt;/li&gt;
&lt;li&gt;
Do your applications utilize resource hierarchies, organizational hierarchies, or ownership models? Are you able to easily model those (recursively) into your policies?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have an existing implementation -&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
How granular are the current permissions? Do you support role, attribute, or context-based access control?&lt;/li&gt;
&lt;li&gt;
Does your authorization layer support multi-tenancy as a first-class citizen?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first step in designing an authorization layer is determining the resources to which you need to manage access. Each type of resource and its place in the overall structure of your application might require you to utilize a different type of authorization model (RBAC, ABAC, ReBAC, or a combination of them).&lt;/p&gt;

&lt;p&gt;It is important that you &lt;a href="https://www.permit.io/blog/rbac-vs-abac-vs-rebac" rel="noopener noreferrer"&gt;familiarize yourself with the available policy models out there&lt;/a&gt;, their pros and cons, and try to assess which ones are the best fit for your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Policy Authoring: Involving Other Stakeholders
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Are non-technical stakeholders (e.g. Product, Security, Compliance, Sales, Support) able to participate in policy authoring? Should they? If so, to what extent?&lt;/li&gt;
&lt;li&gt;
Are end-customers able to customize their policies within your system (e.g. dynamically create roles, assign permissions, define hierarchies)?&lt;/li&gt;
&lt;li&gt;
Are you able to utilize &lt;a href="https://www.permit.io/blog/what-is-policy-as-code" rel="noopener noreferrer"&gt;policy as code&lt;/a&gt; as part of your authorization layer?&lt;/li&gt;
&lt;li&gt;
Are you able to utilize Infrastructure as code to define these policies?&lt;/li&gt;
&lt;li&gt;
How quickly can you deliver new policies to production? Seconds? Hours?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Authorization policies should be flexible and accessible while remaining secure. It is common for various stakeholders (Product, Security, Compliance, Sales, Support etc.) to require a certain level of access to your authorization layer, being able to author and edit policies, and having these policies take immediate effect in the system.&lt;/p&gt;

&lt;p&gt;Facilitating this need can’t come as an afterthought to building your authorization layer, and should be considered from day one. Utilizing Policy-as-code for this endeavor facilitates automation and integration into CI/CD pipelines, enabling faster deployment and iteration of policies while keeping all the best practices of code deployment in place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FmAQIIBOxTOurLMAIfvBC" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FmAQIIBOxTOurLMAIfvBC" title="Untitled (54).png" alt="Untitled (54).png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The&lt;/em&gt; &lt;a href="http://permit.io/" rel="noopener noreferrer"&gt;&lt;em&gt;Permit.io&lt;/em&gt;&lt;/a&gt; &lt;em&gt;UI allows you to define policy via a UI that generates policy as code for you in your language of choice.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. User and Data Management:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
How do you manage the synchronization of user identities and attributes across systems?&lt;/li&gt;
&lt;li&gt;
Can you consume external data sources to aid in the authorization decision process without creating dependencies (To systems that aren’t highly available, highly performant / low latency)?&lt;/li&gt;
&lt;li&gt;
What mechanisms manage user roles and hierarchies?&lt;/li&gt;
&lt;li&gt;
Is there a method of loading dynamic data (e.g. geo-location, quotes, billing) into the authorization system in place?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Effective user and data management ensures the authorization system is both accurate and responsive. Handling dynamic data efficiently can enhance the system's adaptability and responsiveness to real-time changes.&lt;/p&gt;

&lt;p&gt;This can be achieved by using tools like &lt;a href="https://github.com/permitio/opal" rel="noopener noreferrer"&gt;Open Policy Administration Layer&lt;/a&gt; (&lt;a href="https://github.com/permitio/opal" rel="noopener noreferrer"&gt;OPAL&lt;/a&gt;), which helps keep your authorization layer updated in real-time with data and policy updates. This OSS includes two important features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
OPAL allows tracking a specific policy repository (like GitHub, GitLab, or Bitbucket) for updates. It does this by either using a webhook or checking for changes every few seconds. This makes the system act as a Policy Administration Point (PAP), which sends the policy changes to your policy engine, ensuring it is always up to date.&lt;/li&gt;
&lt;li&gt;
The ability to track any relevant data source (API, Database, external service) for updates via a REST API, and fetch up-to-date data back into your policy engine.
Using these capabilities allows you to take advantage of the full benefits of policy languages by keeping your policy engines up to date with all the relevant policies and data in real-time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Policy Management:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
How are authorization policies managed and defined within your system?&lt;/li&gt;
&lt;li&gt;
Can policies react dynamically to contextual changes at runtime?&lt;/li&gt;
&lt;li&gt;
Is there a single source of truth for your policies?&lt;/li&gt;
&lt;li&gt;
How are policies tested, reviewed, and benchmarked? Can this be done as part of their authoring process?&lt;/li&gt;
&lt;li&gt;
Are you able to unify policies across different surfaces (gateways, proxies, middleware, code, DBs)?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A centralized management system helps maintain consistency and integrity of policies across all platforms. Dynamic policies that adapt to real-time data ensure that access control is always relevant and secure. Centralization of your policy decisions can be achieved by using Policy Engines such as &lt;a href="https://www.permit.io/blog/introduction-to-opa" rel="noopener noreferrer"&gt;Open Policy Agent&lt;/a&gt; vs &lt;a href="https://www.permit.io/blog/everything-you-need-to-know-about-aws-cedar-policy-language" rel="noopener noreferrer"&gt;AWS Cedar&lt;/a&gt;. It is important to choose the &lt;a href="https://www.permit.io/blog/policy-engines" rel="noopener noreferrer"&gt;policy engine&lt;/a&gt; and &lt;a href="https://www.permit.io/blog/opa-cedar-openfga-why-are-policy-languages-trending" rel="noopener noreferrer"&gt;policy language&lt;/a&gt; that best suits your needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Auditing and Compliance: Tracking and Simplification
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
How do you track and log access decisions?&lt;/li&gt;
&lt;li&gt;
Can you aggregate and search audit logs effectively?&lt;/li&gt;
&lt;li&gt;
Are you able to track decision paths for audit logs?&lt;/li&gt;
&lt;li&gt;
Is your audit log aggregation retaining logs in a way that matches your policy requirements?&lt;/li&gt;
&lt;li&gt;
Does your system simplify compliance with standards like HIPAA, GDPR, and PCI?&lt;/li&gt;
&lt;li&gt;
Are there tools in place to analyze access patterns and detect anomalies on top of audit logs?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quality &lt;a href="https://www.permit.io/blog/audit-logs" rel="noopener noreferrer"&gt;logging and auditing capabilities&lt;/a&gt; are essential for compliance and security. They help track access patterns and detect anomalies, ensuring that your application meets regulatory standards and effectively manages risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. &lt;strong&gt;Integration and Scalability: Preparing for Growth&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
How does your authorization system integrate with other infrastructure components?&lt;/li&gt;
&lt;li&gt;
Is the system scalable to meet the growth of your application?&lt;/li&gt;
&lt;li&gt;
What is the impact of changing your policy model (&lt;a href="https://www.permit.io/blog/from-rbac-to-rebac-and-abac-with-nextjs-and-permitio" rel="noopener noreferrer"&gt;RBAC to ABAC&lt;/a&gt;, for example) on your engineering resources?&lt;/li&gt;
&lt;li&gt;
Do you practice &lt;a href="https://www.permit.io/blog/what-is-policy-as-code" rel="noopener noreferrer"&gt;decoupling of policy and code&lt;/a&gt;?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A well-integrated system reduces maintenance overhead and avoids bottlenecks as your application scales. Consider the long-term impact of potential system changes to ensure sustainability.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. &lt;strong&gt;Performance and Reliability: Ensuring High Availability&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
What impact does the authorization system have on application performance?&lt;/li&gt;
&lt;li&gt;
What percentage of this impact is due to latency to the authorization service or dependent data sources?&lt;/li&gt;
&lt;li&gt;
How do you ensure the service’s reliability and availability?&lt;/li&gt;
&lt;li&gt;
Is the information &lt;a href="https://www.permit.io/blog/what-is-token-based-authentication" rel="noopener noreferrer"&gt;stored in your JWTs limited to identity-bound data points&lt;/a&gt;?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Minimizing latency and maximizing reliability are critical for maintaining user satisfaction and trust. Efficient performance management ensures that security measures do not impede the application’s responsiveness.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Security and Risk Management: Safeguarding Access
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
What security measures protect your authorization data?&lt;/li&gt;
&lt;li&gt;
How do you manage breach detection and response to unauthorized access?&lt;/li&gt;
&lt;li&gt;
Are there access controls and logs for changes to access management?&lt;/li&gt;
&lt;li&gt;
Do you have audit logs on who can change your access control?&lt;/li&gt;
&lt;li&gt;
Is the lifespan of your JWTs less than a minute? Or at least less than 10 minutes?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having &lt;a href="https://devops.com/watching-the-watchers-solving-the-problem-of-meta-permissions/" rel="noopener noreferrer"&gt;an authorization layer that monitors access to the app’s authorization layer&lt;/a&gt; is crucial. It prevents unauthorized changes from being made to the authorization layer and ensures that any potential breaches are quickly identified and addressed.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Technology and Tooling: Leveraging the Best Tools
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
What external libraries, frameworks, or services are you using for authorization?&lt;/li&gt;
&lt;li&gt;
What are the current tools and solutions for authentication? Are you able to leverage all your authentication and identity claims in your authorization layer with ease? Are you easily able to support attributes coming from external identity providers?&lt;/li&gt;
&lt;li&gt;
What are the limitations of your current tooling?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choosing the right technology stack for authorization and authentication can greatly affect both the system's effectiveness and the developer's ease of implementation. Understanding the limitations of current tools can guide future improvements and integrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;10. Future-Proofing: Staying Ahead with Continuous Improvement&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
How do you ensure your authorization system remains up-to-date with the latest security practices?&lt;/li&gt;
&lt;li&gt;
Are you able to quickly adapt your authorization strategies to accommodate new technologies and changing regulatory requirements?&lt;/li&gt;
&lt;li&gt;
What processes do you have in place for continuous assessment and improvement of your authorization system?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The IAM landscape, as well as the potential security risks involved are constantly changing. This means we must keep our system current and adaptable. Implementing a process for ongoing assessment and improvement can help address emerging security challenges and incorporate advancements in technology. Regular updates, guided by the latest security research and compliance demands, ensure that your system not only meets current standards but is also prepared for future requirements. This approach reduces vulnerabilities and ensures that your authorization system evolves in step with both technological innovations and changes in the regulatory environment.&lt;/p&gt;

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

&lt;p&gt;Building and managing an effective authorization system requires a thoughtful approach that balances security, usability, and performance. By considering these detailed questions, you can ensure your authorization system is strong, compliant, and ready for the challenges of modern application development.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>security</category>
      <category>architecture</category>
      <category>microservices</category>
    </item>
    <item>
      <title>OPA, Cedar, OpenFGA: Why are Policy Languages Trending Right Now?</title>
      <dc:creator>Gabriel L. Manor</dc:creator>
      <pubDate>Thu, 02 May 2024 18:00:00 +0000</pubDate>
      <link>https://dev.to/permit_io/opa-cedar-openfga-why-are-policy-languages-trending-right-now-g7e</link>
      <guid>https://dev.to/permit_io/opa-cedar-openfga-why-are-policy-languages-trending-right-now-g7e</guid>
      <description>&lt;p&gt;You might have noticed a rising trend lately - Policy languages like OPA, Cedar, and OpenFGA are being increasingly used in Identity and Access Management (IAM) to manage complex authorization requirements. Join us as we explore the challenges faced in authorization, the solutions provided by policy languages, and the benefits of using them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Policy Languages are on the Rise
&lt;/h2&gt;

&lt;p&gt;Domain-specific declarative languages have been a huge part of software development since its early days. They were created to tackle the complexities and requirements general-purpose programming languages struggled to manage and are now a part of every developer's toolkit.&lt;/p&gt;

&lt;p&gt;In Identity and Access Management (IAM), &lt;strong&gt;authorization&lt;/strong&gt; is becoming increasingly challenging in recent years - apps are getting more complex, as are user requirements. The result? &lt;strong&gt;a huge surge in domain-specific declarative languages focused on authorization&lt;/strong&gt;. Older languages, such as Open Policy Agent’s Rego, are getting a facelift &lt;a href="https://www.permit.io/blog/whats-new-on-opa-v1" rel="noopener noreferrer"&gt;with their upcoming V1&lt;/a&gt;, and new languages and platforms like OpenFGA and, more recently, &lt;a href="https://www.permit.io/blog/oss-aws-cedar-is-a-gamechanger-for-iam" rel="noopener noreferrer"&gt;AWS’ Cedar&lt;/a&gt;, are being created.&lt;/p&gt;

&lt;p&gt;It’s quite clear that significant steps are being made to tackle authorization’s ever-growing complexity. In this blog, we’ll talk about why these policy languages are rising in popularity, and how you can use them to your advantage to build better, more secure applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge of Fine-Grained Decisions
&lt;/h2&gt;

&lt;p&gt;There’s a new problem in the software development world: the problem of &lt;strong&gt;decisions&lt;/strong&gt;. Decisions are obviously not a new issue - it’s one of the most basic aspects of software development, and simple ‘if’ statements are at the very foundation of any programming language out there. But in the vast majority of cases, that’s not enough.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FnLLAxpF6ROur57G4MeIl" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FnLLAxpF6ROur57G4MeIl" title="Untitled (50).png" alt="Untitled (50).png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many modern applications require extremely fine-grained decisions to be made, especially regarding security matters in authorization (handling what a user or service can or cannot do in your application). Let’s briefly go over these challenges:&lt;/p&gt;

&lt;h3&gt;
  
  
  Application Architecture
&lt;/h3&gt;

&lt;p&gt;Working as a developer back in 2010, you could easily imagine having one server, one programming language, one database, and one application. Today, even the most basic apps start tons of services from the get-go, yet we still don’t want users to access data that they're not supposed to. This means all of these services need to have one concrete source of truth for their decision-making, and these decisions have to be streamlined across the entire stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Points and Decision Fatigue
&lt;/h3&gt;

&lt;p&gt;In LAMP or older architectures, we used to have one SQL database. Even the simplest apps today use multiple data sources, which are only growing more complex by the minute. All of this data still needs to adhere to the same level of security when in comes to making decisions. That means the way of making these decisions is also growing increasingly complex.&lt;/p&gt;

&lt;p&gt;The more data we have, the more decisions we need to make, and the more data needs to be included in that decision-making process. At some point, it gets too complex, and we can’t keep supporting more and more granularity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Velocity and Frameworks
&lt;/h3&gt;

&lt;p&gt;We’re delivering more software. That means more endpoints and more production environments that just keep growing. This creates the need for a layer we can trust to always make the right decision when it comes to access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Confidence - Not Just End-Users Anymore
&lt;/h3&gt;

&lt;p&gt;Users of modern-day applications are significantly more security aware. They want to own their data and manage its privacy, and you need to support that. That means supporting very fine-grained ownership, temporary data access functions, location-based access policies; you name it. On the other hand, app users are not really users in the classic sense anymore. Think DevOps, RevOps, and AppSec - they all want access to the code, and they affect the way that software should be delivered. Above all else, they affect how access decisions should be made.&lt;/p&gt;

&lt;p&gt;And all of that complexity doesn't include the newest player on the block - AI Agents and LLMs. These create a problem of unstructured decisions, as they want unstructured access to our data - how do we provide them with the right access&lt;/p&gt;

&lt;p&gt;This long list of challenges requires more complex solutions than what can be achieved with ‘if’ statements hard coded into your application. That’s where policy engines and policy languages come in.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution? Structure and Domain-Specific Declarative Code
&lt;/h2&gt;

&lt;p&gt;Now that wev’e gained a better understanding of the problem, - let’s talk solutions.&lt;/p&gt;

&lt;p&gt;The first step to solving this challenge is understanding where all these complex decisions should be made. This can be achieved by mapping out our application into a few authorization layers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2Fx3LqftTvuXiJvTX0fsAu" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2Fx3LqftTvuXiJvTX0fsAu" title="Untitled (51).png" alt="Untitled (51).png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The most basic layer is the &lt;strong&gt;code itself&lt;/strong&gt;. Developers today have a lot of effect on how code is delivered and what production looks like. So the first decision that needs to be made is, basically put, “What can the developer do?”&lt;/li&gt;
&lt;li&gt;Then there are the &lt;strong&gt;services&lt;/strong&gt;. Here there are the questions of “Which service can talk to other services?”, “How are they deployed in the CI/CD and speak with each other”?&lt;/li&gt;
&lt;li&gt;Above that is the application database. Here, we need to make the decision of “Who can read what from the database?”&lt;/li&gt;
&lt;li&gt;On top of that, there’s the application backend, where we need to decide “What actions can application users perform?”&lt;/li&gt;
&lt;li&gt;On top of everything else, we have the frontend, where we need to ask ourselves, “What can our application users see?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With a clear structure of where authorization decisions should be made, it’s easier for us to design a solution that can actually handle them. To do that, we can use two important architectural principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Centralized Policy Configuration:&lt;/strong&gt; consolidating all our configuration in one place will help us streamline it and ensure that we're following all the standards we're trying to establish.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy Engines:&lt;/strong&gt; The Policy Engine is in charge of evaluating authorization queries, using the policy rules as a source of truth. Authorization policies are written in Policy Languages, which the policy engine interprets, providing a decision to any authorization query it is presented with. Having a piece of software that knows how to take the policies we configure and make the right decisions is a must.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This plane needs to be decentralized for several reasons: First, it has to react super fast, and second, we want every part of our stack to be able to communicate with this plane directly and enforce permissions based on these decisions.&lt;/p&gt;

&lt;p&gt;Now that we've identified the need for using a decentralized authorization engine let’s dive deeper into the language these engines utilize to process and handle authorization queries - Policy Languages.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Policy Languages?
&lt;/h2&gt;

&lt;p&gt;A policy language is a formal and structured way of defining rules, conditions, and logic for specifying policies. It provides a standardized syntax and semantics for expressing authorization rules and access control requirements, making it easier to manage and enforce security policies. There are many different policy languages, such as OPA’s Rego, AWS’ Cedar, OSO’s Polar, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Benefit of Using Policy Languages
&lt;/h2&gt;

&lt;p&gt;The benefits of using Domain-Specific Declarative languages can help us overcome these challenges thanks to the benefits of having &lt;a href="https://docs.permit.io/integrations/gitops/overview/#policy-as-code" rel="noopener noreferrer"&gt;policy as code&lt;/a&gt; -&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;They are &lt;strong&gt;readable.&lt;/strong&gt; When you look at policy as code written in languages intended for authorization policies, you should immediately understand what is happening - who can do what, on what, and when.&lt;/li&gt;
&lt;li&gt;They improve performance. As all decisions are made in a single domain, nothing is in their way of being made and delivered with no latency.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Not only that - defining policies using code provides you with the ability to ensure policies are consistently enforced across different systems and environments, which can help prevent policy violations and reduce the risk of unauthorized access. It allows you to easily manage and update policies, as you do that with the same tools and processes used to manage and deploy software. This makes it easier to track changes to policies over time, roll back changes if necessary, and in general, enjoy the well-thought-through best practices of the code world (e.g., GitOps).&lt;/p&gt;

&lt;h2&gt;
  
  
  What Policy Languages are there?
&lt;/h2&gt;

&lt;p&gt;There are many policy languages available to choose from, each more fit to handle different scenarios:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2Fdml2XLdCS7uOPu1h8IQo" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2Fdml2XLdCS7uOPu1h8IQo" title="Untitled (52).png" alt="Untitled (52).png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Open Policy Agent (OPA) - Rego
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prolog"&gt;&lt;code&gt;&lt;span class="ss"&gt;allow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;role&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"viewer"&lt;/span&gt;
    &lt;span class="ss"&gt;validate_department&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="ss"&gt;validate_classification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;classification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="ss"&gt;validate_dynamic_rules&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="ss"&gt;validate_department&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;department&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;department&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="ss"&gt;validate_classification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;user_role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;doc_classification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;role_permissions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;user_role&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;doc_classification&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="ss"&gt;validate_dynamic_rules&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;dynamic_rules&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="ss"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;document&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;OPA started out as a multi-purpose policy engine, and that’s where its power comes from. It’s an extremely flexible language that can help you model any type of decision you want. The thing is, Rego can get quite complicated - it's not the perfect example of a declarative language being simple and intuitive, but it does provide you with the ability to handle extremely complex decisions on any layer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FEoPa9JW2RwW3XfT8f23y" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FEoPa9JW2RwW3XfT8f23y" title="Untitled (53).png" alt="Untitled (53).png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have the ability to learn this new language, and you want to have one agent with one policy language across the stack, Open Policy Agent is a great choice.&lt;/p&gt;

&lt;p&gt;Read more about it here: &lt;a href="https://www.permit.io/blog/implement-rbac-using-opa" rel="noopener noreferrer"&gt;RBAC with Open Policy Agent (OPA)&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS’ Cedar
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;permit &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;principal&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;PhotoApp&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stacey&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;PhotoApp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;viewPhoto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;resource&lt;/span&gt;
 &lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="nx"&gt;when&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;PhotoApp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stacey&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;&lt;a href="https://www.permit.io/blog/oss-aws-cedar-is-a-gamechanger-for-iam" rel="noopener noreferrer"&gt;Launched by AWS just one year ago&lt;/a&gt;, Cedar’s started as a language dedicated language for application-level authorization. Unlike AWS IAM, it's a language that can be used in any application. Cedar uses the Dafny language to provide scientific proof of correctness and performance, yet it is still challenging to use it when dealing with unstructured data, and it lacks ReBAC support. It’s a great option to use for fast ABAC based decisions, with auditing, static analysis, and partial evaluation supported out of the box.&lt;/p&gt;

&lt;p&gt;Read more about it here: &lt;a href="https://www.permit.io/blog/cedar-rbac" rel="noopener noreferrer"&gt;RBAC With AWS’ Cedar&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenFGA
&lt;/h3&gt;

&lt;p&gt;Not a policy language per-se, but more of an authorization platform based on &lt;a href="https://www.permit.io/blog/zanzibar-vs-opa" rel="noopener noreferrer"&gt;Google’s Zanzibar white paper&lt;/a&gt;, OpenFGA is a great choice when it comes to handling ReBAC. Backed and maintained by Auth0 and used by them for authorization, with a graph-based engine built-in, it is the perfect solution for large-scale authorization implementations. OpenFGA is less suitable when it comes to RBAC and ABAC.&lt;/p&gt;

&lt;p&gt;You can learn more about how it compares with Cedar here: &lt;a href="https://www.youtube.com/watch?v=sG2OUXes8Hs&amp;amp;t=1s" rel="noopener noreferrer"&gt;OpenFGA&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A broader overview and comparison of all three languages can be found here: &lt;a href="https://www.permit.io/blog/policy-engines" rel="noopener noreferrer"&gt;How Open Policy Agent compares to AWS Cedar and Google Zanzibar&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What do Policy Engines Lack?
&lt;/h2&gt;

&lt;p&gt;While policy languages and engines provide us with a great basis for creating a separate microservice for authorization, both OPA and Cedar lack several key abilities. Let’s look at an example -&lt;/p&gt;

&lt;p&gt;Say our policy requires a user to be a subscriber to see parts of our site. To make a policy decision, we need to know the user’s &lt;strong&gt;subscription status&lt;/strong&gt; from our &lt;strong&gt;billing service&lt;/strong&gt; (e.g. PayPal or Stripe) and &lt;strong&gt;be immediately aware of any changes to it&lt;/strong&gt; : a new subscriber expects immediate access to our site, and a churned user should lose access on the spot.&lt;/p&gt;

&lt;p&gt;That means our policy engine needs to be updated in &lt;a href="https://www.permit.io/blog/introduction-to-opal" rel="noopener noreferrer"&gt;&lt;strong&gt;real time&lt;/strong&gt;&lt;/a&gt;, from &lt;strong&gt;outside data sources&lt;/strong&gt; , while all of our &lt;strong&gt;decentralized policy engines are in sync&lt;/strong&gt; with each other.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/permitio/opal" rel="noopener noreferrer"&gt;&lt;strong&gt;Open Policy Administration Layer (OPAL)&lt;/strong&gt;&lt;/a&gt; is an OSS project created to aid with Policy Engine management, which keeps them updated in real-time with data and policy updates. Supporting both OPA and AWS’ Cedar, OPAL offers two important features:\&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
OPAL allows tracking a specific policy repository (like GitHub, GitLab, or Bitbucket) for updates. It does this by either using a webhook or checking for changes every few seconds. This makes the system act as a Policy Administration Point (PAP), which sends the policy changes to your policy engine, ensuring it is always up to date.&lt;/li&gt;
&lt;li&gt;
The ability to track any relevant data source (API, Database, external service) for updates via a REST API, and fetch up-to-date data back into your policy engine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using these capabilities allows you to take advantage of the full benefits of policy languages by keeping your policy engines up to date with all the relevant policies and data in real time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Please consider supporting this open-source project by &lt;a href="https://github.com/permitio/opal" rel="noopener noreferrer"&gt;giving OPAL a star on GitHub&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;Domain-specific declarative languages are proving to be crucial tools in managing complex tasks in software development. They help us build systems that are high-performing, secure, and user-friendly. Whether it's managing fine-grained access controls or adapting to the demands of AI agents, these languages are keeping us ahead of the curve.&lt;/p&gt;

&lt;p&gt;Authorization is a critical component of any modern application, and we can see the tremendous benefit brought to this space with domain-specific declarative languages. Open Policy Agent (OPA), AWS' Cedar, and OpenFGA allow us to tackle the challenges that come with the modern state of IAM, while OPAL (Open Policy Administration Layer) enhances their functionality by automating the synchronization between the policy store and the real-time data required for decision-making, ensuring that policies are consistently applied with the latest relevant data. This integration enables us to create secure, reliable, and dynamic authorization systems that can adapt to changing conditions and requirements.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>news</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Authentication is Not Enough: Here's Your Auth Roadmap for 2024</title>
      <dc:creator>Gabriel L. Manor</dc:creator>
      <pubDate>Wed, 27 Dec 2023 11:30:00 +0000</pubDate>
      <link>https://dev.to/permit_io/top-5-access-control-features-you-should-implement-in-2024-4e7p</link>
      <guid>https://dev.to/permit_io/top-5-access-control-features-you-should-implement-in-2024-4e7p</guid>
      <description>&lt;p&gt;Reflecting on the technological advancements of 2023, it was a remarkable year for software developers. Notably, the introduction of tools like Co-pilot has exponentially expedited development speed, while AI agents and vector databases have been effectively processing massive amounts of data for meaningful insights. Moreover, &lt;a href="https://vercel.com/resources/the-frontend-cloud-advantage"&gt;frontend clouds&lt;/a&gt; have revolutionized the deployment process, enabling full-stack applications to be launched in mere minutes.&lt;/p&gt;

&lt;p&gt;Building on these advancements, our prediction for 2024 is a continued focus on security and reliability. Specifically, we forecast the implementation of robust features that will secure and support the evolution of these remarkable trends into our applications.&lt;/p&gt;

&lt;p&gt;In the following article, we will delve into one of the most fundamental areas in user experience and security, access control, and find the five new features we should implement in 2024 to benefit the most from the amazing capabilities of applications nowadays.&lt;/p&gt;

&lt;h2&gt;
  
  
  Passkeys Authentication
&lt;/h2&gt;

&lt;p&gt;Passwords have not been considered a secure method to verify identities for many years now. Not only have brute-force techniques become easy to apply even for complex passwords with modern methodologies, but the nature of users using one key for all their applications also makes it a bad pattern for secure applications.&lt;/p&gt;

&lt;p&gt;Over the last decade, Multi-Factor Authentication (MFA) has attempted to address the security issues associated with passwords by requiring users to verify their identity using an additional factor. While MFA initially held great promise, by 2023, &lt;a href="https://en.wikipedia.org/wiki/Multi-factor_authentication_fatigue_attack"&gt;MFA fatigue attacks&lt;/a&gt; had become a significant attack surface, and MFA was no longer considered the most secure method.&lt;/p&gt;

&lt;p&gt;Besides the security issues, passwords with MFA are also considered a bad user experience. They need to remember multiple passwords (or have weak security), insert them many times, and use a device as another factor for authentication. Passkeys authenticate users with a method that proves their identity with biometrics or physical devices.&lt;/p&gt;

&lt;p&gt;In 2023, &lt;a href="https://webauthn.io/"&gt;WebAuthn&lt;/a&gt;, an open standard for &lt;a href="https://www.passkeys.io/"&gt;passkeys&lt;/a&gt; and biometric authentication, was adopted by all the main application platforms, including all modern browsers and mobile devices. The WebAuthn standard paved the way for every application developer to adopt passkeys as an authentication method.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--J1vWExiX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/GCTGiqQHqEePjrzxoxaA" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--J1vWExiX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/GCTGiqQHqEePjrzxoxaA" alt="Untitled (1).png" title="Untitled (1).png" width="800" height="646"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using &lt;a href="https://github.com/teamhanko/docs"&gt;open-source tools&lt;/a&gt; like &lt;a href="http://www.hanko.io/"&gt;Hanko.io&lt;/a&gt; can help you &lt;a href="https://www.permit.io/blog/better-access-control-with-passkeys-and-fine-grained-authorization"&gt;implement passkeys into any application&lt;/a&gt; in a matter of minutes. With WebAuthn and Hanko, you can ensure your application provides an amazing and secure experience for all your users in 2024.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fine-Grained Authorization
&lt;/h2&gt;

&lt;p&gt;The amount of data we process in our applications is growing exponentially every day. One of the challenges with data of any size is managing who can perform operations on it, or in other words, &lt;a href="https://www.permit.io/blog/authentication-vs-authorization"&gt;authorizing users&lt;/a&gt; in our applications.&lt;/p&gt;

&lt;p&gt;The complexity of authorization with large amounts of data has two aspects&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
From the decision-making perspective, much more data is involved in our decisions. For example, to decide the permissions of a subset of data, we need to consider the time it was created, the users who are related to it, and more. All of that makes authorization decisions more complex than ever.&lt;/li&gt;
&lt;li&gt;
From the permissions perspective, we need to obtain high granularity on the permission levels we get on the data. For example, we want to give someone access to file metadata, but not to its content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While the &lt;a href="https://www.permit.io/blog/roll-your-own-rbac"&gt;traditional Role-Based Access Control (RBAC)&lt;/a&gt; used to be the de-facto authorization capability of applications, the amount of data and the challenges we encounter cannot fit into the simple roles we assign to users. This is where Fine-Grained authorization comes into the picture.&lt;/p&gt;

&lt;p&gt;Fine-grained authorization combines advanced approaches such as &lt;a href="https://www.permit.io/blog/what-is-rebac"&gt;Relationship-Based Access Control (ReBAC)&lt;/a&gt; and &lt;a href="https://www.permit.io/blog/what-is-attribute-based-access-control"&gt;Attribute Based Access Control (ABAC)&lt;/a&gt; to provide the granularity that modern applications with complex data deserve.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  Please Support Us
&lt;/h3&gt;

&lt;p&gt;If you find this post helpful,&lt;a href="https://github.com/permitio/opal"&gt;please give OPAL a star on GitHub&lt;/a&gt;! Your support helps us make access control easier and motivates us to write more articles like this one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xInLC-dM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/0KCya41tQG6SDBDCx73T" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xInLC-dM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/0KCya41tQG6SDBDCx73T" alt="88f6wm.jpg" title="88f6wm.jpg" width="697" height="500"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, ReBAC leverages the relationships between data entities to evolve the static RBAC model into a dynamic one, deriving permissions between entities. In ABAC, &lt;a href="https://www.permit.io/blog/how-to-implement-abac"&gt;we use data attributes&lt;/a&gt; to construct conditions that enable detailed decision-making for authorization.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example of RBAC/ABAC/ReBAC&lt;/em&gt; &lt;a href="https://www.permit.io/blog/building-healthcare-authorization-nextjs"&gt;&lt;em&gt;usage in one healthcare permissions model&lt;/em&gt;&lt;/a&gt; &lt;em&gt;👇🏻&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--u01YlU5J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/YK8SHDPxTqWrgZ6CqeLx" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u01YlU5J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/YK8SHDPxTqWrgZ6CqeLx" alt="Untitled (2).png" title="Untitled (2).png" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Implementing fine-grained authorization has become essential for every application, and you should prioritize it in 2024.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decouple Policy from Code
&lt;/h2&gt;

&lt;p&gt;The most trending cloud-native field in 2023 was the "frontend" cloud. Services for edge computing, such as Vercel Edge and Railway, provide an efficient way for developers to deploy comprehensive full-stack web applications to a fully managed cloud environment in record time. This trend is simply a continuation of our application's nature to exist in small, autonomous environments, separate from each other.&lt;/p&gt;

&lt;p&gt;While the separation of concerns and modern distributed architectures are great for rapid development, it's challenging to ensure our security standards are streamlined across all applications. To assist with the authorization aspect, we need to decouple policy from code.&lt;/p&gt;

&lt;p&gt;In the decoupling pattern, instead of using imperative code to write authorization conditions in the application code, we use dedicated languages or standards to declare centralized policy rules in one policy store. All the distributed applications enforce their permissions using these streamlined policy rules.&lt;/p&gt;

&lt;p&gt;Another approach that has been gaining traction lately is using &lt;a href="https://www.permit.io/blog/zanzibar-vs-opa"&gt;policy as a graph&lt;/a&gt;. This is similar to the concept of &lt;a href="https://www.permit.io/blog/opa-vs-cedar"&gt;Policy as Code&lt;/a&gt;, but incorporates a graph DB into the mix. This graph DB contains all the nodes as resources and users, while the edges determine the dynamic permission derivations. This approach is primarily relevant to the ReBAC model we discussed earlier.&lt;/p&gt;

&lt;p&gt;In 2023, AWS announced its first application policy language, &lt;a href="https://www.permit.io/blog/oss-aws-cedar-is-a-gamechanger-for-iam"&gt;Cedar&lt;/a&gt;, which paved the way for giants to join the party and use the decoupling pattern as the best practice for application authorization. Cedar allows application developers to adopt &lt;a href="https://www.permit.io/blog/scaling-authorization-with-cedar-and-opal"&gt;Policy as Code and implement fine-grained authorization&lt;/a&gt; into their applications without the hassle of creating complex policies.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Here's an example of how Cedar code combines RBAC and ABAC.&lt;/em&gt; 👇🏻&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;principal&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;writer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;put&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;ResourceType&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;article&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;when&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;karma&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="nx"&gt;has&lt;/span&gt; &lt;span class="nx"&gt;published&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;published&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;false&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;Another tool that can help you deploy a Policy as Code-based solution in 2024 is &lt;a href="https://github.com/permitio/opal"&gt;OPAL, the Open Policy Administration Layer&lt;/a&gt;. OPAL is an open-source project that provides a comprehensive policy-based service for applications. With one click, &lt;a href="https://www.permit.io/blog/access-control-scary-to-simple"&gt;you can deploy a full architecture&lt;/a&gt; of a Git-based centralized policy store with decentralized policy engines running as a sidecar with your applications. OPAL also provides a unified architecture to sync all the data you need with the policy engines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WwIE6TNE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/KsYVbqKfTdOpX27EHaiz" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WwIE6TNE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/KsYVbqKfTdOpX27EHaiz" alt="Untitled (3).png" title="Untitled (3).png" width="800" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Better Audit Logs
&lt;/h2&gt;

&lt;p&gt;2023 was a year of diversity, not only in the workforce but also in our application identities. Besides users, our application now has access to many computer-based identities, such as AI agents, bots, and more. Even our application code is accessible by co-pilots, CI/CD automation, etc.&lt;/p&gt;

&lt;p&gt;A fundamental requirement for stable access control is audit logs, often referred to as the recurring &lt;code&gt;this.audit({…})&lt;/code&gt; code snippet that should be placed wherever an authorization decision occurs. Given the diversity of identities accessing our applications, &lt;a href="https://www.permit.io/blog/audit-logs"&gt;these logs require special attention&lt;/a&gt;. We must ensure that at any given time, we can precisely audit who has access to which resource in our applications.&lt;/p&gt;

&lt;p&gt;Modern policy engines and policy-as-code architectures solve many aspects of audit log challenges. First, they allow developers to define a single location where all the authorization audit logs are logged. Second, since all the policy rules are configured in the same way, the logs can provide much more data with no extra effort.&lt;/p&gt;

&lt;p&gt;Besides that, Policy as Code architectures provide logging of all the changes in authorization. It starts with configuration changes that are logged in the same format, continues with versions and data updates, and then the application decisions themselves.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F0JRJ2jA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/JC4fGi0R86Zpw3eRixGQ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F0JRJ2jA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/JC4fGi0R86Zpw3eRixGQ" alt="Untitled (4).png" title="Untitled (4).png" width="800" height="557"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using a policy-as-code system can provide you with what you need to start improving audit logs in your applications in 2024.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approval Flows
&lt;/h2&gt;

&lt;p&gt;In the early days of applications, permissions were only in a Mandatory Access Control (MAC) model, which meant the application developer was the only one to assign permissions to users. The modern web replaces MAC with Discretionary Access Control (DAC), which allows users to assign permissions to themselves and to other users.&lt;/p&gt;

&lt;p&gt;The rise of AI and cloud-native architectures in 2023 pushed the DAC to a new limit. Users now need to assign permissions for scopes of data that are unknown to the application developer. For example, users now want the ability to give access to third-party AI applications that are unknown to developers, and they want to define the scope of the data to which they are allowing access. The best way to deal with this is through policy-based approval flows.&lt;/p&gt;

&lt;p&gt;In a well-structured approval flow, the developer defines the tasks or the flow of permissions in the form of request → approve (or partial approve) → policy change. Using &lt;a href="https://www.youtube.com/watch?v=FkKpmkpVvVc&amp;amp;list=PLt_dDry66sLxvPjidOxhyLpZJx4Me4Kol&amp;amp;index=1&amp;amp;pp=iAQB"&gt;policy as code, this configuration is not coupled to a particular configuration or data&lt;/a&gt;. For example, a developer defines a method for users to approve other users to access their data by dynamically generating new policy rules into the policy engine.&lt;/p&gt;

&lt;p&gt;In our work in 2023, we found that Approval Flows are one of the &lt;a href="https://youtu.be/AKD6pXmIgEY"&gt;most requested features&lt;/a&gt; by our users for their applications. Our perspective is that 2024 will be full of ideas and work around defining and designing smart approval flows for applications.&lt;/p&gt;

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

&lt;p&gt;The list you just read summarizes the work we did at &lt;a href="http://permit.io/"&gt;Permit.io&lt;/a&gt; with Application Developers in 2023. As the leader in end-to-end solutions for application authorization as a service, we have experience with various types of applications and engineering teams around authorization and access control.&lt;/p&gt;

&lt;p&gt;If you plan to implement improved access control in your application in 2023, we encourage you to open a free account on &lt;a href="https://app.permit.io/"&gt;the Permit.io platform&lt;/a&gt; and try our solutions for fine-grained authorization. Our service is based on policy-as-code and a decentralized architecture, and our audit logs are industry-leading.&lt;/p&gt;

&lt;p&gt;In the meantime, you can join our &lt;a href="//io.permit.io/medium-slack"&gt;Authorization Slack community&lt;/a&gt;, where we chat and collaborate on day-to-day access control challenges. See you there.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>security</category>
    </item>
    <item>
      <title>How Reddit Built Authorization with OPA</title>
      <dc:creator>Gabriel L. Manor</dc:creator>
      <pubDate>Mon, 18 Dec 2023 18:30:00 +0000</pubDate>
      <link>https://dev.to/permit_io/how-reddit-built-authorization-with-opa-143n</link>
      <guid>https://dev.to/permit_io/how-reddit-built-authorization-with-opa-143n</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Effectively managing Authorization in Advertising Technology (Ad Tech), is a complex and crucial task. Tackling this challenge,  *&lt;em&gt;Reddit *&lt;/em&gt; developed an advanced authorization system for its advertising platform, a process described in great detail by Staff Engineer Braden Groom&lt;a href="https://www.reddit.com/r/RedditEng/comments/13vttm8/evolving_authorization_for_our_advertising/"&gt;&lt;u&gt; in this Reddit post&lt;/u&gt;&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Inspired by Braden’s post, this blog explores the journey of Reddit's team, focusing on their strategic decisions, the challenges they encountered, and the innovative solutions they crafted. Alongside Reddit's in-house efforts, we also examine &lt;a href="https://github.com/permitio/opal"&gt;&lt;u&gt;OPAL&lt;/u&gt;&lt;/a&gt;, an open-source solution that aligns with the functionality of Reddit’s system, presenting an alternative approach for organizations seeking sophisticated authorization management solutions in the field of Ad Tech.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yr_Pfb3o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h8hq8eejyc7xg36vl5ew.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yr_Pfb3o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h8hq8eejyc7xg36vl5ew.png" alt="An example of an authorization code no one wants to author" width="640" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorization in Ad Tech
&lt;/h2&gt;

&lt;p&gt;Advertising technology consists of a wide range of digital strategies and platforms for targeting, delivering, and analyzing online advertisements. From advertisers and publishers to ad exchanges and networks, each of these entities manages vast amounts of data and a range of transactions with multiple stakeholders involved. &lt;/p&gt;

&lt;p&gt;One of the critical challenges in Ad Tech is authorization. Unlike simpler systems where access control can be relatively straightforward, authorization in Ad Tech platforms requires a more sophisticated approach.&lt;/p&gt;

&lt;p&gt;Advertisers have distinct expectations of how their accounts should be structured and who should access them. These systems should not only be thoroughly secure but also flexible enough to accommodate a wide range of requirements. They need to manage who (or what, in the case of automated systems) has access to which parts of the platform, under what conditions, and to what extent. This requirement for detailed and dynamic access control is where basic authorization solutions often fall short, necessitating more advanced, granular solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reddit’s Ad Tech platform as a case study
&lt;/h2&gt;

&lt;p&gt;Reddit is one of the largest online platforms out there, with its advertising platform being an integral part of its business model, allowing businesses to tap into its vast and varied user base. The platform enables advertisers to target audiences based on interests, demographics, and behaviors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YYQJeYL---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/VKFNTTWTQW1HjFCkKz4Q" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YYQJeYL---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/VKFNTTWTQW1HjFCkKz4Q" alt="Group 67762.png" title="Group 67762.png" width="800" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As much of Reddit’s content is public and does not necessitate an overly complex authorization system, Reddit’s team was unable to find an existing generalized authorization service within the company and started exploring the development of a homebrew solution within the ads organization.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reddit.com/r/RedditEng/comments/13vttm8/evolving_authorization_for_our_advertising/"&gt;&lt;u&gt;In his post&lt;/u&gt;&lt;/a&gt;, Braden Groom, a Staff Engineer at Reddit, describes the unique challenges Reddit faced with creating authorization for its Ad Tech platform, specifically with crafting an effective authorization system for its advertising platform. These challenges stem from the need to cater to a diverse range of advertiser requirements and the complex nature of digital advertising itself.&lt;/p&gt;

&lt;p&gt;Let’s start by seeing what their requirements were - &lt;/p&gt;

&lt;h2&gt;
  
  
  Reddit’s Authorization Requirements:
&lt;/h2&gt;

&lt;p&gt;In developing its authorization system for the advertising platform, Reddit identified several crucial requirements that would guide its approach. These requirements were essential in ensuring that the system would not only meet their current needs but also be adaptable for future challenges:&lt;/p&gt;

&lt;h3&gt;
  
  
  Low latency
&lt;/h3&gt;

&lt;p&gt;Every action on Reddit’s advertising platform necessitates a rapid authorization check. This requirement for low latency is crucial to ensure a seamless experience for users and advertisers alike.&lt;/p&gt;

&lt;h3&gt;
  
  
  Availability
&lt;/h3&gt;

&lt;p&gt;An outage in the authorization service could mean a complete halt in the operation of the advertising platform, making it impossible to perform essential authorization checks. Therefore, high uptime is critical to maintain the continuous functioning of the platform. &lt;/p&gt;

&lt;h3&gt;
  
  
  Auditability
&lt;/h3&gt;

&lt;p&gt;For security and compliance, a detailed log of all decisions made by the authorization service is necessary. This aspect of auditability is not just a regulatory requirement but also a fundamental component of managing this system, especially in the case of unauthorized access. It allows Reddit to track and review authorization decisions, ensuring that the system is functioning correctly and adhering to all necessary policies and regulations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flexibility
&lt;/h3&gt;

&lt;p&gt;Reddit, like every player in the advertising landscape, must frequently evolve based on the expectations of its advertising partners - allowing them to define and manage their own roles.  Therefore, the authorization system must be flexible and adaptable to changing requirements without significant overhauls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-Tenancy (stretch goal)
&lt;/h3&gt;

&lt;p&gt;While not an explicit initial requirement, Reddit aimed for a &lt;a href="https://docs.permit.io/concepts/multitenancy"&gt;&lt;u&gt;multi-tenant&lt;/u&gt;&lt;/a&gt; capability in their authorization system. This goal was set with the understanding that a generalized authorization solution was lacking at Reddit, and thus, a system that could address multiple use cases across the company would be beneficial. Although focused on the advertising platform, this stretch goal would enhance the system’s flexibility and scalability, allowing it to potentially serve various needs across Reddit as a whole. &lt;/p&gt;

&lt;p&gt;With the requirements laid out before us, there is one more important challenge, unique to ad tech, to consider - &lt;/p&gt;

&lt;h3&gt;
  
  
  Authorization for Anonymous Identities
&lt;/h3&gt;

&lt;p&gt;An additional significant challenge with advertising on a platform like Reddit comes from the fact that a large portion of user interaction occurs through anonymous identities,  as you don’t have to create an account in order to browse content (And see ads while you do). This presents a unique challenge in the context of advertising authorization. &lt;/p&gt;

&lt;p&gt;When it comes to advertising, the platform needs to perform authorization checks to determine which ads to show to which users. These checks are straightforward when dealing with registered users, as their profiles, preferences, and histories can guide ad targeting. However, for anonymous users, the platform lacks this personalized data, requiring a different approach to authorization and ad targeting.&lt;/p&gt;

&lt;p&gt;So how did the Reddit team seek to tackle these challenges, and what can we learn from their experience? Let’s start with the first principle they decided to implement - &lt;/p&gt;

&lt;h2&gt;
  
  
  Decoupling Policy from Code
&lt;/h2&gt;

&lt;p&gt;Inspired by &lt;a href="https://www.permit.io/blog/zanzibar-vs-opa"&gt;&lt;u&gt;Google Zanzibar&lt;/u&gt;&lt;/a&gt;, the first decision the Reddit team decided to make when designing their authorization solution was decoupling policy and code. Separating the app’s authorization code from the actual application code is a recommended best practice for various reasons. &lt;/p&gt;

&lt;p&gt;The Reddit team explained their choice to do so meant their database had to perform no rule evaluation when fetching rules at query time, keeping the query patterns “simple, fast, and easily cacheable”. Rule evaluation will thus only happen in the application after the database has returned all of the relevant rules. Having the policy storage and evaluation engines clearly isolated also allowed them to potentially replace one of them with relative ease if they decide to do so in the future.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o41OHv0c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/I2kYzWQmTT6uTET4HNjo" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o41OHv0c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/I2kYzWQmTT6uTET4HNjo" alt="pasted image 0.png" title="pasted image 0.png" width="800" height="855"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To achieve that, they have decided to use the &lt;a href="https://www.permit.io/blog/introduction-to-opa"&gt;&lt;u&gt;Open Policy Agent (OPA) policy engine&lt;/u&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Policy Agent
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.permit.io/blog/introduction-to-opa"&gt;&lt;u&gt;Open Policy Agent (OPA)&lt;/u&gt;&lt;/a&gt; is an open-source, general-purpose policy engine that decouples policy decision-making from policy enforcement. It provides a high-level declarative language (Rego) to specify policy as code and APIs to offload decision-making from your software.&lt;/p&gt;

&lt;p&gt;OPA was already in use at Reddit for Kubernetes-related authorization tasks. It also provides a testing framework that the Reddit team could use to enforce 100% coverage for policy authors.&lt;/p&gt;

&lt;p&gt;Using OPA allowed the Reddit team to facilitate centralized rule management, allowing policies to be defined in a unified manner and applied consistently across various parts of a system, maintaining consistency and manageability. &lt;/p&gt;

&lt;p&gt;OPA’s architecture also enabled policies to be enforced anywhere in the system without requiring the policy engine to be co-located with the service making the decision. This is aligned with Reddit's approach of separating rule retrieval from rule evaluation. &lt;/p&gt;

&lt;p&gt;An example of Rego code &lt;a href="https://www.permit.io/blog/implement-abac-using-opa"&gt;representing ABAC&lt;/a&gt; rule 👇🏻&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rego"&gt;&lt;code&gt;&lt;span class="ow"&gt;package&lt;/span&gt; &lt;span class="n"&gt;abac&lt;/span&gt;

&lt;span class="c1"&gt;# User attributes&lt;/span&gt;
&lt;span class="n"&gt;user_attributes&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"Squid"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"tenure"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"title"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"cashier"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="s2"&gt;"Pat"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"tenure"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"title"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"cashier"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Menu attributes&lt;/span&gt;
&lt;span class="n"&gt;menu_attributes&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"Burger"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"items"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Menu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"price"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="s2"&gt;"Shake"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"items"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Menu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"price"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="ow"&gt;default&lt;/span&gt; &lt;span class="n"&gt;allow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="c1"&gt;# All cashiers may process orders of up to 1$ total&lt;/span&gt;
&lt;span class="n"&gt;allow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# Lookup the user's attributes&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;user_attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="c1"&gt;# Check that the user is a cashier&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"cashier"&lt;/span&gt;
    &lt;span class="c1"&gt;# Check that the item being sold is on the menu&lt;/span&gt;
    &lt;span class="n"&gt;menu_attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ticker&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"Menu"&lt;/span&gt;
    &lt;span class="c1"&gt;# Check that the processed amount is under 1$&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Cashiers with 1=&amp;gt; year of experience may ⁠process orders of up to 10$ total.&lt;/span&gt;
&lt;span class="n"&gt;allow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;# Lookup the user's attributes&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;user_attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="c1"&gt;# Check that the user is a cashier&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"cashier"&lt;/span&gt;

    &lt;span class="c1"&gt;# Check that the item being sold is on the menu&lt;/span&gt;
    &lt;span class="n"&gt;menu_attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ticker&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"Menu"&lt;/span&gt;
    &lt;span class="c1"&gt;# Check that the user has at least 1 year of experience&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tenure&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="c1"&gt;# Check that the processed amount is under is under $10&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another decision made by the Reddit team was to build a centralized service instead of a system of sidecars. While the sidecar approach seemed viable, it seemed unnecessarily complex for their needs, so they opted for a centralized service to keep maintenance costs down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modeling Policy Rules
&lt;/h2&gt;

&lt;p&gt;As outlined in the requirements of the Reddit team, it was crucial for them to create a highly flexible system capable of accommodating the evolving needs of their advertising platform. &lt;/p&gt;

&lt;p&gt;To do that, developers often utilize the use of common authorization models such as &lt;a href="https://www.permit.io/blog/rbac-with-permit"&gt;&lt;u&gt;RBAC&lt;/u&gt;&lt;/a&gt;, &lt;a href="https://www.permit.io/blog/what-is-attribute-based-access-control"&gt;&lt;u&gt;ABAC&lt;/u&gt;&lt;/a&gt;, and &lt;a href="https://www.permit.io/blog/what-is-rebac"&gt;&lt;u&gt;ReBAC&lt;/u&gt;&lt;/a&gt;. The Reddit team decided to take a more abstract approach, creating rules consisting of three fields describing access policies: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Subject: Describes who or what the rule pertains to.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Action: Specifies what the subject is allowed to do.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Object: Defines what the subject may act upon.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As well as two more fields representing different layers of isolation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Domain - Represents the specific use-case within the authorization system. For example, there is a distinct domain dedicated to advertisements, while other teams within Reddit can utilize the service for different domains, such as community moderation, maintaining isolation from the advertising domain. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Shard ID - Provides an additional layer of sharding within the domain. In the advertising domain, sharding is organized by the advertiser's business ID, whereas in the community moderation domain, sharding could be based on community IDs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Rule Storage, OPAL, and GitOps
&lt;/h2&gt;

&lt;p&gt;The system Reddit designed does not enforce validations on these fields. Each use-case has the freedom to store simple IDs or employ more sophisticated approaches, such as using paths to describe the scope of access. Each use-case can shape its rules as needed and encode any desired meaning into its policy for rule evaluation.&lt;/p&gt;

&lt;p&gt;Whenever the service is asked to check access, it only has one type of query pattern to fulfill. Each check request is limited to a specific (domain, shard ID) combination, so the service simply needs to retrieve the bounded list of rules for that shard ID. Having this single simple query pattern keeps things fast and easily cacheable. This list of rules is then passed to the evaluation side of the service.&lt;/p&gt;

&lt;p&gt;As mentioned above, Reddit’s team made a strategic decision to develop a centralized service for managing authorization. While the Reddit team made the decision to develop this capability themselves, it is also possible to achieve these results by using OPAL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3pllEPr6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/ib4tayphQlq3UF0qM0Ta" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3pllEPr6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/ib4tayphQlq3UF0qM0Ta" alt="image (41).png" title="image (41).png" width="800" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/permitio/opal"&gt;&lt;u&gt;Open Policy Administration Layer (OPAL)&lt;/u&gt;&lt;/a&gt;, is an open source administration layer for Policy Engines such as Open Policy Agent (OPA), and &lt;a href="https://github.com/permitio/cedar-agent"&gt;&lt;u&gt;AWS' Cedar Agent&lt;/u&gt;&lt;/a&gt; that detects changes to both policy and policy data in real time and pushes live updates to those agents. Using Git repositories and GitOps as a method for rule storage, OPAL provides several benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Version Control: Using Git repositories for rule storage means that every change is tracked. This is crucial for audit trails, allowing teams to see who made changes, when, and why.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rollback and History: In case of errors or unforeseen issues, it’s easy to roll back to previous versions of policies, enhancing the system's reliability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Collaboration and Review: GitOps facilitates collaboration among team members. Changes can be reviewed through merge requests, ensuring that updates to policies undergo scrutiny before implementation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automated Deployment: Changes in the repository can trigger automated deployments, making the update process more efficient and reducing manual intervention.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Rule Evaluation, Policy, and Data Synchronization
&lt;/h2&gt;

&lt;p&gt;After successfully establishing a system for efficiently retrieving rules, the next step for the Reddit team was to evaluate these rules and generate an answer for the client. &lt;/p&gt;

&lt;p&gt;For each domain within their system, the ability to define specific policies determining how rules are evaluated was crucial. Although their application was written in Go, which would have facilitated the direct implementation of these policies, Reddit prioritized keeping policy logic distinctly separate from the application logic. &lt;/p&gt;

&lt;p&gt;As mentioned previously, this separation served two key purposes: it prevented policy logic from inadvertently influencing other parts of the service and allowed for remote updating of policy logic, enabling clients to publish policy updates independently of service deployments.&lt;/p&gt;

&lt;p&gt;In parallel to the bespoke solution developed by Reddit, OPAL (Open Policy Administration Layer) stands out as a ready-made open-source solution offering similar capabilities. OPAL, when used in conjunction with OPA, acts as a dynamic administration layer, ensuring the policy engine is continuously synchronized with the latest policies and data. This is achieved by deploying OPAL Clients alongside OPA, which then subscribe to topic-based Pub/Sub updates. These updates are efficiently managed and disseminated from the OPAL Server, supplemented by data from various sources like databases, APIs, or third-party services.&lt;/p&gt;

&lt;p&gt;The synergy of OPA and OPAL provides a comprehensive solution for managing authorization systems, particularly in environments as dynamic and complex as Reddit's advertising platform.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  Please Support Us
&lt;/h3&gt;

&lt;p&gt;If you find this post helpful,&lt;a href="https://github.com/permitio/opal"&gt;please give OPAL a star on GitHub&lt;/a&gt;! Your support helps us make access control easier and motivates us to write more articles like this one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xInLC-dM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/0KCya41tQG6SDBDCx73T" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xInLC-dM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/0KCya41tQG6SDBDCx73T" alt="88f6wm.jpg" title="88f6wm.jpg" width="697" height="500"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Auditing
&lt;/h2&gt;

&lt;p&gt;To fulfill the requirements mentioned above, the Reddit team had to create a system of &lt;a href="https://www.permit.io/blog/audit-logs"&gt;&lt;u&gt;Audit Logs&lt;/u&gt;&lt;/a&gt; to record all decisions made by the service, playing a crucial role in both compliance and security. The auditing mechanism was implemented in two distinct parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A change data capture pipeline:&lt;/strong&gt; This system is engineered to track and upload all changes occurring within the database directly to BigQuery. This process ensures that every modification, whether minor or significant, is captured and stored securely for review and analysis.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Application logs&lt;/strong&gt; : The application itself also logs all of the decisions, which are then uploaded to BigQuery by a sidecar. While this functionality was developed in-house, it's noteworthy that OPA also offers a decision log feature.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Initially, these auditing features were primarily integrated for compliance and security purposes. However, as the system evolved, the team discovered an additional, invaluable benefit: these logs became a powerful tool for debugging. By providing detailed insights into the decision-making process of the authorization service, the team gained the ability to trace and rectify issues with greater efficiency and precision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Following the implementation of their newly developed authorization service, the Reddit team undertook several key steps to align the service with the needs of their advertising platform. &lt;/p&gt;

&lt;p&gt;They established a detailed rule structure, defined policies for rule evaluation, integrated authorization checks throughout the platform, and developed user interfaces tailored for rule definition on a per-business basis.&lt;/p&gt;

&lt;p&gt;Upon reviewing the performance of the newly implemented service, the Reddit team reported outstanding results. The service has demonstrated impressive efficiency, with &lt;strong&gt;p99 latencies around 8 milliseconds and p50 latencies close to 3 milliseconds for authorization checks&lt;/strong&gt;. These metrics are indicative of the service's ability to handle authorization requests swiftly and effectively.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E4fyTip1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/9oHtmFDsSQWmRV4dsWEN" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E4fyTip1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.graphassets.com/9oHtmFDsSQWmRV4dsWEN" alt="pasted image 0 (1).png" title="pasted image 0 (1).png" width="800" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Equally notable is the service's remarkable stability. Since its launch over a year ago (At the time Branden published his post), the service has operated without any outages, underscoring its reliability. Interestingly, the majority of issues encountered were related to logical errors within the policies themselves, rather than the infrastructure or the software.&lt;/p&gt;

&lt;p&gt;A critical factor contributing to the service's success is the separation of policy and code and its effective use of audit logs. This system ensures that the results of every check are accurately recorded, and isolated from other software complexities. In many systems, the lack of clear separation between policy and code can lead to muddled results and increased difficulty in debugging. However, by decoupling policy from code and maintaining detailed audit logs, Reddit has been able to achieve clear, unambiguous insights into the authorization process. This clarity not only aids in compliance and security but also significantly enhances the debugging and maintenance process, ensuring the system remains efficient and reliable.&lt;/p&gt;

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

&lt;p&gt;Reddit's journey in crafting the authorization system for its advertising platform shows the complex challenges in the realm of Ad Tech. Their endeavor, as described by Staff Engineer Braden Groom, underscores a crucial evolution in managing digital advertising's nuanced authorization demands. &lt;/p&gt;

&lt;p&gt;The choice to decouple policy from code, inspired by Google's Zanzibar, and the implementation of Open Policy Agent (OPA) reflect Reddit’s commitment to building a system that is both robust and adaptable. The auditing mechanisms they established, ensuring every action is logged and reviewable, not only enhance security and compliance but also serve as a powerful tool for debugging and system refinement.&lt;/p&gt;

&lt;p&gt;Reddit's results speak for themselves. The performance metrics of their authorization checks and the system's remarkable stability since its launch are testaments to the efficacy of their solution. The clear separation of policy and code, paired with comprehensive audit logs, has provided them with a system that is efficient, reliable, and adaptable to ever-changing needs.&lt;/p&gt;

&lt;p&gt;We also learned about OPAL, an open-source solution that echoes the functionalities developed by Reddit. Its use of Git repositories and GitOps for rule storage, combined with the dynamic synchronization capabilities provided by OPAL Clients, offers a streamlined, efficient alternative for managing complex authorization systems. For organizations seeking to implement sophisticated authorization management without building from scratch, OPAL presents a compelling option, enabling them to stay agile and responsive in the fast-evolving landscape of digital advertising.&lt;/p&gt;

&lt;p&gt;Reddit's case study is a shining example of how thoughtful, well-engineered solutions can successfully meet the intricate demands of Ad Tech authorization. It serves as both a blueprint and an inspiration for others in the industry, showcasing the power of innovative thinking in overcoming complex technological challenges.&lt;/p&gt;

&lt;p&gt;Want to learn more about Authorization? Join our &lt;a href="https://io.permit.io/permitslack"&gt;&lt;u&gt;Slack community&lt;/u&gt;&lt;/a&gt;, where there are hundreds of devs building and implementing authorization.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>security</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
