Learn how to use policies to implement a pure attribute-based access control (ABAC) model in Fine-Grained Authorization (FGA).
Explore the example from this guide in the FGA Playground, where you can interact with the schema, warrants, and access checks in real-time!
Attribute-Based Access Control (ABAC) is an authorization model that grants access based on attributes of users, resources, environments, and other contextual factors.
FGA allows you to implement a pure ABAC model, where permissions rely solely on attributes without requiring warrant data. By centralizing authorization policies, FGA eliminates hardcoded access logic, making your system more scalable and maintainable.
Note: Starting with a pure ABAC model can be an effective way to remove hardcoded authorization logic while keeping policies flexible. As your needs evolve, you can seamlessly integrate Relationship-Based Access Control (ReBAC) to support permissions based on user-resource relationships, such as team memberships, delegated roles, or hierarchical access.
ABAC is ideal when access rules are complex and depend on multiple dynamic factors such as:
version 0.3 type user type organization relation view_financial_records [] inherit view_financial_records if // Policies can be combined with inheritance rules all_of policy user_in_organization policy is_finance_manager relation view_research_data [] inherit view_research_data if all_of policy user_in_organization policy is_assigned_researcher policy is_within_working_hours type document relation edit [] inherit edit if policy edit_document policy user_in_organization(user_attributes map, organization_id string) { user_attributes.organization_id == organization_id } policy is_finance_manager(user_attributes map) { user_attributes.department == "finance" && "manager" in user_attributes.roles } policy is_assigned_researcher(user_attributes map, project_id string) { user_attributes.role == "manager" && project_id in user_attributes.assigned_projects } policy is_within_working_hours(access_time_epoch_seconds integer) { let second_since_midnight = access_time_epoch_seconds % 86400; // 9 AM (32400s) to 5 PM (61200s) second_since_midnight >= 32400 && second_since_midnight <= 61200 } policy edit_document(user_attributes map, document_attributes map) { let user_is_document_editor = "document_editor" in user_attributes.roles; let draft_status = document_attributes.status == "draft"; let user_can_access_document = document_attributes.organization_id == user_attributes.organization_id; user_is_document_editor && draft_status && user_can_access_document }
Create a file called schema.txt containing the schema definition from above. Then use the CLI to apply this schema to your WorkOS FGA environment.
Note: make sure to select the correct environment with the CLI
workos fga schema apply schema.txt
With our environment setup, we can check the user’s permissions.
import { WorkOS, CheckOp } from '@workos-inc/node'; const workos = new WorkOS('sk_example_123456789'); const checkResult = await workos.fga.check({ op: CheckOp.AllOf, checks: [ { resource: { resourceType: 'organization', resourceId: 'acme', }, relation: 'view_research_data', subject: { resourceType: 'user', resourceId: 'user_2oDscjroNWtzxzYEnEzT9P7VYEe', }, context: { user_attributes: { id: 'user_2oDscjroNWtzxzYEnEzT9P7VYEe', department: 'finance', roles: ['manager'], organization_id: 'acme', assigned_projects: ['project-1', 'project-2'], }, organization_id: 'acme', project_id: 'project-1', access_time_epoch_seconds: 1712653200, }, }, { resource: { resourceType: 'document', resourceId: 'document-1', }, relation: 'edit', subject: { resourceType: 'user', resourceId: 'user_3kLwpXyzQTuvbNApRmC5X4ZhAmd', }, context: { user_attributes: { id: 'user_3kLwpXyzQTuvbNApRmC5X4ZhAmd', department: 'engineering', roles: ['document_editor'], organization_id: 'acme', assigned_projects: ['project-2'], }, document_attributes: { id: 'document-1', organization_id: 'acme', status: 'draft', project_id: 'project-2', }, }, }, ], }); if (checkResult.isAuthorized()) { console.log('Users are authorized'); }