Query which resources users have access to in your application.
The Query Language is a declarative, SQL-like language used to query WorkOS FGA for (1) the set of resources a particular subject has access to or (2) the set of subjects who have access to a particular resource. Examples of queries that can be specified with the query language include:
user:A
is a viewer
on.editor
s of document:finance-report
.user:malicious
has access to.view-financial-reporting
.A query is composed of a select
clause and either a for
clause (if querying for subjects) or a where
clause (if querying for resources):
select permission where user:tony-stark is member
The select clause specifies whether a query should return resources a subject has access to or return subjects that have access to a resource.
Return resources a subject has access to
select <resource_types>
<resource_types>
can be a comma separated list of one or more resource types that results of the query will be filtered to. To select resources matching any resource type, pass a wildcard (*
) instead.
Return subjects that have access to a resource.
select <relations> of type <subject_types>
<relations>
and <subject_types>
can be comma separated lists of one or more relations or one or more resource types respectively, that results of the query will be filtered to. To match any relation or any subject type, pass a wildcard (*
) for the <relations>
or <subject_types>
properties respectively.
When selecting resources (e.g. select tenant
), provide a where
clause to specify a subject and one or more relations that subject must have on any resources returned in the query result.
select <resource_types> where <subject> is <relations>
<subject>
must be a resource in the format <resource_type>:<resource_id>
. <relations>
can be a comma separated list of one or more relations. To match any relation, pass a wildcard (*
) instead.
When selecting subjects (e.g. select member of type user
), provide a for
clause to specify a resource and one or more relations subjects must have on the specified resource to be returned in the query result.
select <relations> of type <subject_types> for <resource>
<relations>
and <subject_types>
can be comma separated lists of one or more relations or one or more resource types respectively. To match any relation or any resource type respectively, pass a wildcard (*
) instead.
A query can optionally include the explicit
keyword immediately following the select
keyword to indicate that the query should only return results that explicitly match the provided relations. Explicit results are results for which a warrant matching one or more of the relations specified in the query explicitly exists. Implicit results are results which may implicitly match the relations specified in the query through inheritance rules. Without the explicit
keyword specified, a query will return both explicit and implicit results.
select explicit viewer of type user for document:doc1
select viewer of type user for document:doc1
Schema policies are not supported in the current Query implementation. Any access results that are granted only by schema policies (as determined via the check endpoint) will be excluded from query responses.
This limitation exists because schema policies are fundamentally more complex than warrant policies. While warrant policies apply to specific relationships (e.g., user:1 is viewer of document:doc1), schema policies define rules that apply across all resources of a certain type and relation – for example, every viewer of every document.
This generalization introduces two core issues:
Given these challenges, schema policies should be evaluated like traditional policy engines – by explicitly checking access between individual subjects and resources. This is what the check endpoint is for.
Warrant policies are supported in query, since they conditionally create specific relationship edges rather than applying general rules.
To check access to a list of resources when using schema policies, you have two options:
The query engine does not support join semantics across relationships. For example, a query like:
select viewer of type user for document:doc1 where group is viewer
…is not supported directly.
To achieve a similar behavior, you could do one of the following:
type user type group relation member [user] type document relation viewer [user, group] relation group_viewer [] // Query for documents where a user is a viewer through their group membership inherit group_viewer if relation member on viewer [group] inherit viewer if relation member on viewer [group]
Then you can query for the new relation:
select group_viewer of type user for document:doc1
If you want to intersect results of two queries, you can use an all_of
rule in your schema to define a new relation that combines the results of two existing relations. For example:
type document relation subscriber [user] relation owner [group] inherit subscriber_and_owner if all_of relation owner relation subscriber inherit owner if relation member on owner [group]
Then you can query for the new relation:
select subscriber_and_owner of type user for document:doc1
select viewer of type group for document:doc1 select member of type user for group:xyz // using groups from prior query
select viewer of type group for document:doc1
Then you can batch check user:xyz
on all viewer groups
for document:doc1
.
select document where user:1 is viewer
select explicit document where user:1 is viewer
select document where user:1 is *
select * where user:1 is *
select viewer of type user for document:doc1
select explicit viewer of type user for document:doc1
select * of type user for document:doc1
select * of type * for document:doc1