<?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: SWCode</title>
    <description>The latest articles on DEV Community by SWCode (@swcode).</description>
    <link>https://dev.to/swcode</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%2F1178407%2F31e2244a-df57-4eb1-9bf1-b72125607fd5.png</url>
      <title>DEV Community: SWCode</title>
      <link>https://dev.to/swcode</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/swcode"/>
    <language>en</language>
    <item>
      <title>Mastering Data Consistency: A Deep Dive into the Transactional Outbox Pattern</title>
      <dc:creator>SWCode</dc:creator>
      <pubDate>Tue, 23 Jan 2024 07:30:41 +0000</pubDate>
      <link>https://dev.to/swcode/mastering-data-consistency-a-deep-dive-into-the-transactional-outbox-pattern-1im9</link>
      <guid>https://dev.to/swcode/mastering-data-consistency-a-deep-dive-into-the-transactional-outbox-pattern-1im9</guid>
      <description>&lt;p&gt;Unlock the potential of modern distributed systems with our latest exploration: The Transactional Outbox Pattern. &lt;br&gt;
Discover how this pattern enhances data consistency, reliability, and system resilience in microservices architectures.&lt;/p&gt;
&lt;h2&gt;
  
  
  Introduction: Navigating the Complexities of Modern Software Development
&lt;/h2&gt;

&lt;p&gt;In the realm of software development, managing data consistency and integrity is a cornerstone of reliable systems. &lt;br&gt;
The complexity escalates when we transition from a single, well-understood system to an interconnected web of services and components.&lt;/p&gt;

&lt;p&gt;The simplicity and robustness of SQL databases have long been a foundation in software development. &lt;br&gt;
These databases offer &lt;a href="https://en.wikipedia.org/wiki/ACID"&gt;ACID (Atomicity, Consistency, Isolation, Durability)&lt;/a&gt; properties, ensuring transactions are processed reliably. &lt;br&gt;
In this controlled environment, developers can perform business logic within transactions confidently, knowing that any failure will trigger a rollback, preserving data integrity and preventing inconsistent states. &lt;br&gt;
This traditional model has proven effective and straightforward when operations are confined within the bounds of a single database.&lt;/p&gt;

&lt;p&gt;However, modern software architectures often require interactions beyond a single database. &lt;br&gt;
The introduction of third-party systems and external services adds layers of complexity when business logic involves modifying data across distributed systems, &lt;br&gt;
such as a SQL database and a event bus like RabbitMQ. &lt;br&gt;
In these distributed architectures, the ACID properties, which are the backbone of transactional integrity within a single database, &lt;br&gt;
become challenging to enforce across multiple systems.&lt;/p&gt;

&lt;p&gt;One of the core issues is the uncertainty of atomicity. &lt;br&gt;
For instance, consider a scenario where a transaction involves writing an event to a RabbitMQ and also updating a record in a database. &lt;br&gt;
There's a possibility that the event write to RabbitMQ succeeds, but the outer database transaction fails. &lt;br&gt;
This results in a scenario where an event indicating a business action is published, &lt;br&gt;
but the corresponding database state does not reflect this action because the transaction was not completed successfully. &lt;br&gt;
The system thus ends up in an inconsistent state, with the event bus reflecting a change that the database does not.&lt;/p&gt;

&lt;p&gt;When integrating an event bus or any other external service within an application in a distributed system, there are two naive approaches one might consider. &lt;br&gt;
Each approach has its own set of challenges and potential pitfalls:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Execute Business Logic Within the Transaction and Publish Events After Committing the Transaction
&lt;/h3&gt;

&lt;p&gt;In this approach, the application first executes all the required business logic within a database transaction. &lt;br&gt;
After this transaction is successfully committed, it then publishes the relevant events to the event bus.&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%2Faatrrkxzp0nnajj3rh87.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%2Faatrrkxzp0nnajj3rh87.png" alt="commit-publish" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenges:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Risk of Event Loss:&lt;/strong&gt; If the application crashes or encounters an issue between the transaction &lt;a href="https://en.wikipedia.org/wiki/Commit_(data_management)"&gt;commit&lt;/a&gt; and the event publication, the event may never get published. 
This leads to a situation where the database state has changed, but the corresponding event informing other services of this change is lost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inconsistency in Distributed Systems&lt;/strong&gt;: Other services relying on these events for triggering their own processes will not be aware of the changes, leading to data inconsistency across the system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex Recovery Mechanisms&lt;/strong&gt;: Implementing a mechanism to check for such failures and recover from them can be complex and error-prone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach can be suitable for situations where the events being published are not critical to the core business logic or data integrity of the application. &lt;br&gt;
An example of this might be events used for monitoring or logging purposes. &lt;br&gt;
In these cases, the loss of some events due to system failures or crashes might be considered an acceptable risk.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Execute Business Logic and Publish Events Within the Transaction
&lt;/h3&gt;

&lt;p&gt;In this approach, the application attempts to execute business logic and publish events to the event bus, all within the same database transaction. &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%2Fttoqg8sz6s9p936gwwxm.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%2Fttoqg8sz6s9p936gwwxm.png" alt="publish-commit" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenges:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Event Publication Preceding Transaction Commit:&lt;/strong&gt; When events are published to the event bus as part of the database transaction, there's a risk that the transaction might not successfully commit even after the event has been sent out. 
This situation can occur due to various reasons, such as issues in completing subsequent operations within the same transaction or a late-occurring failure in the database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inconsistent State Risks:&lt;/strong&gt; If the transaction fails to commit after the event is published, it leads to a critical inconsistency. 
The event bus carries an event that suggests a change or action that, in reality, the database did not finalize. This discrepancy can lead to serious data integrity issues, as other services responding to the event may act on data that doesn't accurately reflect the current state of the system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex Error Handling:&lt;/strong&gt; The application must be prepared to handle these scenarios, where the event is out in the world, but the corresponding transaction failed. 
This requires sophisticated error handling and potentially complex rollback mechanisms, not just for the database changes, but also for any actions taken by services that consumed the premature event.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the past, one common approach to address such issues was through distributed transactions, like the &lt;a href="https://en.wikipedia.org/wiki/Two-phase_commit_protocol"&gt;two-phase commit (2PC) protocol&lt;/a&gt;. &lt;br&gt;
2PC was designed to ensure atomicity across multiple database systems, &lt;br&gt;
attempting to maintain data consistency by coordinating a commit or rollback across all involved systems. &lt;br&gt;
However, this approach comes with significant drawbacks, particularly in distributed and microservice-based architectures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance Overhead&lt;/strong&gt;: The 2PC protocol is known for being resource-intensive and can significantly impact system performance, particularly in high-throughput environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complexity and Scalability Issues&lt;/strong&gt;: Managing and coordinating distributed transactions across multiple systems adds a layer of complexity and can become a bottleneck in scalable systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lack of Support in Modern Ecosystems&lt;/strong&gt;: Many modern message buses and RESTful APIs do not support the 2PC protocol, making it challenging to implement in contemporary microservices architectures.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  The Real-World Implications of Naive Approaches
&lt;/h3&gt;

&lt;p&gt;From a theoretical standpoint, the challenges with these naive approaches in integrating an event bus within an application may seem obvious. &lt;br&gt;
However, drawing from my professional experience across various projects, I have observed these issues manifest repeatedly in real-world scenarios. &lt;br&gt;
Whether it's dealing with distributed systems employing message buses, interacting with external systems through REST APIs, or managing multiple databases, a common error persists: a lack of clarity among developers regarding the consistency semantics of their applications.&lt;/p&gt;

&lt;p&gt;In practice, this oversight leads to perplexing and hard-to-diagnose errors. &lt;br&gt;
Developers often underestimate the complexity introduced by distributed environments and might not fully consider the implications of their chosen implementation strategy. &lt;br&gt;
As a result, applications can exhibit erratic behavior, where the root cause is deeply embedded in the flawed interaction between different system components. &lt;br&gt;
These issues can be especially challenging to debug and resolve, given the distributed nature of these systems and the often subtle interdependencies between their components.&lt;/p&gt;

&lt;p&gt;The crux of the problem lies in the assumption that techniques and patterns used in monolithic or single-database applications can be directly applied to distributed systems. &lt;br&gt;
This misconception overlooks the fundamental differences in how distributed systems handle data consistency and transaction management. &lt;br&gt;
The consequences of this oversight are not just theoretical inconsistencies but tangible bugs and system failures that can have a significant impact on the reliability and integrity of the application.&lt;/p&gt;

&lt;p&gt;This challenge highlights the inherent difficulty in ensuring atomicity and consistency when dealing with internal transactions and external communication within the same operational scope. &lt;br&gt;
It underlines the necessity for a pattern like the Transactional Outbox, which offers a way to decouple these concerns, &lt;br&gt;
ensuring that events are only published after the transaction’s successful commitment, thereby maintaining the integrity and consistency of the overall system.&lt;/p&gt;
&lt;h2&gt;
  
  
  Understanding the Transactional Outbox
&lt;/h2&gt;

&lt;p&gt;The Transactional Outbox is a design pattern used in microservices architectures to ensure consistent and reliable message publishing in distributed systems. &lt;br&gt;
At its core, the pattern solves a fundamental problem: how to update a database and publish messages/events to a message bus or event-driven system and keep the state consistent.&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%2Fojke4sr30qwkgneyg9dx.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%2Fojke4sr30qwkgneyg9dx.png" alt="transactional-outbox" width="800" height="605"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Local Transaction with Outbox Table:&lt;/strong&gt; Instead of directly publishing an event to the message bus, the application writes the event into a special table within the same database as part of the business logic transaction. This table is commonly referred to as the &lt;strong&gt;outbox&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Atomic Commit:&lt;/strong&gt; The key to this pattern is the atomic commit. The changes to the business data and the insertion of the event into the outbox are done in the same database transaction. This ensures that either both are committed or neither, maintaining the atomic nature of operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliable Event Publishing:&lt;/strong&gt; After the transaction commits, a separate process (which could be a service, a scheduled job, or a database trigger) reliably reads events from the outbox and publishes them to the message bus. This process ensures that each event is eventually published without being lost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event Deletion/Mark as Processed:&lt;/strong&gt; Once the event is successfully published to the message bus, it is either deleted from the outbox or marked as processed, preventing it from being published again.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By using the transactional outbox, the application ensures that the state in the database and the published events are always consistent.&lt;br&gt;
Moreover, the pattern exhibits a remarkable resilience to system failures. If the application crashes after committing the transaction but before the event is published, the separate process ensures that the event will still be published later.&lt;br&gt;
Another significant advantage of the Transactional Outbox Pattern is the decoupling it offers. By separating the concerns of database transactions and event publishing, the pattern allows each to operate independently. This separation not only simplifies the architecture but also enhances scalability and maintainability. &lt;br&gt;
It allows the system to evolve more flexibly, adapting to changes and scaling components independently without disrupting the fundamental operations of transaction management and event distribution.&lt;/p&gt;

