Attribute-Based Access Control

Attribute-Based Access Control (ABAC) in Descope allows you to make authorization decisions based on custom attributes stored on users or tenants. Unlike ReBAC, ABAC doesn't use a schema or DSL—instead, you check custom attributes in your application code and/or use them in ReBAC queries to dynamically create relations.

ABAC is part of Descope's Fine-Grained Authorization (FGA) system and can be used alongside RBAC and ReBAC to create comprehensive authorization strategies.

Understanding ABAC

ABAC in Descope is based on checking custom attributes that you define and store on users or tenants. These attributes can represent any characteristics you need for authorization:

  • User Custom Attributes: Department, clearance level, license status, location, subscription tier, etc.
  • Tenant Custom Attributes: Organization type, paid tier, geographical region, compliance level, etc.

Unlike ReBAC (which uses a schema DSL to define relations and permissions), ABAC is implemented by:

  1. Defining Custom Attributes: Create custom attribute definitions in the Descope Console:

  2. Setting Attribute Values: Set values on users or tenants using the Management SDK or Console

  3. Checking Attributes in Code: Check those attributes in your application code to make authorization decisions

Key Differences from ReBAC

FeatureReBACABAC
Schema/DSLUses schema DSL to define types, relations, and permissionsNo schema—uses custom attributes
RelationsCreates explicit relation tuples between users and resourcesChecks attribute values in code
ImplementationDefine schema, create relations, check permissionsSet attributes, check attributes in code
Use CaseResource-specific access (e.g., "user owns document X")Attribute-based access (e.g., "users in department Y can access")

When to Use ABAC

Use ABAC when you need to make authorization decisions based on:

  • User Characteristics: Department, clearance level, license status, subscription tier
  • Tenant Characteristics: Organization type, paid tier, geographical region
  • Dynamic Conditions: Time-based access, location-based access, status-based access
  • Compliance Requirements: Regulatory compliance based on user or tenant attributes
  • Complementing RBAC: Adding attribute checks to role-based permissions (e.g., "Editor role AND department match")
  • Complementing ReBAC: Querying users by attributes and creating explicit relations using the DSL schema

How ABAC Relates to RBAC and ReBAC

ABAC can be used standalone or in combination with RBAC and ReBAC to create comprehensive authorization strategies. Here are three common patterns:

ABAC with RBAC

Use ABAC to add attribute-based conditions to role-based permissions. This pattern is ideal when you need role-based access with additional attribute constraints.

Example: Healthcare Records Access

A doctor can only access patient records if they meet multiple conditions:

  • They have the "Doctor" role (RBAC)
  • Their department matches the patient's department (ABAC)
  • Their medical license status is "active" (ABAC)
  • Their clearance level meets or exceeds the record's sensitivity level (ABAC)
// Check RBAC role
const hasDoctorRole = user.roleNames.includes('Doctor');
 
// Check ABAC attributes
const departmentMatch = user.customAttributes.department === patient.department;
const hasActiveLicense = user.customAttributes.licenseStatus === 'active';
const hasRequiredClearance = 
  user.customAttributes.clearanceLevel >= record.sensitivityLevel;
 
// Combined authorization decision
const canAccessRecord = hasDoctorRole && departmentMatch && 
                        hasActiveLicense && hasRequiredClearance;

Example: Department-Based Document Editing

An editor can only edit documents in their department:

  • They have the "Editor" role (RBAC)
  • Their department matches the document's department (ABAC)
  • Their account status is "active" (ABAC)
const canEdit = user.roleNames.includes('Editor') && 
                user.customAttributes.department === document.department &&
                user.customAttributes.accountStatus === 'active';

ABAC with ReBAC

Use ABAC attributes with ReBAC by checking attributes first, then performing the ReBAC check. This approach combines attribute-based filtering with relationship-based access without requiring you to maintain relations based on attributes.

Example: Department-Based Document Access

Check if a user in the "Engineering" department can view a document:

  1. Check the user's department attribute (ABAC)
  2. If attributes pass, perform the ReBAC check to verify relationship-based access (ReBAC)
// 1. Check user's department attribute (ABAC)
const user = await descopeClient.management.user.load(loginId);
if (user.customAttributes?.department !== 'Engineering') {
  return false; // Attribute check failed
}
 
// 2. If attributes pass, check ReBAC relation
const canView = await descopeClient.management.fga.check([{
  resource: 'engineering-roadmap',
  resourceType: 'doc',
  relation: 'can_view',
  target: user.userId,
  targetType: 'user',
}]);
 
return canView[0].allowed;

Example: Time-Based Access with ReBAC

Grant access to a document only if the user is in the correct department AND it's during business hours:

  1. Check department attribute (ABAC)
  2. Check time-based attribute (ABAC)
  3. If both pass, perform the ReBAC check (ReBAC)
const user = await descopeClient.management.user.load(loginId);
const currentHour = new Date().getHours();
 
// ABAC checks
const departmentMatch = user.customAttributes?.department === 'Engineering';
const isBusinessHours = currentHour >= 9 && currentHour < 17;
 
if (!departmentMatch || !isBusinessHours) {
  return false;
}
 
// ReBAC check
const canView = await descopeClient.management.fga.check([{
  resource: 'engineering-roadmap',
  resourceType: 'doc',
  relation: 'can_view',
  target: user.userId,
  targetType: 'user',
}]);
 
return canView[0].allowed;

Standalone ABAC

Use ABAC alone when authorization is purely attribute-based without roles or relations. This is ideal for feature flags, subscription tiers, or simple attribute-based access control.

Example: Subscription-Based Feature Access

Allow access to premium features based on subscription tier:

const canAccessPremiumFeature = 
  user.customAttributes.subscriptionTier === 'premium' ||
  user.customAttributes.subscriptionTier === 'enterprise';

Example: Multi-Tenant Feature Access

Control feature access based on tenant attributes:

const tenant = await descopeClient.management.tenant.load(tenantId);
 
// Premium features only for premium tier tenants
const canAccessPremiumFeature = 
  tenant.customAttributes.subscriptionTier === 'premium';
 
// Geographic restrictions
const canAccessRegionalFeature = 
  tenant.customAttributes.region === 'US' || 
  tenant.customAttributes.region === 'EU';
 
// Compliance-based features
const canAccessHIPAAFeature = 
  tenant.customAttributes.complianceLevel === 'HIPAA';

Example: Time-Based Access Control

Restrict access based on time attributes:

const currentHour = new Date().getHours();
const userShift = user.customAttributes.shift; // 'morning', 'afternoon', 'night'
 
// Only allow access during user's shift
const canAccess = 
  (userShift === 'morning' && currentHour >= 6 && currentHour < 14) ||
  (userShift === 'afternoon' && currentHour >= 14 && currentHour < 22) ||
  (userShift === 'night' && (currentHour >= 22 || currentHour < 6));

For detailed implementation instructions and code examples, see Implementing ABAC.

Next

Continue to learn about implementing ABAC with detailed code examples and best practices.

Was this helpful?

On this page