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.
curl "https://api.workos.com/fga/v1/check" \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ --data-raw \ '{ "op": "all_of", "checks": [ { "resource_type": "organization", "resource_id": "acme", "relation": "view_financial_records", "subject": { "resource_type": "user", "resource_id": "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_type": "document", "resource_id": "document-1", "relation": "edit", "subject": { "resource_type": "user", "resource_id": "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" } } } ] }'