&lt;p&gt;Additionally, an often overlooked yet significant aspect of the Transactional Outbox Pattern is its efficiency, &lt;br&gt;
particularly regarding the speed of writing to the outbox. &lt;br&gt;
Writing an event to the outbox involves merely appending a row to a table, which is one of the fastest operations in database management. This efficiency means that the pattern does not impose a notable performance penalty.&lt;/p&gt;
&lt;h2&gt;
  
  
  Challenges and Solutions
&lt;/h2&gt;

&lt;p&gt;Implementing the Transactional Outbox Pattern, while beneficial, brings its own set of challenges that need careful consideration and handling.&lt;/p&gt;
&lt;h3&gt;
  
  
  At least once delivery
&lt;/h3&gt;

&lt;p&gt;When implementing the Transactional Outbox Pattern in a distributed system, it's important to understand that this pattern inherently guarantees at-least-once-delivery semantics. &lt;br&gt;
At-least-once-delivery is a delivery approach where the system ensures that a message is definitely delivered to its destination at least once.&lt;br&gt;
Since the delivery mechanism is designed to ensure that messages are not lost, it errs on the side of sending duplicates rather than risking a message not being delivered at all. &lt;br&gt;
As a result, the receiving services or components must be equipped to identify and appropriately handle these duplicate messages. &lt;br&gt;
This involves implementing logic to detect if a message has already been processed and ensuring that processing it again does not adversely affect the system's state or lead to incorrect operations.&lt;/p&gt;

&lt;p&gt;A common approach to handle duplicate messages is implementing idempotency at the technical level. &lt;br&gt;
This involves recording the IDs of consumed events and checking against this record before processing new events. &lt;br&gt;
If an incoming event's ID matches one that has already been processed, it is ignored, thus preventing duplicate processing.&lt;/p&gt;

&lt;p&gt;A more sophisticated approach is to design idempotency based on business rules. &lt;br&gt;
Instead of just tracking event IDs, this approach involves designing the business logic and data models in such a way that repeating the same operation does not have adverse effects. &lt;br&gt;
For example, applying the same update twice would result in the same state as applying it once. This method requires a deeper understanding of the business context but can lead to a more robust solution.&lt;/p&gt;

&lt;p&gt;Consider the process of stock reservation in a warehouse. &lt;br&gt;
In this scenario, every time an item is reserved for a shipping order, the system communicates not just the quantity reserved, but also the remaining quantity in stock.&lt;br&gt;
When an article is reserved, the system sends an update that includes both the number of pieces reserved and the current stock level. &lt;br&gt;
This comprehensive update provides a complete picture of the stock status after each transaction.&lt;br&gt;
With the detailed stock information at hand, a replenishment component in the system can easily apply business rules to monitor stock levels. &lt;br&gt;
For instance, if the system receives multiple updates about the same reservation due to a duplicate message, it can discern that the stock level hasn't further decreased since the quantity and remaining stock are consistently reported.&lt;br&gt;
By structuring the update messages in this way, applying the same stock reservation update more than once does not lead to incorrect stock calculations. &lt;br&gt;
The system remains aware of the actual stock level, regardless of duplicate messages, ensuring that replenishment decisions are based on accurate and current information.&lt;/p&gt;
&lt;h3&gt;
  
  
  Eventual Consistency
&lt;/h3&gt;

&lt;p&gt;Eventual consistency refers to a model where the state of the system is not immediately synchronized across all its components following a change. &lt;br&gt;
Instead, these changes propagate through the system over time, resulting in a lag during which different services might have different views of the system’s state. &lt;br&gt;
Eventually, however, all services reach a consistent state, hence the term "eventual consistency." &lt;br&gt;
This concept contrasts with "strong consistency," where a system ensures immediate consistency across all nodes after any operation.&lt;/p&gt;

&lt;p&gt;In the realm of distributed systems, particularly those transitioning from traditional SQL database architectures, the concept of eventual consistency often poses a significant mental shift for developers. &lt;br&gt;
Accustomed to the strong consistency guarantees of SQL databases, where the recent write operation is immediately visible to all subsequent read operations, developers may find the notion of eventual consistency unsettling. &lt;br&gt;
This model, where data is not immediately consistent across all services of the system but becomes consistent over time, can seem counterintuitive and raise concerns about data integrity and application behavior.&lt;/p&gt;

&lt;p&gt;In discussing the eventual consistency inherent in the Transactional Outbox Pattern, it's important to clarify a common misconception: &lt;br&gt;
the introduction of the Transactional Outbox Pattern does not, in itself, bring about eventual consistency in a system. &lt;br&gt;
Rather, if your system already incorporates an event bus, it is by design operating under the principles of eventual consistency.&lt;/p&gt;

&lt;p&gt;The nature of an event bus in a distributed architecture inherently implies that there's a delay between when an event is generated and when it is received and processed by other parts of the system.&lt;br&gt;
When an event is published to the bus, it doesn't instantly synchronize the state across all services and components. &lt;br&gt;
Instead, these components update their state as and when they process the event, leading to a period during which different parts of the system may have slightly different views of the overall state.&lt;/p&gt;

&lt;p&gt;However, a closer examination of real-world processes reveals that eventual consistency is not only natural but often the norm. Consider the example of ordering a meal in a restaurant:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ordering Process:&lt;/strong&gt; When you place an order with the waiter, there's no immediate check with the kitchen to confirm if every ingredient is available. The waiter takes orders from multiple tables, and only later are these orders processed by the kitchen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handling Unavailability:&lt;/strong&gt; If an ingredient is unavailable, the waiter informs you later, and you're given the option to choose an alternative. This delay in information and the need to adapt is a classic example of eventual consistency at play.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same principle applies to many everyday business processes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hotel Bookings:&lt;/strong&gt; When you book a hotel room online, there's often a delay before the booking is confirmed. During high-demand periods, you might even receive a notification later that the room is no longer available, prompting you to find an alternative.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Online Shopping:&lt;/strong&gt; Shopping on platforms like Amazon involves a period where the order is processed, and only later do you get confirmation. In some cases, you might be notified of out-of-stock items or shipping delays.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flight Bookings:&lt;/strong&gt; Booking a flight doesn’t guarantee a seat until various checks are completed, and occasionally, overbookings lead to last-minute changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just as these real-world scenarios adapt and manage eventual consistency, applications in distributed systems must be designed to handle it gracefully. &lt;br&gt;
It's essential to recognize that eventual consistency is not a flaw but a characteristic of distributed systems that, when properly managed, can lead to greater scalability and resilience. &lt;br&gt;
Applications should be designed to expect and handle delays in data synchronization and to manage the exceptions that arise when things don't go as expected.&lt;/p&gt;

&lt;p&gt;Developers can draw lessons from these real-world analogies to better understand and implement eventual consistency in their systems. &lt;br&gt;
By acknowledging that not all processes require or benefit from strong consistency, and by designing systems that can handle inconsistencies and adapt as needed, developers can build more robust, flexible, and scalable applications. &lt;br&gt;
This mindset shift is crucial in successfully navigating the complexities of modern distributed systems.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hands-On Guide: Implementing the Transactional Outbox Pattern with Spring Boot and RabbitMQ
&lt;/h2&gt;

&lt;p&gt;We will demonstrate how to implement the Transactional Outbox Pattern in a Spring Boot application, integrated with RabbitMQ for message handling. &lt;br&gt;
For the transactional outbox mechanism, we'll utilize the &lt;a href="https://github.com/gruelbox/transaction-outbox"&gt;Transaction Outbox library&lt;/a&gt;, &lt;br&gt;
a well-curated Java library that offers seamless integration with Spring Boot and other frameworks like Quarkus.&lt;/p&gt;

&lt;p&gt;The sample project provides an REST endpoint for creating user profiles. &lt;br&gt;
Upon creating a user, it publishes a &lt;code&gt;UserCreatedEvent&lt;/code&gt; to RabbitMQ, demonstrating the Transactional Outbox Pattern's capabilities.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Cloning the Repository
&lt;/h3&gt;

&lt;p&gt;Our example project repository is available at &lt;a href="https://github.com/sw-code/swcode-samples"&gt;SWCode Samples on GitHub&lt;/a&gt;. &lt;br&gt;
This repository provides a "plug and play" setup with a docker-compose file that includes a PostgreSQL database and a RabbitMQ container, offering a hassle-free way to get the environment up and running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/sw-code/swcode-samples.git
cd swcode-samples/transactional-outbox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running Application
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Starting the Application:&lt;/strong&gt; Use Docker to start the PostgreSQL and RabbitMQ services &lt;code&gt;docker-comose up&lt;/code&gt;, 
and then run the Spring Boot application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creating Users:&lt;/strong&gt; To test user creation and the subsequent event publishing, you can use the &lt;code&gt;/users&lt;/code&gt; endpoint. 
This will trigger the flow from the user creation in the &lt;code&gt;UserService&lt;/code&gt; to the publishing and handling of the &lt;code&gt;UserCreatedEvent&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observing Event Handling:&lt;/strong&gt; As you create users through the endpoint, keep an eye on the logs of the RabbitMqConsumer. 
You should see the &lt;code&gt;UserCreatedEvent&lt;/code&gt; payloads being logged, indicating that the events are successfully being consumed from RabbitMQ.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For convenience, the repository includes a &lt;code&gt;sample-requests.http&lt;/code&gt; file,&lt;br&gt;
which provides easy access to all the endpoints if you are using IntelliJ IDEA.&lt;br&gt;
This file simplifies the process of making requests to the application for testing purposes.&lt;/p&gt;
&lt;h2&gt;
  
  
  Explore the Code
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;UserController&lt;/code&gt; controller provides an endpoint to create users.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UserCreateRequestDto&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&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;When a user is created, a &lt;code&gt;UserCreatedEvent&lt;/code&gt; is published. &lt;br&gt;
This is done using the OutboxPublisher to persist the event in the outbox first, and then forward it to RabbitMQ.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;eventPublisher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EventPublisher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;also&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;eventPublisher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserCreatedEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OutboxPublisher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;outbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;TransactionOutbox&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;EventPublisher&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DomainEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;outbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RabbitMqSender&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&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="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;schedule&lt;/code&gt; method leads to the persisting of the task, which involves sending the event to RabbitMQ. &lt;br&gt;
This task is stored in the outbox. &lt;br&gt;
Then, it schedules the execution of this task for after the current transaction has been committed. &lt;br&gt;
This ensures that the event is only sent after the transaction is successfully completed.&lt;/p&gt;

