Use policies to implement advanced attribute based access control with FGA, providing relevant data from your application at access control check time.
WorkOS FGA allows you to define custom logic that is executed when evaluating access checks. A policy is a boolean expression that specifies additional conditions to be satisfied in order for an access check to be authorized. Use policies to enforce complex rules and conditions that go beyond simple role-based access control (RBAC) or attribute-based access control (ABAC).
Policies can be defined on warrants or as part of your schema.
FGA currently supports defining policy expressions using expr. Support for more policy languages will be coming soon.
You can optionally include a policy in a warrant. For a warrant to match a check/query, its policy must evaluate to true. The system evaluates policies after matching the warrant based on its resource, relation, and subject attributes. It evaluates the policy in the context of the check/query request, using any dynamic values provided via the context attribute (see context below) to process the expression.
For example, the following warrant states that [role:accountant] is a [member] of [permission:view-profits-and-losses]
only when companyId == 'wayne-enterprises'
:
{ "resource_type": "permission", "resource_id": "view-profits-and-losses", "relation": "member", "subject": { "resource_type": "role", "resource_id": "accountant" }, "policy": "companyId == 'wayne-enterprises'" }
Policies can reference dynamic variables. You must provide values for these variables in check or query requests via the context attribute (e.g., role, tenant, or geographic location). Before evaluating a policy, the system substitutes the provided values into the expression. Policy expressions undergo static type checking, so type mismatches prevent evaluation from returning true. Policies with missing values or evaluation errors also do not return true. The system compiles and statically checks policies for errors upon creation.
Policies have numerous uses but are most commonly used to implement forms of attribute-based access control (ABAC). For example, create a warrant that only matches users visiting from a specific IP address:
{ "resource_type": "database", "resource_id": "prod", "relation": "admin", "subject": { "resource_type": "user", "resource_id": "ops-user" }, "policy": "user.client_ip == '192.168.1.1'" }
Combine policies with role-based access control (RBAC) to support different role/permission mappings per customer or tenant. For example, define a warrant stating that [role:accountant]
grants [permission:view-balance-sheet]
only when companyId == 'wayne-enterprises'
:
{ "resource_type": "permission", "resource_id": "view-balance-sheet", "relation": "member", "subject": { "resource_type": "role", "resource_id": "accountant" }, "policy": "companyId == 'wayne-enterprises'" }
Create another warrant specifying that [role:accountant]
grants users [permission:view-profits-and-losses]
only when companyId == 'daily-planet'
:
{ "resource_type": "permission", "resource_id": "view-profits-and-losses", "relation": "member", "subject": { "resource_type": "role", "resource_id": "accountant" }, "policy": "companyId == 'daily-planet'" }
Make access checks, passing in different companyId
values via the context
based on the company a user belongs to:
{ "checks": [ { "resource_type": "permission", "resource_id": "view-profits-and-losses", "relation": "member", "subject": { "resource_type": "role", "resource_id": "accountant" }, "context": { "companyId": "wayne-enterprises" } } ] }
This access check returns false
because [role:accountant]
only grants [permission:view-profits-and-losses]
within the context of company daily-planet
.
You can reference policies in your schema, allowing you to define and reuse complex rules across different relations and inheritance rules. Use policies in the inherit clause of your schema definition. For example, consider the following schema:
version 0.3 type user type organization relation view [] inherit view if policy ip_allowed
Here, the view
relation is inherited based on the ip_allowed policy. Users must meet the ip_allowed policy conditions to gain the view permission.
Make sure schema version is set to 0.3
or higher to use policies in your schema.
Unlike warrant policies, schema policies are defined separately and referenced by name in schema rules. In the WorkOS FGA Dashboard Schema Editor, hover over a policy reference to view its expression and required parameters.
In a future release, you can reference named policies from warrants.
WorkOS FGA provides API endpoints to create policies programmatically. Use these endpoints to create, update, retrieve, and delete policies.
See Policies API documentation for more details.
Dashboard and WorkOS CLI tools for policy management are coming soon.
WorkOS FGA is continuously improving its policy support to enable better tooling for syntax validation and additional policy definition languages. Instead of embedding policies directly in the schema, policies will remain separate to allow specialized tooling for different policy languages. These upcoming enhancements will:
When making an FGA check, pass the required context values as you would with warrant policies. FGA evaluates warrant and schema policies together during access checks.
{ "checks": [ { "resource_type": "organization", "resource_id": "acme", "relation": "view", "subject": { "resource_type": "user", "resource_id": "1" }, "context": { "clientIp": "192.168.1.1" } } ] }
Combine policies with inheritance rules to create complex access control models. For example, define a policy that checks specific conditions and apply it across multiple relations or inheritance rules:
version 0.3 type user type staff_group relation member [user] type org_role relation member [user] type organization relation internal_admin [staff_group] relation viewer [user, org_role] relation view_feature_1 [] inherit view_feature_1 if any_of relation member on internal_admin [staff_group] all_of any_of relation viewer relation member on viewer [org_role] policy valid_payment_plan
In this example:
view_feature_1
access can be inherited based on multiple conditions.staff_group
members) can access view_feature_1
.viewer
or an org_role
can also access it if they meet the valid_payment_plan
policy requirements.Using policies and inheritance rules together provides a powerful way to model permissions for:
To start using policies in your schema, ensure the following: