Configuration Language
note
Please note that at this point in time, it is not considered production-ready and does not come with any SLAs; availability and uptime are not guaranteed. Limitations of Auth0 FGA during the Developer Community Preview can be found here.
The Auth0 Fine Grained Authorization (FGA)'s Configuration Language is used to build a representation of a system's authorization model. It informs Auth0 FGA's API on what the object types in the system are and how they could relate to one another. It describes the relations possible on an object of a certain type and lists the conditions under which one is related to that object.
The DSL and the JSON syntax are two presentations of that configuration language. The JSON syntax is accepted by the API and closely matches the API described in the Zanzibar paper. The DSL is syntactic sugar on top of the JSON syntax and compiles down to it before being sent to Auth0 FGA's API. The DSL is meant to make modeling easier and more intuitive.
You'll encounter the JSON syntax when calling the API directly or through the SDKs, and the DSL when interacting with Auth0 FGA through the Playground or the Management Dashboard. Throughout the documentation, you will see both forms (the DSL and the JSON syntax) in most of the pages, and can switch between them.
To better understand this guide correctly, you should be familiar with some Auth0 FGA Concepts and how to get started on modeling.
What does the configuration language look like?
Below is a sample authorization model. In the next sections we'll go over the building blocks that make the Auth0 FGA configuration language.
- DSL
- JSON
type domain
relations
define member as self
type folder
relations
define can_share as writer
define owner as self or owner from parent_folder
define parent_folder as self
define viewer as self or writer or viewer from parent_folder
define writer as self or owner or writer from parent_folder
type document
relations
define can_share as writer
define owner as self or owner from parent_folder
define parent_folder as self
define viewer as self or writer or viewer from parent_folder
define writer as self or owner or writer from parent_folder
{
"type_definitions": [
{
"type": "domain",
"relations": {
"member": {
"this": {}
}
}
},
{
"type": "folder",
"relations": {
"can_share": {
"computedUserset": {
"object": "",
"relation": "writer"
}
},
"owner": {
"union": {
"child": [
{
"this": {}
},
{
"tupleToUserset": {
"tupleset": {
"object": "",
"relation": "parent_folder"
},
"computedUserset": {
"object": "",
"relation": "owner"
}
}
}
]
}
},
"parent_folder": {
"this": {}
},
"viewer": {
"union": {
"child": [
{
"this": {}
},
{
"computedUserset": {
"object": "",
"relation": "writer"
}
},
{
"tupleToUserset": {
"tupleset": {
"object": "",
"relation": "parent_folder"
},
"computedUserset": {
"object": "",
"relation": "viewer"
}
}
}
]
}
},
"writer": {
"union": {
"child": [
{
"this": {}
},
{
"computedUserset": {
"object": "",
"relation": "owner"
}
},
{
"tupleToUserset": {
"tupleset": {
"object": "",
"relation": "parent_folder"
},
"computedUserset": {
"object": "",
"relation": "writer"
}
}
}
]
}
}
}
},
{
"type": "document",
"relations": {
"can_share": {
"computedUserset": {
"object": "",
"relation": "writer"
}
},
"owner": {
"union": {
"child": [
{
"this": {}
},
{
"tupleToUserset": {
"tupleset": {
"object": "",
"relation": "parent_folder"
},
"computedUserset": {
"object": "",
"relation": "owner"
}
}
}
]
}
},
"parent_folder": {
"this": {}
},
"viewer": {
"union": {
"child": [
{
"this": {}
},
{
"computedUserset": {
"object": "",
"relation": "writer"
}
},
{
"tupleToUserset": {
"tupleset": {
"object": "",
"relation": "parent_folder"
},
"computedUserset": {
"object": "",
"relation": "viewer"
}
}
}
]
}
},
"writer": {
"union": {
"child": [
{
"this": {}
},
{
"computedUserset": {
"object": "",
"relation": "owner"
}
},
{
"tupleToUserset": {
"tupleset": {
"object": "",
"relation": "parent_folder"
},
"computedUserset": {
"object": "",
"relation": "writer"
}
}
}
]
}
}
}
}
]
}
info
The authorization model describes three types of objects: domain
, folder
and document
.
The domain
type definition has a single relation called member
that only allows direct relationships.
The folder
and document
type definitions each have five relations, parent_folder
, owner
, editor
, viewer
and can_share
.
The Direct Relationship Keyword
self
, when used in the context of the relation definition allows direct relationships to the objects of this type. The absence of self
disallows these direct relationships.
info
self
in the Auth0 FGA DSL translates to this
in the Auth0 FGA API syntax.
For example, let's take a closer look at the team
type.
- DSL
- JSON
type team
relations
define member as self
{
"type": "team",
"relations": {
"member": {
"this": {}
}
}
}
This team
type definitions defines all relations users can have with object of type team
. In this case the relations are: member
.
Due to the direct relationship keyword (self
) being used, this means that a user in the system can have a direct relationship with the team
type as a member
.
In the type definition snippet above, anne
is a member
of team:product
if any one of the following relationship tuple sets exist:
[
// Anne is directly related to the product team as a member
{
"user": "anne",
"relation": "member",
"object": "team:product",
},
][
// Everyone (`*`) is directly related to the product team as a member
{
"user": "*",
"relation": "member",
"object": "team:product",
},
][
// Members of the contoso team are members of the product team
{
"user": "team:contoso#member",
"relation": "member",
"object": "team:product",
},
// Anne is a member of the contoso team
{
"user": "anne",
"relation": "member",
"object": "team:contoso",
},
]
For more examples, take look at Modeling Concepts: Direct Relationships.
Referencing Other Relations on the Same Object
You can also reference other relations on the same object. Let us look at a simplified document
type definition.
- DSL
- JSON
type document
relations
define editor as self
define viewer as self or editor
define can_rename as editor
{
"type": "document",
"relations": {
"editor": {
"this": {}
},
"viewer": {
"union": {
"child": [
{
"this": {}
},
{
"computedUserset": {
"relation": "editor"
}
}
]
}
},
"can_rename": {
"computedUserset": {
"relation": "editor"
}
}
}
}
The above document
type definition defines all the relations users can have with an object of type document
. In this case the relations are: editor
, viewer
and can_rename
.
The viewer
and can_rename
relation definitions are both referencing editor
, which is another relation on the same type.
info
Notice how can_rename
does not reference the direct relationship keyword (self
), indicating that a direct relationship is not possible (as in a user cannot be directly assigned this relation, it has to be inherited through an assignment of the editor
relation). The viewer
relation on the other hand allows both direct and indirect relationships using the Union Operator.
In the type definition snippet above, anne
is a viewer
of document:new-roadmap
if any one of the following relationship tuple sets exists:
anne is an editor of document:new-roadmap
[
// Anne is an editor of the new-roadmap document
{
"user": "anne",
"relation": "editor",
"object": "document:new-roadmap",
},
]anne is a viewer to document:new-roadmap
[
// Anne is a viewer of the new-roadmap document
{
"user": "anne",
"relation": "viewer",
"object": "document:new-roadmap",
},
]
anne
has a can_rename
relationship with document:new-roadmap
only if anne has an editor
relationship with the document:
- anne is an editor of document:new-roadmap
[
// Anne is an editor of thew new-roadmap document
{
"user": "anne",
"relation": "editor",
"object": "document:new-roadmap",
},
]
For more examples, take look at Modeling Concepts: Concentric Relationships, Modeling Basics: Roles and Permissions and Advanced Modeling: Google Drive.
Referencing Relations on Related Objects
Another form of indirect relationships is made possible by referencing relations on other objects.
The syntax is X from Y
It requires that:
- the other object is related to the current object as
Y
- the user is related to another object as
X
Take a look at the authorization model below.
- DSL
- JSON
type folder
relations
define viewer as self
type document
relations
define parent_folder as self
define viewer as self or viewer from parent_folder
{
"type_definitions": [
{
"type": "folder",
"relations": {
"viewer": {
"this": {}
}
}
},
{
"type": "document",
"relations": {
"parent_folder": {
"this": {}
},
"viewer": {
"union": {
"child": [
{
"this": {}
},
{
"tupleToUserset": {
"tupleset": {
"object": "",
"relation": "parent_folder"
},
"computedUserset": {
"object": "",
"relation": "viewer"
}
}
}
]
}
}
}
}
]
}
The snippet below taken from the authorization model above is stating that viewers of a document are all users directly assigned the viewer relation and all users who can view the document's parent folder.
- DSL
- JSON
define viewer as self or viewer from parent_folder
{
"viewer": {
"union": {
"child": [
{
"this": {}
},
{
"tupleToUserset": {
"tupleset": {
"object": "",
"relation": "parent_folder"
},
"computedUserset": {
"object": "",
"relation": "viewer"
}
}
}
]
}
}
}
In the authorization model above, anne
is a viewer
of document:new-roadmap
if any one of the following relationship tuple sets exists:
- Anne is a viewer of the parent folder of the new-roadmap document
[
// planning folder is the parent folder of the new-roadmap document
{
"user": "folder:planning",
"relation": "parent_folder",
"object": "document:new-roadmap",
},
// anne is a viewer of the planning folder
{
"user": "anne",
"relation": "viewer",
"object": "folder:planning",
},
] - Anne is a viewer of the new-roadmap document (direct relationship)
[
// anne is a viewer of the new-roadmap document
{
"user": "anne",
"relation": "viewer",
"object": "document:new-roadmap",
},
]
This particular use of referencing relations on related objects is defining a transitive implied relationship. If user A is related to a certain object B as a viewer, and object B is related to object C as parent, then user A is related to object C as viewer.
This can be used to indicate that viewers of a folders are viewers of all documents in that folder.
For more examples, take look at Modeling Basics: Parent-Child Objects, Advanced Modeling: Google Drive, Advanced Modeling: GitHub, and Advanced Modeling: Entitlements.
The Union Operator
The union operator (or
in the DSL, union
in the JSON syntax) is used to indicate that a relationship exists if the user is in any of (at least one of) the sets of users (union
).
- DSL
- JSON
define viewer as self or editor
{
"viewer": {
"union": {
"child": [
{
"this": {}
},
{
"computedUserset": {
"relation": "editor"
}
}
]
}
}
}
In the type definition snippet above, anne
is a viewer
of document:new-roadmap
if any of the following conditions are satisfied:
- there exists a direct relationship with anne as editor of document:new-roadmap
[
{
"user": "anne",
"relation": "editor",
"object": "document:new-roadmap",
},
] - anne is a viewer of document:new-roadmap:
[
{
"user": "anne",
"relation": "viewer",
"object": "document:new-roadmap",
},
]
info
The above authorization model indicates that a user is related as a viewer if they are in any of:
- the userset of all users related to the object as "viewer"; indicating that a user can be assigned a direct
viewer
relation - the userset of all users related to the object as "editor"; indicating that a user who is an editor is also implicitly a viewer
So if anne is in at least one of those usersets (is either an editor or a viewer), the check on {"user": "anne", "relation": "viewer", "object": "document:new-roadmap"}
will return {"allowed": true}
.
For more examples, take a look at Modeling Concepts: Concentric Relationships, Modeling Roles and Permissions and Advanced Modeling: Modeling for IoT.
The Intersection Operator
The intersection operator (and
in the DSL, intersection
in the JSON syntax) is used to indicate that a relationship exists if the user is in all the sets of users (intersection
)
- DSL
- JSON
define viewer as authorized_user and editor
{
"viewer": {
"intersection": {
"child": [
{
"computedUserset": {
"relation": "authorized_user"
}
},
{
"computedUserset": {
"relation": "editor"
}
}
]
}
}
}
In the type definition snippet above, anne
is a viewer
of document:new-roadmap
if all of the following conditions are satisfied:
- anne is an editor of document:new-roadmapAND
[
{
"user": "anne",
"relation": "editor",
"object": "document:new-roadmap",
},
] - anne is an authorized_user of document:new-roadmap:
[
{
"user": "anne",
"relation": "authorized_user",
"object": "document:new-roadmap",
},
]
info
The above authorization model indicates that a user is related as a viewer if they are in all of:
- the userset of all users related to the object as "authorized_user"
- the userset of all users related to the object as "editor"
So anne has to be in the intersection of the usersets (anne has to be both an editor AND an authorized_user), in order for the check on {"user": "anne", "relation": "viewer", "object": "document:new-roadmap"}
to return {"allowed": true}
.
anne is not a viewer for document:new-roadmap if either of the following is true:
- anne is not an editor to document:new-roadmap: no relationship tuple of
{"user": "anne", "relation": "editor", "object": "document:new-roadmap"}
- anne is not an authorized_user on the document:new-roadmap: no relationship tuple of
{"user": "anne", "relation": "authorized_user", "object": "document:new-roadmap"}
For more examples, take look at Modeling with Multiple Restrictions.
The Exclusion Operator
The exclusion operator (but not
in the DSL, difference
in the JSON syntax) is used to indicate that a relationship exists if the user is in the base userset, but not in the excluded userset. This is helpful in modeling exclusion or block lists.
- DSL
- JSON
define viewer as self but not blocked
{
"viewer": {
"difference": {
"base": {
"this": {}
},
"subtract": {
"computedUserset": {
"relation": "blocked"
}
}
}
}
}
In the type definition snippet above, anne
is a viewer
of document:new-roadmap
if:
- anne is assigned a direct relationship as viewer to document:new-roadmapAND
[
{
"user": "anne",
"relation": "viewer",
"object": "document:new-roadmap",
},
] - anne is not blocked to document:new-roadmap. That is, the following relation tuple does not exists
[
{
"user": "anne",
"relation": "blocked",
"object": "document:new-roadmap",
},
]
For more information, see Modeling Basics: Blocklists.
info
The above authorization model indicates that a user is related as a viewer if they are in:
- the userset of all users related to the object as "viewer"
but not in:
- the userset of all users related to the object as "blocked"
So anne has to be both a viewer AND NOT blocked, in order for the check on {"user": "anne", "relation": "viewer", "object": "document:new-roadmap"}
to return {"allowed": true}
.
anne is not a viewer for document:new-roadmap if either of the following is true:
- anne is not assigned direct relationship as viewer to document:new-roadmap: no relationship tuple of
{"user": "anne", "relation": "viewer", "object": "document:new-roadmap"}
- anne is blocked on the document:new-roadmap
{"user": "anne", "relation": "blocked", "object": "document:new-roadmap"}
Equivalent Zanzibar Concepts
The JSON syntax accepted by the Auth0 FGA API closely mirrors the syntax represented in the Zanzibar paper, with a bit of flattening and converting keys from snake_case
to camelCase
.
Zanzibar | Auth0 FGA JSON | Auth0 FGA DSL |
---|---|---|
this | this | self |
union | union | or |
intersection | intersection | and |
exclusion | difference | but not |
tuple_to_userset | tupleToUserset | x from y |
In the Zanzibar paper, there's this example:
name: "doc"
relation { name: "owner" }
relation {
name: "editor"
userset_rewrite {
union {
child { _this {} }
child { computed_userset { relation: "owner" } }
}}}
relation {
name: "viewer"
userset_rewrite {
union {
child { _this {} }
child { computed_userset { relation: "editor" } }
child { tuple_to_userset {
tupleset { relation: "parent" }
computed_userset {
object: $TUPLE_USERSET_OBJECT # parent folder
relation: "viewer" }}}
}}}
In Auth0 FGA DSL, it would become:
- DSL
- JSON
type doc
relations
define owner as self
define editor as self or owner
define viewer as self or editor or viewer from parent
{
"type_definitions": [
{
"type": "doc",
"relations": {
"owner": {
"this": {}
},
"editor": {
"union": {
"child": [
{
"this": {}
},
{
"computedUserset": {
"relation": "owner"
}
}
]
}
},
"viewer": {
"union": {
"child": [
{
"this": {}
},
{
"computedUserset": {
"relation": "editor"
}
},
{
"tupleToUserset": {
"tupleset": {
"relation": "parent"
},
"computedUserset": {
"relation": "viewer"
}
}
}
]
}
}
}
}
]
}
We believe this syntax is easier to read/write.
So the following:
- DSL
- JSON
define viewer as self or editor or viewer from parent
{
"viewer": {
"union": {
"child": [
{
"this": {}
},
{
"computedUserset": {
"relation": "editor"
}
},
{
"tupleToUserset": {
"tupleset": {
"relation": "parent"
},
"computedUserset": {
"relation": "viewer"
}
}
}
]
}
}
}
Can be read as:
- The users with a viewer relationship to a certain doc are any of:
- the set of users who are directly related with this doc as
viewer
- the set of users who are related to this doc as
editor
- the set of users who are related to any object OBJ_1 as
viewer
, where object OBJ_1 is any object related to this doc asparent
(e.g. viewers of this doc's parent folder, where the parent folder is OBJ_1)
- the set of users who are directly related with this doc as
Learn more about Zanzibar at the Zanzibar Academy.