&lt;p&gt;In the context of handling potential failures during event sending after a transaction, the &lt;code&gt;TransactionalOutboxScheduler&lt;/code&gt; class provides a robust fallback mechanism. &lt;br&gt;
This class periodically executes a run method that continuously calls &lt;code&gt;transactionOutbox.flush()&lt;/code&gt;.&lt;br&gt;
The &lt;code&gt;flush&lt;/code&gt; method in &lt;code&gt;TransactionOutbox&lt;/code&gt; is responsible for finding and retrying events that haven't been successfully executed after a certain amount of time. &lt;br&gt;
It specifically targets events that were initially set up to be executed but haven't been completed as expected and have not exceeded a predefined number of retry attempts.&lt;br&gt;
This loop continues to invoke &lt;code&gt;flush&lt;/code&gt; as long as it returns true, indicating there are events to be processed. Once &lt;code&gt;flush&lt;/code&gt; returns false, signifying that there are no more events requiring attention, the loop terminates. This approach ensures that all pending events are addressed promptly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TransactionalOutboxScheduler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;transactionOutbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;TransactionOutbox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Scheduled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fixedDelay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transactionOutbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// NOP&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To simulate errors in event sending, utilize the &lt;code&gt;/failing-events&lt;/code&gt; endpoint. &lt;br&gt;
This endpoint generates a &lt;code&gt;FailingEvent&lt;/code&gt; and attempts to send it to RabbitMQ. &lt;br&gt;
The &lt;code&gt;RabbitMqSender&lt;/code&gt; is programmed to mimic an error by intentionally failing once for each instance of &lt;code&gt;FailingEvent&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Play around and have fun exploring the outbox pattern!&lt;/p&gt;

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

&lt;p&gt;As we conclude our exploration of the Transactional Outbox Pattern, &lt;br&gt;
it's evident that this pattern is more than just a technical solution—it's &lt;br&gt;
a strategic approach to ensure data consistency and reliability in the increasingly complex landscape of distributed systems and microservices.&lt;/p&gt;

&lt;p&gt;The key takeaway from this discussion is the importance of understanding and adapting to the nuances of distributed systems. &lt;br&gt;
The shift from traditional SQL database architectures to distributed models, while challenging, opens up new avenues for building scalable, resilient, and flexible applications. &lt;br&gt;
The Transactional Outbox Pattern is a testament to the innovative solutions that emerge when we rethink how data consistency and reliability should be handled in modern application development.&lt;/p&gt;

&lt;p&gt;As you implement this pattern in your projects, remember that the journey towards mastering distributed systems is ongoing. &lt;br&gt;
The Transactional Outbox Pattern is just one of the many tools in your arsenal, equipping you to tackle the challenges and leverage the opportunities presented by distributed architectures. &lt;br&gt;
Stay curious, continue exploring, and most importantly, keep building systems that not only meet today's demands but are also prepared for tomorrow's challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  References and Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://microservices.io/patterns/data/transactional-outbox.html"&gt;Microservices.io - Transactional Outbox Pattern&lt;/a&gt; An excellent resource for a concise overview of the pattern and its applications in microservices.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/"&gt;Designing Data-Intensive Applications&lt;/a&gt; by Martin Kleppmann: This book offers an in-depth exploration of various patterns and models used in designing modern data-intensive applications, including considerations for consistency and reliability in distributed systems.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.oreilly.com/library/view/building-microservices-2nd/9781492034018/"&gt;Building Microservices&lt;/a&gt; by Sam Newman: A comprehensive guide to designing, building, and maintaining microservices-based applications, with insights into communication patterns and data management in distributed environments.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/gruelbox/transaction-outbox"&gt;Transaction Outbox Library&lt;/a&gt; Dive into the source code and documentation of the Transaction Outbox library to understand its implementation and how it facilitates the Transactional Outbox Pattern.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>microservices</category>
      <category>database</category>
      <category>consistency</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Google's Zanzibar and Beyond: A Deep Dive into Relation-based Authorization</title>
      <dc:creator>SWCode</dc:creator>
      <pubDate>Tue, 09 Jan 2024 07:46:41 +0000</pubDate>
      <link>https://dev.to/swcode/googles-zanzibar-and-beyond-a-deep-dive-into-relation-based-authorization-289d</link>
      <guid>https://dev.to/swcode/googles-zanzibar-and-beyond-a-deep-dive-into-relation-based-authorization-289d</guid>
      <description>&lt;p&gt;Dive into the world of online permissions and it quickly becomes clear: it's all about the connections you hold. Imagine being at an upscale gala. It's not just about your invitation card that gets you through the door. It's about who you know inside, the conversations you're a part of, and the circles you move in.&lt;/p&gt;

&lt;p&gt;In the digital realm, it's similar. Access isn't always about direct permissions; it's about the intricate web of relationships that you're entangled in. Can you view this document? Well, it depends – are you linked to its creator, or part of the team that worked on it?&lt;/p&gt;

&lt;p&gt;It's this nuanced dance of relationships that defines relation-based authorization. Less of a straightforward checklist and more of a dynamic network of ties, it offers a richer, deeper layer to deciding "Who gets to do what?".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: We explored the foundational concepts of relation-based authorization models, tracing back to the roots in tech giants like Google. &lt;br&gt;
With the power of Ory Keto and Spring Boot, we crafted a hands-on example to bring the theory to life. &lt;br&gt;
Want to dive straight into the action? Check out our detailed hands-on integration: A Hands-on Integration of Ory Keto and Spring Boot.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Google Zanzibar Paper and its Influence on Rapid Authorization Framework Development
&lt;/h2&gt;

&lt;p&gt;In recent years, a notable event has had a profound influence on the world of authorization frameworks. This event was the release of the &lt;a href="https://research.google/pubs/pub48190/"&gt;Google Zanzibar paper&lt;/a&gt;, a highly insightful document that details Google's approach to scalable, efficient authorization.&lt;/p&gt;

&lt;p&gt;Google's Zanzibar system is a testament to the prowess of modern technology. According to the paper, Zanzibar handles access management for an astonishing number of resources - we're talking trillions of objects - used by hundreds of millions of users. What makes these figures even more impressive is the wide array of client services that rely on Zanzibar. Renowned platforms like Google Maps, Google Drive, and YouTube, all depend on Zanzibar for their authorization needs.&lt;/p&gt;

&lt;p&gt;But Zanzibar doesn't just handle this enormous load, it does so rapidly and reliably. The system boasts a remarkable response time, with 95% of requests being handled within just 10 milliseconds and 99% within 20 milliseconds. On top of this, Zanzibar has proven its reliability, maintaining an exceptional availability rate of 99.999% over the past three years.&lt;/p&gt;

&lt;p&gt;However, the impact of the Zanzibar paper extends beyond these impressive technical capabilities. The release of the paper pushed a flurry of development in the authorization realm, resulting in a variety of open-source projects and SaaS offerings inspired by Google's Zanzibar, including &lt;a href="https://github.com/ory/keto"&gt;Ory Keto&lt;/a&gt;, &lt;a href="https://authzed.com/"&gt;AuthZed&lt;/a&gt;, and &lt;a href="https://openfga.dev/"&gt;OpenFGA&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But why has this paper sparked such a wave of development? The answer lies in a combination of factors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: As mentioned, Zanzibar's ability to handle authorization for trillions of objects by hundreds of millions of users is awe-inspiring. As more businesses adopt microservices and cloud-native architectures, the need for scalable authorization solutions becomes increasingly pressing. Zanzibar offers a proven blueprint for achieving such scalability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: The Zanzibar model, termed &lt;strong&gt;Global, Consistent Authorization System&lt;/strong&gt;, is not tied to specific business logic or policies. This flexibility makes it broadly applicable across various domains and use cases, inspiring many to leverage it in their contexts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency&lt;/strong&gt;: Efficiency in authorization is crucial. Zanzibar's use of data sharding and re-sharding for optimal use of resources has been an inspiration for many developing authorization frameworks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability&lt;/strong&gt;: Google's paper emphasizes Zanzibar's ability to provide consistent authorization decisions, even in the face of network partitions and system failures. This high level of reliability is a key factor in Zanzibar's appeal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Innovation&lt;/strong&gt;: Finally, the Zanzibar paper represents a significant leap in the way we think about and implement authorization. Its innovative approach to handling access control at a massive scale has piqued the interest of many in the field, spurring them to explore and adopt similar strategies.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The widespread interest and rapid development sparked by the Zanzibar paper are testaments to its game-changing potential in the realm of scalable authorization.&lt;br&gt;
As we at SWCode embark on our journey to implement a scalable authorization architecture, we too are inspired by the lessons gleaned from Google's Zanzibar.&lt;/p&gt;
&lt;h3&gt;
  
  
  Unpacking Zanzibar's Relation-Tuple-Based Model
&lt;/h3&gt;

&lt;p&gt;At the core of Google's Zanzibar system is a surprisingly simple yet powerful model: relation tuples. A relation tuple is a small record that describes a relationship, in the form of &lt;code&gt;namespace:object#relation@subject&lt;/code&gt;. In this format:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;namespace&lt;/code&gt; represents the type of the object, such as &lt;code&gt;document&lt;/code&gt; or &lt;code&gt;folder&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;object&lt;/code&gt; refers to a unique identifier for a specific instance of that type, like a specific document ID or folder ID.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;relation&lt;/code&gt; relation signifies the type of relationship between the object and the subject, such as &lt;code&gt;owner&lt;/code&gt; or &lt;code&gt;viewer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;subject&lt;/code&gt; can either be a user or another relation tuple, allowing for complex, nested relationships.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a relation tuple might look like this: &lt;code&gt;document:readme#owner@user456&lt;/code&gt;, meaning that &lt;code&gt;user456&lt;/code&gt; is the &lt;code&gt;owner&lt;/code&gt; of &lt;code&gt;readme&lt;/code&gt; in the &lt;code&gt;document&lt;/code&gt; namespace.&lt;br&gt;
Expanding on this, the subject in a relation tuple doesn't necessarily need to be a user. It could also be another relation tuple. This introduces the ability to create relationships between objects, as exemplified by &lt;code&gt;document:readme#parent@folder:A&lt;/code&gt;, indicating that the folder A is the parent of the document readme.&lt;/p&gt;

&lt;p&gt;By combining these simple elements, Zanzibar can describe complex hierarchical relationships and permissions across vast numbers of objects and users. This granularity of control is one of the key reasons for Zanzibar's flexibility and scalability, and it's a fundamental concept that has been adopted by Zanzibar-inspired frameworks mentioned before.&lt;/p&gt;

&lt;p&gt;Expanding on this concept, Zanzibar's relationships weave a structured graph connecting objects. Its strength lies in the straightforward approach: for authorization validation, Zanzibar merely verifies the presence of a certain relationship. Using our previous example, it would simply verify if there's an &lt;code&gt;owner&lt;/code&gt; connection between the document &lt;code&gt;readme&lt;/code&gt; and &lt;code&gt;user456&lt;/code&gt;. To dive deeper into this mechanism and gain a clearer understanding, continue to our next chapter where we dissect the Ory Keto framework, a system inspired by Zanzibar.&lt;/p&gt;

&lt;p&gt;It's worth noting that this explanation is somewhat simplified for clarity. The original Zanzibar paper is a scientific work and delves into greater theoretical depth, but the above should provide readers with a foundational understanding of the core concept.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ory Keto
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ory/keto"&gt;Ory Keto&lt;/a&gt;, written in Go, is an open-source authorization system that pivots around the concept of relation tuples, echoing the foundational principles of Google's Zanzibar. Ory Keto is packaged as a standalone service, offering both HTTPS and gRPC APIs for seamless integration across diverse systems. Recognizing the varied deployment needs of organizations, Ory provides Keto both as a Software as a Service (SaaS) offering and a self-hosted solution, ensuring adaptability across different infrastructural requirements.&lt;/p&gt;

&lt;p&gt;While conceptualizing Ory Keto, certain guiding principles and assumptions were maintained to ensure its efficacy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity in Management&lt;/strong&gt;: The system was built on the hypothesis that no individual or team would dedicate their full time to configuring an authorization system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intuitive Nature&lt;/strong&gt;: Keto is designed to be self-explanatory, minimizing the learning curve and ensuring that users find the system approachable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Familiarity&lt;/strong&gt;: By adhering to familiar paradigms and practices, Keto reduces the onboarding time for developers and system administrators.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ease of Modification&lt;/strong&gt;: Any changes or updates to the authorization configurations can be carried out with high confidence, ensuring system stability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Editorial Support&lt;/strong&gt;: Thanks to the Ory Permission Language, which is a subset of Typescript, Keto is compatible with numerous editors. This ensures users have the flexibility and familiarity in their choice of tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Core Concepts of Ory Keto
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Adoption of the Relation Tuple Model&lt;/strong&gt;: Ory Keto adapts the Zanzibar-inspired relation tuples model. As we’ve previously elaborated, a relation tuple succinctly describes a relationship in a format like &lt;code&gt;namespace:object#relation@subject&lt;/code&gt;. Through these tuples, Ory Keto can express and evaluate intricate hierarchical relationships and permissions across a multitude of objects and users, ensuring a granular and fine-tuned access control mechanism.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ory Permission Language (OPL)&lt;/strong&gt;: OPL, envisioned as a subset of TypeScript, is Ory Keto's method to detail and evaluate policies within its framework. Despite the internal engine of Keto being rooted in Go, OPL offers developers a familiar TypeScript-like syntax to outline intricate authorization policies seamlessly and precisely.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;OPL integrates namespaces and rules to aid in permission evaluations by exploring relations, though the actual tracing is managed by Keto internally. &lt;br&gt;
While Google Zanzibar's model was framed scientifically for researchers and experts, Ory Keto uses TypeScript-based OPL, targeting a broader developer audience for a more user-friendly experience.&lt;/p&gt;
&lt;h4&gt;
  
  
  Ory Permission Language
&lt;/h4&gt;

&lt;p&gt;In Ory Keto, defining namespaces and relations is at the heart of the model. Let's illustrate this with a hands-on example featuring two namespaces: Document and User.&lt;/p&gt;

&lt;p&gt;Within the Document namespace, a user is designated as either an &lt;code&gt;owner&lt;/code&gt;, a &lt;code&gt;viewer&lt;/code&gt;, or an &lt;code&gt;editor&lt;/code&gt; of a document through specific relations.&lt;/p&gt;

&lt;p&gt;The core of authorization revolves around permissions, such as &lt;code&gt;view&lt;/code&gt; or &lt;code&gt;edit&lt;/code&gt;, rather than checking relations like 'owner' or 'editor'. The concrete permission is checked against the relationships. Within the Ory Permission Language, permissions are declared as functions inside the permits property of the corresponding namespace. &lt;/p&gt;

&lt;p&gt;The code provided outlines a basic permission structure, which Keto subsequently processes to generate relation tuples internally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class User implements Namespace {}

class Document implements Namespace {
  related: {
    owners: User[]
    editors: User[]
    viewers: User[]
  }

