Relationship-Based Access Control

Understanding ReBAC

Descope supports full Relationship-Based Access Control (ReBAC) to manage access permissions in your application based on relationships between entities. Create a schema, define relationships, and add checks to your application using our APIs and SDKs.

Practical Scenario for ReBAC instead of RBAC

An E-commerce platform

With RBAC, access is granted based on roles like Seller, Buyer, or Admin. A seller with a generic seller role would have the same access rights as any other seller, which might include managing listings, processing orders, and handling customer queries.

However, RBAC could have limitations in this scenario:

  • One-Size-Fits-All: All sellers have identical access privileges regardless of their specific relationship with the buyer or the product. For example, sellers cannot offer personalized deals or discounts to repeat customers or manage after-sale services uniquely for each customer.
  • Static Permissions: The RBAC system cannot easily accommodate temporary or conditional permissions, such as allowing a buyer to track the progress of a custom-made item directly through the seller's interface.

ReBAC, on the other hand, can provide access controls that adapt to the relationships between users:

  • Seller-Customer Relationships: Sellers might give specific customers special access to pre-orders or exclusive products based on their purchase history or membership status.
  • Collaborative Features: For custom-made items, the relationship between a buyer and seller could allow for a direct communication channel within the platform, enabling the buyer to provide input or get updates on their order's progress.
  • Dynamic Permissions: Access permissions can evolve in real-time. For instance, a buyer might have temporary access to a seller's design tool to customize a product, which expires after the order is finalized. In the e-commerce platform scenario, ReBAC allows for a more nuanced and customer-centric approach. It enables dynamic access control based on the evolving relationships between sellers, buyers, and products. In contrast, RBAC's static roles might not effectively handle the varied and personalized interactions that modern e-commerce platforms often facilitate.

Implementing ReBAC in Descope

The general process of setting up ReBAC in Descope is as follows:

  1. Defining a schema: Establish the types of entities (e.g., user, document) and the possible relationships (e.g., owner, editor) that exist within your application.
  2. Saving a schema: Store the schema in a way that it can be efficiently queried and managed, ensuring it can be updated as the relationships evolve.
  3. Creating relations: Build out the actual linkages between specific entities based on your defined schema, which will serve as the foundation for making access decisions.
  4. Adding relations checks: Integrate checks into your application to consult the defined relationships and confirm if a user's action is authorized.

A full code example

After you've completed the aforementioned steps, you'll have employed code looking something like the below, with everything from implementing a schema to creating and checking relations. The schema is loaded from a YAML file (as shown in the define schema example section), and the relations are created and checked using the Descope SDK.

const file = fs.readFileSync(option.input, 'utf8'); // Read the file
const schema: AuthzSchema = JSON.parse(file); // Parse the file into a schema object
const authzService = descopeClient.management.authz;
const existingSchema: AuthzSchema = await authzService.loadSchema();
if (existingSchema.name !== schema.name) {
  await authzService.deleteSchema();
  await authzService.saveSchema(schema, true);
  const relations: AuthzRelation[] = [{
    resource: 'some-doc',
    relationDefinition: 'owner',
    namespace: 'doc',
    target: 'u1'
  },
  {
    resource: 'some-other-doc',
    relationDefinition: 'editor',
    namespace: 'doc',
    target: 'u2'
  }]
  await authzService.createRelations(relations);
}
const relationQueries: AuthzRelationQuery[] = [{
  resource: 'some-doc',
  relationDefinition: 'owner',
  namespace: 'doc',
  target: 'u1'
},
{
  resource: 'some-other-doc',
  relationDefinition: 'editor',
  namespace: 'doc',
  target: 'u2'
}];
const resp = await authzService.hasRelations(relationQueries);
 
assert(resp[0].hasRelation);
assert(resp[1].hasRelation);
 
const resource: string = 'some-doc';
const relationDefinition: string = 'editor';
const namespace: string = 'doc';
const users: string[] = await authzService.whoCanAccess(resource, relationDefinition, namespace);
 
const relations: AuthzRelation[] = authzService.resourceRelations(resource);
 
const targets: string[] = ['u1', 'u2'];
const relations: AuthzRelation[] = authzService.targetsRelations(targets);
 
const target: string = 'u1';
const relations: AuthzRelation[] = authzService.whatCanTargetAccess(target);

Next

Now that you have a high-level vision of the ReBAC implementation process, let's move on to defining a schema.

Was this helpful?

On this page