Warrants specify relationships between resources in your application.
Warrants are access rules that specify relationships between the resources in your application (e.g. [store:A] is [parent] of [item:123]
). WorkOS FGA uses the set warrants and resource types for an application to answer access checks and queries. Individual warrants define explicit relations between resources while resource types define rules (policies) by which some relationships can exist implicitly.
tenant:stark-industries # admin @ user:tony-stark | | | Resource Relation Subject
Each warrant is composed of three core attributes and an optional policy (more on this later):
resource_type
and a resource_id
. The resource_type
must refer to a valid resource type defined for the application. The resource_id
must be a unique identifier used by the application to identify the resource.resource_type
. It is often used to specify an action the warrant will grant the subject the ability to perform on the resource (e.g. editor
, viewer
, etc.).resource_type
, and a resource_id
, and optionally a relation
(to specify a group of subjects). A subject’s resource_type
must refer to a valid resource type defined for the application, and its resource_id
must be a unique identifier used by the application to identify the resource. While the subject will often times be an individual user or resource, the subject can also specify a group of resources (e.g. in group warrants).true
in order for the warrant to be considered a match for the check/query. If a warrant’s resource, relation, and subject attributes do not match the requested check/query or the policy expression evaluates to false
, the warrant will not be matched during evaluation of the check/query. The policy attribute can be used to implement a form of attribute-based access control (ABAC).Here is an example warrant specifying that the subject user:ABC
has the relation editor
on resource item:123
:
{ "resource_type": "item", "resource_id": "123", "relation": "editor", "subject": { "resource_type": "user", "resource_id": "ABC" } }
A direct warrant represents a relationship between a resource and a specific subject. For example, we can define a warrant specifying that [user:1] is a [member] of [role:admin]
:
{ "resource_type": "role", "resource_id": "admin", "relation": "member", "subject": { "resource_type": "user", "resource_id": "1" } }
In some cases, we might need to specify a relationship between a resource and a group of subjects (e.g. [member]s of [role:admin]
, [manager]s of [tenant:acme]
, etc). Group warrants are warrants that include the optional relation
attribute on the subject
. They specify that all resources matching the subject’s resource_type
, resource_id
, and relation
will have the specified relation
on the resource. For example, we can define a group warrant specifying that [member]s of [role:admin] are [editor]s of [report:1]
:
{ "resource_type": "report", "resource_id": "1", "relation": "editor", "subject": { "resource_type": "role", "resource_id": "admin", "relation": "member" } }
Warrants can optionally include a policy. A policy is a boolean expression specifying additional conditions that must be satisfied in order for a warrant to match an access check or query. In other words, if a warrant is matched during a check/query via its resource, relation, and subject, the warrant’s policy (if it has one) must also be evaluated in order to determine whether or not the warrant matches the check/query. If the policy evaluates to true
the warrant is matched. Otherwise, it is not matched.
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 variables whose values are dynamic. The value these variables must be provided in check or query requests via the context attribute (i.e. contextual information from your application such as a role, a tenant, a geographic location, etc). Before a policy is evaluated, the values provided via context are substituted into the expression so the expression can be evaluated. Policy expressions are statically type checked, so type mismatches between values will not evaluate to true
. Policies with incomplete values (i.e. when the value for one or more variables in the expression is not provided in the context) or policies that encounter an error during evaluation will also not evaluate to true
. Note that policies are compiled and statically checked for errors upon creation.
Policies have numerous uses but are most commonly used to implement forms of attribute-based access control (ABAC). For example, we can create a warrant with a policy 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'" }
When combined with role-based access control (RBAC), policies allow an application to support different role/permission mappings per customer or tenant. For example, we can create a warrant specifying that [role:accountant]
grants users [permission:view-balance-sheet]
only for companyId == 'wayne-enterprises'
:
{ "resource_type": "permission", "resource_id": "view-balance-sheet", "relation": "member", "subject": { "resource_type": "role", "resource_id": "accountant" }, "policy": "companyId == 'wayne-enterprises'" }
And another warrant specifying that [role:accountant]
grants users [permission:view-profits-and-losses]
only for 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'" }
We can then make access checks, passing in different values for companyId
via the context
based on the company a user belongs to in our application:
{ "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 will return false
because [role:accountant]
only grants [permission:view-profits-and-losses]
within the context of company daily-planet
.
Warrants can be created directly in the FGA dashboard or programmatically via API. Refer to the Warrants API Reference to learn more about managing Warrants via API.