  permits = {
    view: (ctx: Context): boolean =&amp;gt;
      this.related.viewers.includes(ctx.subject) ||
      this.related.editors.includes(ctx.subject) ||
      this.related.owners.includes(ctx.subject)
  }  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Revisiting Jane with Ory Keto Relations
&lt;/h3&gt;

&lt;p&gt;In our preceding discussions on Role-Based Access Control (RBAC), we introduced Jane, an auditor working for GlobeCorp. Jane was granted 'readonly' access to GlobeCorp's financial data and held the admin role at EcoLife. This time around, let's reframe Jane’s scenario using Ory Keto’s relation tuple framework.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0Y_RA6ig--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/35cab2vieghjy36d3e5q.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0Y_RA6ig--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/35cab2vieghjy36d3e5q.jpg" alt="RBAC" width="800" height="549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's a quick recap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GlobeCorp is a global conglomerate&lt;/li&gt;
&lt;li&gt;TechNovelties and EcoLife are direct subsidiaries of GlobeCorp&lt;/li&gt;
&lt;li&gt;GreenHealth is a specialized vertical of EcoLife&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the OPL, all organizations will be clustered within a singular 'Organization' namespace, with functional dependencies illustrated using the 'parents' relations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Organization implements Namespace {
  related: {
    editors: User[]
    viewers: User[]
    parents: Organization[]
  }

  permits = {
    view: (ctx: Context): boolean =&amp;gt;
      this.related.viewers.includes(ctx.subject) ||
      this.related.editors.includes(ctx.subject) ||
      this.related.parents.traverse((p) =&amp;gt; p.permits.view(ctx))
    edit: (ctx: Context): boolean =&amp;gt;
      this.related.editors.includes(ctx.subject) ||
      this.related.parents.traverse((p) =&amp;gt; p.permits.edit(ctx))      
  }  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The diagram effectively visualizes Jane's direct relations and how they cascade down the organization hierarchy using the parents relation in the context of Ory Keto's permission system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i-rge51e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dlu5nr29yqnu90t0zp6u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i-rge51e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dlu5nr29yqnu90t0zp6u.png" alt="Relations" width="800" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Given this arrangement and the provided OPL:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jane has a &lt;code&gt;viewer&lt;/code&gt; relation to GlobeCorp, allowing her 'readonly' access to its data. This relationship extends hierarchically, meaning Jane can also view data of the companies that are subsidiaries or children of GlobeCorp due to the parents relation, which are TechNovelties and EcoLife.&lt;/li&gt;
&lt;li&gt;Jane, due to her &lt;code&gt;editors&lt;/code&gt; relation with EcoLife, is endowed with edit access to its data. Leveraging the hierarchical structure, this access naturally extends to GreenHealth, EcoLife's subsidiary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Creating Relations in Ory Keto via REST API
&lt;/h3&gt;

&lt;p&gt;Defining namespaces, relations, and permission rules forms the configuration phase in Ory Keto. &lt;br&gt;
Once this setup is complete, you can then dynamically create the actual relations to express relationships between various entities. &lt;br&gt;
This is achieved on-demand via REST API calls.&lt;/p&gt;

&lt;p&gt;To illustrate, let's define a relation that indicates EcoLife is a child organization of GlobalCorp. &lt;br&gt;
You can do this by making a PUT request as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;--request&lt;/span&gt; PUT &lt;span class="s1"&gt;'http://localhost:4467/admin/relation-tuples'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
      "namespace": "Organization",
      "object": "EcoLife",
      "relation": "parents",
      "subject_set": {
        "namespace": "Organization",
        "object": "GlobalCorp",
        "relation": ""
      }
    }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the relation &lt;code&gt;parents&lt;/code&gt; for the object EcoLife points to GlobalCorp, indicating the hierarchical relationship between the two organizations.&lt;/p&gt;

&lt;p&gt;Likewise, to establish a relationship between a user and an object, you would follow a similar approach. &lt;br&gt;
For instance, if you want to specify that the user &lt;code&gt;jane&lt;/code&gt; has a &lt;code&gt;viewers&lt;/code&gt; relation to the organization &lt;code&gt;EcoLife&lt;/code&gt;, you would craft a REST call as such:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;--request&lt;/span&gt; PUT &lt;span class="s1"&gt;'http://localhost:4467/admin/relation-tuples'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
    "namespace": "Organization",
    "object": "GlobalCorp",
    "relation": "viewers",
    "subject_id": "jane"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the subsequent hands-on section, we provide a comprehensive configuration setup for Ory Keto, ensuring that you have all the tools and information at your disposal to effectively establish relations using the REST API.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Hands-on Integration of Ory Keto and Spring Boot
&lt;/h2&gt;

&lt;p&gt;Now that you've had a sip of the theory behind relation-based authorization, it's time to roll up your sleeves and witness it in action. Our destination? A realistic scenario involving the integration of Ory Keto and Spring Boot. &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Cloning the Repository
&lt;/h3&gt;

&lt;p&gt;To kick things off, we have laid out everything on a silver platter for you.&lt;br&gt;
By cloning our repository, you get access to a fully equipped application for our use case and docker-compose file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A PostgreSQL database to store your data.&lt;/li&gt;
&lt;li&gt;Keycloak, already set up with pre-configured users to handle authentication.&lt;/li&gt;
&lt;li&gt;Ory Keto, primed with an OPL definition, ensuring authorization processes are streamlined right from the get-go.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/sw-code/swcode-samples.git
cd swcode-samples/authz/authz-keto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 2: Explore the Code
&lt;/h3&gt;

&lt;p&gt;Within the &lt;code&gt;authz-keto&lt;/code&gt; directory, you'll stumble upon our representation of the Jane and GlobalCorp scenario. &lt;br&gt;
Remember Jane and her relationship with GlobalCorp and its sub-organizations? Yup, that's what we're bringing to life here.&lt;/p&gt;

&lt;p&gt;Now, let's dive deep into the heart of our application: the &lt;code&gt;OrganizationController&lt;/code&gt;. &lt;br&gt;
Two distinct endpoints are waiting to unveil the story of relation-based authorization in action.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Viewing an Organization:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/organizations/{organizationId}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@PreAuthorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hasPermission(#organizationId, 'Organization', 'view')"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getOrganization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathVariable&lt;/span&gt; &lt;span class="n"&gt;organizationId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrganizationDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The beacon guiding us here is the @PreAuthorize annotation. &lt;br&gt;
Notice the "hasPermission" argument? This expression is the gatekeeper, determining if the user can &lt;code&gt;view&lt;/code&gt; the specified Organization.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Updating an Organization:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@PutMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/organizations/{organizationId}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@PreAuthorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hasPermission(#organizationId, 'Organization', 'edit')"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;updateOrganization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nd"&gt;@PathVariable&lt;/span&gt; &lt;span class="n"&gt;organizationId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OrganizationUpdateDto&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrganizationDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Again, the &lt;code&gt;@PreAuthorize&lt;/code&gt; annotation stands guard. This time, however, it's on the lookout for those who wish to &lt;code&gt;edit&lt;/code&gt; the Organization.&lt;/p&gt;

&lt;p&gt;But what brews behind this magical curtain of @PreAuthorize: The &lt;code&gt;KetoPermissionEvaluator&lt;/code&gt;.&lt;br&gt;
This component, a standard approach in Spring Security, implements the &lt;code&gt;PermissionEvaluator&lt;/code&gt; interface and is instrumental in collaborating with Ory Keto to check permissions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;authentication&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Authentication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Serializable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;targetType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;permission&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ketoKetoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targetType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targetId&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;permission&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;String&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 &lt;code&gt;hasPermission&lt;/code&gt; method takes in four arguments:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;authentication: This is an object provided by Spring Security, representing the current user's authentication information.&lt;/li&gt;
&lt;li&gt;targetId: A Serializable ID, in this context, typically the identifier for a specific entity within the system.&lt;/li&gt;
&lt;li&gt;targetType: This string represents the type or category of the entity. In our case, it corresponds to the namespace in Ory Keto.&lt;/li&gt;
&lt;li&gt;permission: Represents the specific action or permission we want to check, such as &lt;code&gt;view&lt;/code&gt; or &lt;code&gt;edit&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Within the method, a call is made to &lt;code&gt;ketoKetoClient.checkPermission(...)&lt;/code&gt;, which, in turn, communicates with Ory Keto via REST API.&lt;/p&gt;

&lt;p&gt;In essence, this method is asking Ory Keto: "Given this user and this specific entity in the provided namespace, do they have the specified permission?"&lt;br&gt;
The response is a Boolean, indicating either permission granted or denied.&lt;/p&gt;

&lt;p&gt;An important detail to note is our choice of using the username directly from the authentication, instead of the typically recommended user ID. &lt;br&gt;
This decision was made purely for illustrative clarity. &lt;br&gt;
While in a production scenario, leveraging UUIDs as the subject would be the standard approach, here we've prioritized a straightforward demonstration to ensure a clear and uncomplicated understanding.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Setup &amp;amp; Configuration
&lt;/h3&gt;

&lt;p&gt;To initialize the necessary test data, we utilize the &lt;code&gt;SampleDataInitializer&lt;/code&gt; class. &lt;br&gt;
This class orchestrates the creation of our well-known GlobalCorp and its associated organizational hierarchies upon application launch. &lt;br&gt;
Additionally, it ensures Jane is granted the appropriate access.&lt;/p&gt;

&lt;p&gt;While user-to-organization relationships are forged directly within this class as part of sample data, &lt;br&gt;
the relationships defining the organizational hierarchies (&lt;code&gt;parents&lt;/code&gt;) are dynamically established. &lt;br&gt;
Whenever a new organization is brought to life in our system, an &lt;code&gt;OrganizationCreatedEvent&lt;/code&gt; is emitted. &lt;br&gt;
This event is the catalyst, triggering the creation of &lt;code&gt;parents&lt;/code&gt; relationships in Ory Keto when necessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Launch &amp;amp; Play
&lt;/h3&gt;

&lt;p&gt;Before launching the application, make sure you've initiated the necessary infrastructure using the supplied docker-compose file.&lt;/p&gt;

&lt;p&gt;Once the application is up and running, test out the endpoints.&lt;br&gt;
Within the repository, there's a Postman collection tailor-made for this hands-on. &lt;br&gt;
This collection includes everything you'll need, from fetching a token from Keycloak for a user to making calls to our endpoints.&lt;br&gt;
Start by trying to retrieve GlobalCorp's data as Jane using GET &lt;code&gt;/organizations/1&lt;/code&gt;. &lt;br&gt;
Since Jane holds viewer permissions, this attempt will succeed. &lt;br&gt;
But if you try to update this data? Expect a "Forbidden" response.&lt;br&gt;
Remember, though, that Jane has editing rights for EcoLife. &lt;br&gt;
This means you can update its information using PUT &lt;code&gt;/organizations/3&lt;/code&gt;. &lt;br&gt;
The same goes for its sub-organization, GreenHealth, accessible via PUT &lt;code&gt;/organizations/4&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Certainly, you might've spotted endpoints like &lt;code&gt;GET /organizations&lt;/code&gt; and &lt;code&gt;POST /organizations&lt;/code&gt; that haven't been enveloped in our authorization discussion yet. &lt;br&gt;
These endpoints, unlike the others, don't target a specific entity and thus require a slightly different approach. &lt;br&gt;
However, fret not; the path forward with Keto will be smooth and intuitive. &lt;br&gt;
The upcoming posts, where we'll delve deeper into these aspects and navigate through other exciting challenges ahead.&lt;/p&gt;

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

&lt;p&gt;In this comprehensive exploration, we dove into the fascinating world of relation-based authorization models. &lt;br&gt;
With its roots deeply embedded in Google's Zanzibar, this approach presents a robust paradigm shift in how we perceive and implement permissions in the digital realm.&lt;/p&gt;

&lt;p&gt;We unveiled a ready-to-use example coupling Spring Boot and Ory Keto, offering readers a tangible demonstration of these concepts in action. &lt;br&gt;
This elucidated how the various building blocks, when seamlessly integrated, can create an effective and secure authorization system.&lt;/p&gt;

&lt;p&gt;As we step further into this domain, our journey is only just beginning. &lt;br&gt;
Looking ahead, there are several compelling challenges to address: &lt;br&gt;
understanding the dynamics of users and roles, managing blocking relations for exception handling, and tackling the demands of searching and filtering with permissions in mind.&lt;/p&gt;

&lt;p&gt;The world of authorization is vast and ever-evolving, and we're just scratching the surface. &lt;br&gt;
Stay with us as we delve deeper into its depths in our forthcoming discussions.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Requirements for a scalable Authorization Architecture</title>
      <dc:creator>SWCode</dc:creator>
      <pubDate>Wed, 27 Dec 2023 15:37:01 +0000</pubDate>
      <link>https://dev.to/swcode/requirements-for-a-scalable-authorization-architecture-4k9n</link>
      <guid>https://dev.to/swcode/requirements-for-a-scalable-authorization-architecture-4k9n</guid>
      <description>&lt;p&gt;Our prior exploration, &lt;a href="https://dev.to/swcode/authorization-basics-35ni"&gt;Authorization Basics&lt;/a&gt; of our &lt;a href="https://dev.to/swcode/scaling-authz-a-journey-into-authorization-architectures-5ef2"&gt;Scaling Authz&lt;/a&gt; blog series, provided a primer on the foundational elements of authorization. Yet as organizations evolve, so too must the systems that safeguard their data and resources. This article delves deeper, defining essential criteria for an adaptive authorization system and starting our journey into their detailed exploration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;When designing an authorization system that scales, it's crucial to prioritize functional requirements that guarantee both performance and user satisfaction. Here are the foundational prerequisites for creating such a system.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Fine-Grained Access Management
&lt;/h3&gt;

&lt;p&gt;Every individual or system component should have tailored access rights. Think of it as ensuring that each employee in a vast company has the right keycard for the specific rooms they need to enter, nothing more and nothing less. Moreover, as businesses evolve and expand, so do their requirements. What starts as a simple access model can soon become a complex web of permissions. Therefore, it's crucial to have an authorization system that not only adapts to these growing needs but is also designed to handle intricate access patterns from the outset. Building flexibility into your system from day one ensures you're not caught off guard when the business asks for a new, nuanced access rule tomorrow.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Built with Security Front and Center
&lt;/h3&gt;

&lt;p&gt;Authorization, at its core, stands as a bastion against unauthorized access to critical resources. But to ensure robustness, the underlying framework employed within the authorization system becomes pivotal. Let's examine some of the foundational pillars that ensure the security of such a framework:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Secure Coding Practices&lt;/strong&gt;: As with any software component, the framework should be developed with best coding practices to avoid common vulnerabilities such as code injection or buffer overflows. Regular security audits and adherence to guidelines like the &lt;a href="https://owasp.org/www-project-top-ten/" rel="noopener noreferrer"&gt;OWASP Top Ten&lt;/a&gt; provide a layer of assurance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensibility without Exposure&lt;/strong&gt;: A scalable authorization architecture must allow for extensions and integrations, but each integration point poses a potential risk. The framework must support secure APIs and integrations, ensuring that extensibility doesn't equate to exposure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strong Encryption Standards&lt;/strong&gt;: Data, especially concerning user roles, permissions, and policies, is critical. The chosen framework should support robust encryption both at rest and in transit, using industry-approved algorithms and protocols.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimal Attack Surface&lt;/strong&gt;: The framework should be lightweight with no unnecessary components or plugins that could be exploited. This "minimalism" reduces the attack surface, making it tougher for adversaries to find vulnerabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regular Patching &amp;amp; Updates&lt;/strong&gt;: Security isn't a one-time affair. As new vulnerabilities are discovered, the framework must be actively maintained and patched, ensuring that known issues are promptly addressed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fine-Grained Auditing and Logging&lt;/strong&gt;: Being able to trace back actions can be a lifesaver when it comes to detecting and investigating security incidents. The framework should offer detailed auditing capabilities, capturing who did what and when.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role and Policy Lifecycle Management&lt;/strong&gt;: Over time, roles may become obsolete, or policies might need refining. The framework should offer mechanisms to safely deprecate roles or adjust policies, ensuring that outdated rules don't become security loopholes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Technology Agnosticism
&lt;/h3&gt;

&lt;p&gt;An effective authorization system must be a universal translator, smoothly integrating across diverse technological landscapes. It shouldn't matter whether one department uses Python and another uses Java. Authorization should be a seamless bridge.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Low Latency
&lt;/h3&gt;

&lt;p&gt;Every time a user interacts with a system, there's a series of backend operations taking place, many of which are invisible to the user. Among these operations is the crucial step of verifying whether the user has the right to perform the action they're attempting. This verification, the permission check, is a constant companion to every API call, database fetch, or file access. For a seamless user experience, these checks must be lightning fast. Any delay, no matter how slight, amplifies with every interaction and request. The cumulative result is a noticeable increase in response time, which could make the difference between an efficient, enjoyable user experience and a slow, frustrating one. Thus, an authorization system must be designed with latency at the forefront, ensuring that these repeated checks don't become bottlenecks in the user's journey.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Cloud-Compatibility
&lt;/h3&gt;

&lt;p&gt;In today's digital landscape, scalability is synonymous with cloud compatibility. Only cloud environments offer the elasticity and on-demand resources necessary to meet the volatile demands of a growing user base. Without a cloud-native design, the architecture would struggle to efficiently scale, both in terms of handling large numbers of users and the vast array of resources they access. It's worth noting: if your architecture doesn't need to thrive in the cloud, you probably don't need a massively scalable authorization system in the first place. Thus, designing for cloud compatibility isn't just about keeping up with technological trends; it's about laying the foundation for the scalable, high-performance system that modern applications demand.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Consistent Authorization Decisions:
&lt;/h3&gt;

&lt;p&gt;Consistency in authorization is paramount. Let's consider two contrasting scenarios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A user has been restricted from accessing a sensitive resource, perhaps due to a change in their role or an observed security risk. If this revocation isn't consistently applied across all instances immediately, there's a potential window where the user can still access this data. Such inconsistencies can lead to unintentional data leaks, unauthorized actions, or breaches.&lt;/li&gt;
&lt;li&gt;Conversely, imagine a user who has just been granted access to specific resources, perhaps as a result of a promotion or a new project assignment. If the system doesn't promptly recognize and enforce this updated permission, the user may face unnecessary access denial errors. This not only hampers their workflow but can also be a significant source of frustration, leading to decreased productivity and satisfaction.
In both scenarios, any change in access rights should be instantly reflected across the system, ensuring that access controls are accurate and reliable at all times, no matter where or when the access request is made.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  7. Simplicity in Maintenance
&lt;/h3&gt;

&lt;p&gt;Just like a well-curated library where one can effortlessly locate and replace books, the components of an authorization system should be designed for ease of modification, replacement, or scaling. This foresight ensures longevity, adaptability, and can lead to cost savings in the long run.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Separation of Concerns&lt;/strong&gt;: Authorization should be managed within its own dedicated layer, distinct from the business logic. Mixing business logic with authorization checks can lead to increased complexity, making updates or changes more prone to errors. Separating these concerns ensures that modifications to one do not inadvertently affect the other.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparent Mechanisms&lt;/strong&gt;: The authorization mechanism should be transparent and replicable. This ensures that, as the team grows or changes, new developers can quickly understand and work with the system without a steep learning curve.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility from Business Requirements&lt;/strong&gt;: While the authorization system must be robust and capable of handling a myriad of scenarios, it should be independent of ever-evolving business requirements. This means that changes in business rules or strategies shouldn't necessitate a reconfiguration of the authorization architecture. The system should be adaptable enough to accommodate these changes without a need for frequent overhauls.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  8. Scalability to Match Growth
&lt;/h3&gt;

&lt;p&gt;As organizations evolve, they often witness a surge in user numbers, resources, and the frequency of requests. An authorization system should not only be comparable to a well-trained athlete, capable of sprinting when demands peak, but also maintain its performance and resilience over extended periods.&lt;/p&gt;

&lt;p&gt;To delve deeper into what scalability truly means in this context:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;User Base Scalability&lt;/strong&gt;: The system should handle a rapid increase in users seamlessly. A tenfold or even hundredfold surge in user numbers shouldn't cause the system to falter or slow down. It should be designed such that adding more users doesn't create an exponential increase in required resources or system load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaptable to Expanding Business Needs&lt;/strong&gt;: As a company grows, it often diversifies, bringing forth new business models, services, and use cases. The authorization system should be flexible enough to accommodate this evolution. Whether there's a need for integrating new services, managing more granular permissions, or interfacing with new technologies, the system should be ready.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service Distribution&lt;/strong&gt;: Modern businesses, especially tech-driven ones, often adopt microservice architectures or other distributed systems. This fragmentation can pose unique challenges to authorization, as permissions may have to be checked and reconciled across various services and databases. A scalable authorization system should, therefore, be prepared to operate efficiently across such distributed environments, ensuring consistent and timely access decisions.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  9. Testability for Peace of Mind
&lt;/h2&gt;

&lt;p&gt;Ensuring the robustness of an authorization system isn't just about design – it's about validation. Testability plays a pivotal role in this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Continuous Validation&lt;/strong&gt;: Integrating an authorization system's test suite with an external library or service is not merely a luxury; it's a necessity. With continuous testing, you can promptly catch any regressions or unexpected behavior changes. The immediacy of feedback accelerates the development process, all the while keeping systems in check.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Assurance&lt;/strong&gt;: Security is a non-negotiable aspect of authorization, and a well-crafted test suite aids immensely in this regard. By thoroughly testing the various authorization scenarios, edge cases, and potential vulnerabilities, developers can confidently make changes and enhancements. The testing framework serves as a safety net, catching any potential breaches or inconsistencies before they go live. This setup empowers developers to focus on the primary task at hand, ensuring top-tier security without getting bogged down by the nitty-gritty of each potential risk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintainability &amp;amp; Scalability&lt;/strong&gt;: As your system grows and evolves, so do its intricacies. A comprehensive test suite ensures that changes, no matter how minor or significant, don't inadvertently disrupt existing functionalities. This not only maintains the health of the system but also scales its resilience. Developers can swiftly integrate new features or scale existing ones, all the while having the assurance that the rest of the system remains unaffected.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Tackling the Essentials
&lt;/h2&gt;

&lt;p&gt;In our quest to establish a solid foundation for scalable authorization, we will embark on a journey through each key requirement. These requirements aren't just academic or theoretical constructs; they represent the core of what it takes to make authorization truly effective and scalable in real-world scenarios. Our exploration begins with arguably one of the most crucial facets: Fine-Grained Access Management.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fine-Grained Access Management: The Heart of Modern Authorization
&lt;/h2&gt;

&lt;p&gt;When discussing authorization, particularly in complex and evolving systems, the need for fine-grained access management becomes paramount. It's no longer sufficient to rely on broad strokes and generalized roles. As business requirements expand, so too does the need for a more nuanced approach to permissions. Let's delve deeper into the complexities of this and understand the nuances.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Limitations of Flat Roles
&lt;/h3&gt;

&lt;p&gt;When we talk about flat roles, we're typically referring to systems where users are assigned broad, general roles such as "admin", "editor", or "viewer". These roles, while simple and intuitive, come with their own set of challenges when implemented within intricate organizational setups.&lt;/p&gt;

&lt;p&gt;In real-world systems, developers often grapple with the limitations of these generalized roles by encoding information directly into the role name. A prime example would be designations like "editor:organization_a". While this might seem like a handy workaround initially, it quickly compounds the complexity of the system and detracts from the initial simplicity that flat roles promised.&lt;/p&gt;

&lt;p&gt;These flat roles are easily understood but come with a host of limitations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Inadequate Representation of Complex Hierarchies&lt;/strong&gt;: In most real-world scenarios, resources and their access patterns are not flat. They follow a complex hierarchy, often with nested levels. For instance, consider a multinational corporation with departments, sub-departments, teams, and sub-teams. A flat role might easily allow access to an entire department but struggles when you need to provide access only to a specific sub-team within that department.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lack of Flexibility&lt;/strong&gt;: With flat roles, the permissions are typically rigid. If you need to give someone access to a resource that doesn't align neatly with these predefined roles, you either risk over-privileging them (by giving them a broader role) or under-privileging them (by denying access they might legitimately need).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance Challenges&lt;/strong&gt;: Over time, as more exceptions and one-off permissions are added to accommodate the inadequacies of flat roles, the system becomes increasingly challenging to manage and maintain. This might lead to inefficient practices like creating a multitude of narrowly defined roles, exacerbating the issue of role explosion.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Role Explosion
&lt;/h3&gt;

&lt;p&gt;As systems aim for more granularity, there's a risk of over-complicating things. When every new business need results in a new role being created, you end up with 'role explosion'. This brings its own set of challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance Nightmare&lt;/strong&gt;: With hundreds of roles, managing and updating them becomes a Herculean task. It's easy to lose track of what each role represents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decreased Security&lt;/strong&gt;: The more roles you have, the harder it is to ensure each is correctly configured. This could lead to security gaps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cognitive Overload&lt;/strong&gt;: For those managing these roles, remembering and understanding the function and scope of each becomes a challenge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Bloat&lt;/strong&gt;: In flat role-based systems, especially those leaning on IDPs, roles are commonly embedded as claims within JWT tokens. Role explosion causes these tokens to become bloated. Consequently, these oversized tokens may exceed the HTTP header size limitations set by some receiving systems, rendering them non-functional due to the token's size. This leads to requests being denied, creating potential operational disruptions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hierarchies and Their Importance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Role Hierarchies
&lt;/h3&gt;

&lt;p&gt;A role hierarchy can be visualized as a pyramid or tree structure, where roles inherit permissions from roles beneath them. In a hierarchical role-based system, each role can encompass the permissions of roles "below" it, making the management of permissions more modular and reducing redundancy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: In a corporate setting, we might have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Employee&lt;/strong&gt;: Basic access to company resources, such as the intranet or time tracking system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manager&lt;/strong&gt;: Inherits all permissions of the Employee role, but also has added permissions like approving timesheets or access to team performance data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Director&lt;/strong&gt;: Inherits all permissions of both Employee and Manager roles. They might also have access to department-wide data, budgeting systems, and strategic planning tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this model, if a basic permission, like accessing the company intranet, needed to be changed, you'd only need to modify it at the Employee level. Both Manager and Director roles would automatically inherit this change, thanks to the hierarchy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resource Hierarchies
&lt;/h3&gt;

&lt;p&gt;Just as roles can be hierarchical, so can resources. Resources are often not flat; they're nested within each other, forming a structured hierarchy. Understanding and modeling these hierarchies is essential for fine-grained access control.&lt;/p&gt;

&lt;p&gt;Let’s take the concept of resource hierarchies and apply it to a scenario we're all familiar with: the structure of a multi-national corporation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GlobeCorp&lt;/strong&gt; is a global conglomerate with its headquarters in New York. This is our “Parent Organization”.&lt;/p&gt;

&lt;p&gt;Under &lt;strong&gt;GlobeCorp&lt;/strong&gt;, there are several subsidiaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TechNovelties in Silicon Valley&lt;/li&gt;
&lt;li&gt;EcoLife in London&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, EcoLife itself has a specialized vertical focused on organic health products named GreenHealth, based in London as well.&lt;/p&gt;

&lt;p&gt;Imagine an employee, let’s call her Jane. Jane is an auditor and is given a 'readonly' access role to the financial data of GlobeCorp. &lt;br&gt;
Due to the hierarchy, this 'readonly' access should automatically extend to both TechNovelties and EcoLife, since they are subsidiaries of GlobeCorp.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpkr8vgx5511b7tjmgsw.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpkr8vgx5511b7tjmgsw.jpg" alt="ReadOnly inheritance"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, Jane's role at EcoLife isn't just to audit. She's also responsible for operations. Thus, she's granted an 'admin' access role specifically for EcoLife. &lt;br&gt;
This 'admin' access, following our hierarchical structure, should grant her broader privileges not just for EcoLife, but also for its child organization, GreenHealth.&lt;/p&gt;

&lt;p&gt;Through this example, it’s evident how roles and access permissions can cascade through a hierarchical system. &lt;br&gt;
It also underscores the importance of having a flexible authorization system that can discern between broad, inherited permissions and specific, assigned ones.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffos6xmiyl6tbxa5zn3an.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffos6xmiyl6tbxa5zn3an.jpg" alt="Admin inheritance"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Exception Handling in Hierarchies
&lt;/h2&gt;

&lt;p&gt;An efficient hierarchy-based system isn't merely about cascading permissions down the chain. It's equally crucial for such systems to provide the capability to make exceptions to the rule, preventing certain permissions even if the hierarchy would naturally grant them.&lt;/p&gt;

&lt;p&gt;Let's revert back to our &lt;strong&gt;GlobeCorp&lt;/strong&gt; scenario. &lt;strong&gt;Jane&lt;/strong&gt;, who has a 'readonly' role at &lt;strong&gt;GlobeCorp&lt;/strong&gt;, and an 'admin' role at &lt;strong&gt;EcoLife&lt;/strong&gt;, might find herself in a tricky situation. Perhaps, due to new data protection regulations, she shouldn't have access to individual health records within &lt;strong&gt;GreenHealth&lt;/strong&gt;, even though her 'admin' role for &lt;strong&gt;EcoLife&lt;/strong&gt; would naturally grant her that access.&lt;/p&gt;

&lt;p&gt;This scenario underscores the necessity of an authorization system that can make nuanced decisions. It should not only grant permissions based on hierarchical roles but also be adept at carving out exceptions based on specific business rules or compliance requirements. Such capabilities ensure that a company remains compliant with both its internal policies and external legal standards.&lt;/p&gt;

&lt;p&gt;Embracing these hierarchical principles with the capacity for exception handling enables businesses to craft an authorization system that is structured yet adaptable, reflecting the real-world complexities of roles and resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion &amp;amp; What's Next
&lt;/h2&gt;

&lt;p&gt;In "Requirements for a Scalable Authorization Architecture," we've taken a deep dive into the essential requirements, both technical and functional, needed for robust authorization. One of the key components we’ve highlighted is the ever-important realm of Fine-Grained Access Management, shedding light on its complexities and indispensable role in modern systems.&lt;/p&gt;

&lt;p&gt;However, our journey is just beginning. As we move forward, subsequent articles will delve deeper into the other requirements, ensuring you have a comprehensive understanding of what it takes to build an effective, scalable, and secure authorization system.&lt;/p&gt;

&lt;p&gt;Stay with us for more insights and deeper explorations into the expansive world of authorization.&lt;/p&gt;

</description>
      <category>security</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Authorization Basics</title>
      <dc:creator>SWCode</dc:creator>
      <pubDate>Mon, 18 Dec 2023 12:56:35 +0000</pubDate>
      <link>https://dev.to/swcode/authorization-basics-35ni</link>
      <guid>https://dev.to/swcode/authorization-basics-35ni</guid>
      <description>&lt;p&gt;Welcome back to our &lt;strong&gt;Scaling Authz&lt;/strong&gt; blog series, where we're documenting our journey toward a scalable and efficient authorization architecture.&lt;/p&gt;

&lt;p&gt;In this second installment of our blog series, we'll delve into the foundational aspects of authorization. We'll explore various models from simple authentication-based authorization, through role-based access control, and up to complex relationship-based models.&lt;/p&gt;

&lt;p&gt;To ensure a hands-on experience, each segment of our series will be accompanied by practical examples and implementation snippets. For those enthusiastic about diving deeper, all resources, code samples, and detailed walkthroughs are readily available in our &lt;a href="https://github.com/sw-code/swcode-samples"&gt;dedicated repository&lt;/a&gt;. We believe that the synergy of theoretical knowledge and hands-on practice paves the way for profound understanding and mastery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication vs Authorization
&lt;/h2&gt;

&lt;p&gt;Authentication: Think of it as the grand entrance—the main gateway to your application. It's about ascertaining "who" stands at the gates. Whether you employ the age-old username-password duo, modern techniques like OAuth, or even the increasingly popular OpenID Connect (often recognized in functionalities like "Login with Google"), the essence remains the same: confirming the identity of the entity trying to gain access. &lt;/p&gt;

&lt;p&gt;Authorization: Once past the main gates, what parts of the castle is one permitted to explore? That's the realm of authorization. It delineates what you're allowed to do once you've made your entrance. The rooms you can enter, the secrets you can access, all fall under its domain.&lt;/p&gt;

&lt;p&gt;In other words, authentication answers the question, "Who are you?" while authorization answers the question, "What are you allowed to do?"&lt;/p&gt;

&lt;p&gt;In real-world applications, the distinctions between authentication and authorization begin to blur as they work hand-in-hand. Once a user's identity is verified, this information is frequently used to determine the permissions they have. For instance, after successfully authenticating, a system might use the user's ID or other attributes to determine which resources or actions they can access.&lt;/p&gt;

&lt;p&gt;This series will primarily center on the nuances of authorization. However, we'll touch upon authentication when it's relevant to the topic at hand. We assume readers are already familiar with, or have in place, a basic authentication system, and there's a bunch of resources available for those looking to further delve into authentication mechanisms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication as Authorization
&lt;/h2&gt;

&lt;p&gt;The simplest form of authorization is when the mere identity of a user is sufficient to grant access to resources. Such scenarios commonly surface in systems engineered for limited functionality or catering to a compact user base. In these instances, user authentication effectively doubles as a form of authorization.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Glimpse into the Process
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;User Accesses Web Application: A user attempts to access a protected resource or service within a web application.&lt;/li&gt;
&lt;li&gt;Authentication Required: Recognizing that the user is not yet authenticated, the application redirects the user to a login page.&lt;/li&gt;
&lt;li&gt;User Authenticates: The user provides their credentials, such as a username and password.&lt;/li&gt;
&lt;li&gt;Token Granted: Upon successful authentication, the identity provider issues a token to the user. This token acts as a proof of the user's identity and might contain claims, roles, or other pertinent information.&lt;/li&gt;
&lt;li&gt;Token Utilized: The web application uses this token to grant the user access to its services and to communicate with backend APIs. It is essential to note that the backend verifies the integrity of this token to ensure it's genuine and hasn't been tampered with.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The flow above is reminiscent of the OAuth2 "Authorization Code Flow", albeit in a simplified manner. It primarily aims to illustrate the core concept of authentication. For those looking for an in-depth dive into OAuth2, consider exploring &lt;a href="https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow"&gt;Auth0's comprehensive guide on the Authorization Code Flow&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorization Models
&lt;/h2&gt;

&lt;p&gt;In the intricate world of authorization, one size seldom fits all. As applications grow and requirements become more nuanced, the mechanisms to decide who gets to do what need to evolve as well. The diversity of use-cases and the need for granularity have given rise to various models of authorization. These models serve as conceptual frameworks, providing structured methods to grant or deny access to resources based on different criteria. From the rudimentary setups that hinged primarily on lists to the more intricate designs that account for dynamic attributes and relationships, the evolution of these models mirrors the increasing complexity of our digital ecosystems.&lt;/p&gt;

&lt;p&gt;Let's dive deeper into some of the prevailing models in authorization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ACL (Access Control List): Stemming from its historical roots in the Unix file system, ACLs provide a list of permissions attached to an object. They are inherently a means to define which user have access to specific objects and the operations they can perform on them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example&lt;/strong&gt;: Think of ACLs like a club's guest list. If your name (and perhaps a specific criterion, like VIP) is on the list, you're allowed entry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application Context&lt;/strong&gt;: ACL would be apt for file-sharing platforms, where individual files/folders can be shared with specific users.&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;RBAC (Role-Based Access Control): A more structured approach, RBAC assigns permissions to specific roles rather than individual users. Users are then assigned to roles. This model offers simplicity and scalability, especially in larger systems where defining permissions for each user can become unwieldy.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example&lt;/strong&gt;: Imagine a hospital. There are doctors, nurses, and administrators. Each role has different access levels in the patient database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application Context&lt;/strong&gt;: RBAC might be ideal for corporate intranets where access needs to be defined by job roles like manager, employee, HR, etc.&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;ABAC (Attribute-Based Access Control): A more dynamic approach, ABAC bases access decisions on policies derived from various attributes—be it of the user, the resource, or even the surrounding environment. For instance, a document might only be accessible during working hours or if a user is located in a specific country. This approach provides nuanced, context-aware authorization.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example&lt;/strong&gt;: A confidential company document that's only accessible from company premises (using location as an attribute) and during working hours.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application Context&lt;/strong&gt;: ABAC is well-suited for complex environments like financial systems where access to resources might depend on various dynamic factors.&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;ReBAC (Relationship-Based Access Control): Building on ABAC, ReBAC incorporates relationships. Access decisions take into account both attributes and their interrelationships. Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Example&lt;/strong&gt;: On Facebook, you can view a friend's private post, but you can't necessarily view the private posts of a friend of a friend unless you're also friends with that person.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application Context&lt;/strong&gt;: Social networking platforms where user relationships play a pivotal role in determining access would greatly benefit from ReBAC.&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;While each model brings its distinct approach, in practice, they often intermingle. Implementations commonly weave elements from multiple models to create a tailored authorization mechanism that comprehensively fulfills specific requirements. The blending of these models in real-world setups reflects the flexibility and complexity required in today's digital ecosystems.&lt;/p&gt;

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

&lt;p&gt;Diving into the practicalities, we'll use a Spring Boot application to breathe life into our conceptual understanding of authorization. Our canvas for this exercise is a modest web service dedicated to managing a list of pets. This service, while simple, will help us demarcate the boundaries between an authenticated user and one that comes adorned with specific roles or permissions.&lt;/p&gt;

&lt;p&gt;For the scope of this chapter, our emphasis will mainly be on &lt;strong&gt;authentication as authorization&lt;/strong&gt;" and on the facets of &lt;strong&gt;Role-Based Access Control (RBAC)&lt;/strong&gt;. As we progress further in the series, we'll delve deeper into intricate authorization mechanisms, but for now, these two paradigms serve as our focal points.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Pet Controller
&lt;/h3&gt;

&lt;p&gt;Consider this Spring Boot PetsController. It offers two endpoints:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An endpoint to fetch a list of pets, accessible by any authenticated user.&lt;/li&gt;
&lt;li&gt;An endpoint to add a new pet, restricted to only those users with the 'admin' role.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PetsController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;pets&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mutableListOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dog"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/pets"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getPets&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pets&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/pets"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@PreAuthorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hasAnyRole('admin')"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;addPet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Pet&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;species&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&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, the &lt;code&gt;@GetMapping&lt;/code&gt; annotation is standard for any Spring Boot application, denoting an HTTP GET endpoint. However, the &lt;code&gt;@PostMapping&lt;/code&gt; is a bit special. It's decorated with the &lt;code&gt;@PreAuthorize&lt;/code&gt; annotation, a component of Spring Security, which states that the following method (in this case, addPet) can only be accessed if the authenticated user has an 'admin' role.&lt;/p&gt;

&lt;p&gt;When a user attempts to post a new pet to our service, the &lt;code&gt;@PreAuthorize&lt;/code&gt; annotation intercepts the request and evaluates the user's roles. If they have the 'admin' role, the method is executed. Otherwise, an access denied response is returned.&lt;/p&gt;

&lt;p&gt;You may wonder: where does this 'admin' role come from and how does the system recognize whether the user possesses this role or not?&lt;/p&gt;

&lt;p&gt;The answer lies in the JSON Web Token (JWT) used by the application for authentication and authorization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1692800905&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1692800845&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iss"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:8090/realms/master"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"aud"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"master-realm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"account"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"84059de0-00e4-43ab-82f5-5b7b217cf8dd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"typ"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"azp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postman"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"acr"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"allowed-origins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"https://oauth.pstmn.io"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"realm_access"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"roles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"admin"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openid profile email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7395ed9c-09d4-449b-9f95-60958afe5f91"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"preferred_username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"admin"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This JWT is a compact, URL-safe means of representing claims between two parties. In the context of our application, the claims within the JWT relay information about the authenticated user to the application. Let's break down some of these claims:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;exp&lt;/code&gt;: This stands for "expiration time". It specifies the time after which the JWT will no longer be accepted. It's a mechanism to ensure that old tokens get discarded and are not misused if intercepted.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;iat&lt;/code&gt;: The "issued at" time claim identifies the time at which the JWT was issued. This can be used to determine the age of the JWT.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;iss&lt;/code&gt;: This is the "issuer" claim. It indicates the issuer of the JWT. In our token, the issuer is specified as &lt;code&gt;http://localhost:8090/realms/master&lt;/code&gt;. Knowing the issuer is vital for validating the authenticity of the token, ensuring it comes from a trusted authority.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sub&lt;/code&gt;: Short for "subject", it identifies the principal entity that is the subject of the JWT. Often, this is used to hold the user ID.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;preferred_username&lt;/code&gt;: This claim provides a human-readable string that identifies the user, which can be used to give a personalized user experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Amongst these claims, the &lt;code&gt;realm_access&lt;/code&gt; claim is particularly interesting for our case. This claim reveals the roles associated with the user within the context of a realm in Keycloak, an open-source identity and access management solution. In our provided token, the user possesses the &lt;code&gt;admin&lt;/code&gt; role within the realm, which correlates with the role our &lt;code&gt;@PreAuthorize&lt;/code&gt; annotation is checking for.&lt;/p&gt;

&lt;p&gt;Now, it's essential to draw attention to the mechanics of how this token is used. As highlighted in our previous chapter on authentication, this JWT token isn't a one-off; it accompanies every request made to the application. It's transmitted as a part of the Authorization header. This persistent presence means that the token, and by extension its claims, must be evaluated repeatedly. Every time the application receives a request, it needs to validate the token and identify the user and his permissions to ensure the right levels of access. This continuous validation plays a pivotal role in maintaining the security and integrity of the application's operations.&lt;/p&gt;

&lt;p&gt;For those interested in a deeper dive into tokens and their functionalities, &lt;a href="https://developer.auth0.com/resources/labs/tools/jwt-basics#introduction"&gt;Auth0's JWT Basics&lt;/a&gt; provides an extensive overview.&lt;/p&gt;

&lt;p&gt;This example highlights a basic use of Role-Based Access Control (RBAC). In this case, roles within the user's token are evaluated by the Spring framework to determine authorization. However, as systems grow and become more complex, challenges can arise. A common issue is "role explosion", where the number of roles becomes too large to manage effectively. In some cases, there may be too many roles to fit within the token's constraints.&lt;/p&gt;

&lt;p&gt;To address this, advanced systems often separate roles or permissions from the token. Instead of including every role directly, they use a user identifier, like the &lt;code&gt;sub&lt;/code&gt; claim (user ID). When a user requests access, this identifier is checked against an external source to determine the user's roles or permissions. This approach is more flexible and scalable, making it easier to handle complex authorization setups.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upcoming
&lt;/h2&gt;

&lt;p&gt;As we journey through this series, we'll delve deeper into more intricate mechanisms with practical exercises, especially Relationship-Based Access Control (ReBAC). This blog is largely centered on the latter, given our keen interest in harnessing the capabilities of &lt;a href="https://research.google/pubs/pub48190/"&gt;Google's Zanzibar&lt;/a&gt;, a powerful system known for its robust ReBAC features. By familiarizing ourselves with these advanced techniques, we aim to demonstrate the potential and flexibility that advanced authorization mechanisms can bring to contemporary applications.&lt;/p&gt;

</description>
      <category>security</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Scaling Authz: A Journey into Authorization Architectures</title>
      <dc:creator>SWCode</dc:creator>
      <pubDate>Tue, 31 Oct 2023 08:46:53 +0000</pubDate>
      <link>https://dev.to/swcode/scaling-authz-a-journey-into-authorization-architectures-5ef2</link>
      <guid>https://dev.to/swcode/scaling-authz-a-journey-into-authorization-architectures-5ef2</guid>
      <description>&lt;p&gt;Welcome to "Scaling Authz," a new series dedicated to exploring the complexities and challenges of implementing scalable authorization architectures, especially within the context of microservice environments. In this series, we will delve into the nuances of authorization, various approaches to solve common problems, and the techniques used by industry leaders to scale their systems.&lt;/p&gt;

&lt;p&gt;The lessons shared here are not purely theoretical. Currently, I am engaged in a customer project where we are actively developing a scalable authorization architecture based on &lt;a href="https://www.ory.sh/keto/"&gt;Ory Keto&lt;/a&gt;. We've moved beyond the conceptual phase and are now diving into the implementation process. I look forward to sharing the progress, challenges, and successes from this hands-on experience with all of you.&lt;/p&gt;

&lt;p&gt;Before we delve into the specifics of our current journey, it's essential to highlight the invaluable experience our team at SWCode has garnered over the years. This isn't our first encounter with the challenges and intricacies of authorization at scale. In fact, we've been running a scalable system based on &lt;a href="https://casbin.org/"&gt;Casbin&lt;/a&gt; successfully for several years.&lt;/p&gt;

&lt;p&gt;This prior experience at SWCode has offered us practical insights and deep knowledge about scalable authorization. The lessons we learned have been instrumental in shaping our approach and decisions as we build and enhance our authorization frameworks. We intend to share these insights throughout this blog series, in the hope that they might aid others navigating the same path.&lt;/p&gt;

&lt;p&gt;If there's one lesson I've learned from my 8 years of cloud-native development, it's this: Never underestimate the power and complexity of authorization. The authentication stage of a user's journey, while crucial, is just the tip of the iceberg. Beneath the surface, a labyrinth of permissions, roles, and policies is waiting to be navigated and understood. Unfortunately, it's a journey many of us embark on too late.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Authentication to Authorization
&lt;/h2&gt;

&lt;p&gt;In the early stages of most projects, the primary focus tends to revolve around authentication - confirming that the user is who they claim to be. Upon successfully validating their identity, the gates to the system swing wide open, granting them access to a broad set of features and data. Initially, this may seem like an adequate solution, particularly for applications with a limited scope or user base.&lt;/p&gt;

&lt;p&gt;However, as business requirements expand and evolve, the needs of the system inevitably become more complex. What was once a modest application might now be dealing with multiple types of users, each requiring distinct levels of access and control. A system that started with a handful of services might have transformed into a microservices landscape, with each microservice managing its own set of resources. This deepening resource hierarchy and the need to precisely control access at various levels herald the onset of a new challenge: authorization.&lt;/p&gt;

&lt;p&gt;At this point, many projects introduce roles and permissions in an attempt to meet their growing authorization needs. A 'role' is a descriptor for a user's function within a system, while 'permissions' determine what actions this role can perform. For instance, an 'admin' role might have permission to 'create', 'read', 'update', and 'delete' all types of resources, while a 'user' role might only have 'read' permission.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Simple Isn't Enough: The Pitfalls of Authorization Workarounds
&lt;/h2&gt;

&lt;p&gt;For a time, this roles-and-permissions model may serve well. It's a flexible system that can handle a variety of scenarios. However, as the application continues to grow, the cracks start to show. A flat model of roles and permissions soon struggles to keep up with the intricacies of a deepening resource hierarchy and an expanding user base with diverse needs. What happens when a specific user needs access to a particular set of resources, but not others? Or when a user's permissions need to vary depending on the context or the specific attributes of the resources they're trying to access?&lt;/p&gt;

&lt;p&gt;That's when we find ourselves in murky waters. The simple roles-and-permissions model, initially perceived as sufficient, starts to buckle under the weight of growing business requirements. The reality we face is that business requirements never stop growing. The resource hierarchy deepens and becomes more complex. And soon enough, we realize that our initial roles, often embedded within the token, no longer suffice. We start finding workarounds, implementing special handling for authorization, digging into the database, and examining roles. Some of us might even modify the business code to accommodate new requirements&lt;/p&gt;

&lt;p&gt;The initial sense of relief that comes with implementing quick fixes and workarounds can quickly give way to a myriad of new problems. As we start to manipulate our authorization mechanisms to fit new, unanticipated requirements, we find ourselves in a precarious situation. Our previously clean and straightforward authorization process now starts to resemble a complex, intertwined web of conditions and exceptions, scattered throughout the codebase.&lt;/p&gt;

&lt;p&gt;One significant downside to this approach is that it makes our system harder to understand and maintain. With special handling and exceptions woven into the business logic, the complexity of our codebase grows. This complexity can create cognitive overhead for developers, increasing the time it takes to onboard new team members and slowing down the debugging and development process.&lt;/p&gt;

&lt;p&gt;Additionally, these workarounds can make our system more fragile. Since these patches are often rushed and not part of the initial design, they may not be covered by our existing test suite. This lack of test coverage can lead to unintended side effects and obscure bugs, which can be difficult to trace back to their source.&lt;/p&gt;

&lt;p&gt;A perhaps more insidious problem is that with every workaround we implement, we start to erode the separation of concerns in our system. The business logic becomes entangled with authorization concerns. This entanglement can lead to a 'spaghetti code' situation, where the business logic and the authorization logic are so intertwined that changing one can inadvertently affect the other.&lt;/p&gt;

&lt;p&gt;Finally, workarounds scattered throughout the business code can easily get lost or forgotten, leading to potential security vulnerabilities. When authorization checks are not centralized in an authorization layer, it's easy to miss some when making changes or additions to the system.&lt;/p&gt;

&lt;p&gt;Arriving at this point in a project often feels like driving at full speed and suddenly spotting a red light in the distance. You must hit the brakes. It's a moment for pause, introspection, and reassessment. We must step back and ask ourselves: "How did we end up here?" It's a pivotal realization, a turning point where we understand that our approach needs a serious reevaluation.&lt;/p&gt;

&lt;p&gt;Speaking from personal experience, I've encountered this scenario numerous times. Project after project, I've seen the same pattern emerge - the struggle to accommodate growing authorization needs within an unprepared system. Each time, it underscores the reality that this is a widespread and commonly underappreciated problem.&lt;/p&gt;

&lt;p&gt;My message to those moving in this direction is clear and direct: Stop. Evaluate your current trajectory and consider its implications. If your project is becoming bogged down in a quagmire of workarounds and patchy fixes to accommodate for growing authorization needs, it's a clear warning sign that your current approach is not sustainable.&lt;/p&gt;

&lt;p&gt;Realize that authorization is not an afterthought, or a 'nice-to-have'. It's not something that can be tacked onto a system with duct tape and good intentions. Authorization is a fundamental building block for any scalable, secure, and flexible system. It should be one of the cornerstones of your architecture, designed and planned for from the start.&lt;/p&gt;

&lt;p&gt;Ignoring or underestimating this fact only leads to a technical debt that becomes increasingly burdensome to pay off. It's a road I've seen many teams travel down, and it always leads to the same destination: a complex, hard-to-maintain system that doesn't meet its users' needs or the security standards of today's digital landscape.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upcoming
&lt;/h2&gt;

&lt;p&gt;In this introductory post of our series, we aim to underscore the criticality of authorization and the complexities it introduces, particularly in microservice ecosystems. As we navigate through this series, we will explore in-depth topics such as the requirements for a scalable authorization architecture, fundamental concepts of authorization, roles, claims, tokens, permission structures, and the impact of &lt;a href="https://research.google/pubs/pub48190/"&gt;Google's Zanzibar paper&lt;/a&gt;, among others.&lt;/p&gt;

&lt;p&gt;Whether you're a seasoned architect seeking to solidify your knowledge or a beginner starting your journey in the world of scalable architectures, this series aims to be a comprehensive guide to mastering the art and science of authorization. So sit back, relax, and join me as we explore the intricate world of authorization in the era of scalability and microservices.&lt;/p&gt;

</description>
      <category>security</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
