. Your users might [have roles on a given object, rather than the entire system](./roles-and-permissions.mdx). But starting from the term "role" might lead you down the wrong path. Instead it is better to discover roles while you are modeling.
:::
Your feature description should include the , and participating in the system. Sentences should look like this:
Let's look at an example of a simplified Google Drive like system. We'll focus on the feature allowing users to create, read,
update, delete, and share documents with other users.
This feature can be described with these sentences:
- A user can create a document in a drive if they are the owner of the drive.
- A user can create a folder in a drive if they are the owner of the drive.
- A user can create a document in a folder if they are the owner of the folder. The folder is the parent of the document.
- A user can create a folder in a folder if they are the owner of the folder. The existing folder is the parent of the new folder.
---
- A user can share a document with another user or an organization as either editor or viewer if they are an owner or editor of a document or if they are an owner of the folder/drive that is the parent of the document.
---
- A user can share a folder with another user or an organization as a viewer if they are an owner of the folder.
---
- A user can view a document if they are an owner, viewer or editor of the document or if they are a viewer or owner of the folder/drive that is the parent of the document.
---
- A user can edit a document if they are an owner or editor of the document or if they are an owner of the folder/drive that is the parent of the document.
---
- A user can change the owner of a document if they are an owner of the document.
---
- A user can change the owner of a folder if they are an owner of the folder.
---
- A user can be a member of an organization.
How a user is added as a member to an organization is beyond the scope of the feature we picked to write down.
---
- A user can view a folder if they are the owner of the folder, or a viewer or owner of either the parent folder of the folder, or the parent drive of the folder.
### 02. List The Object Types

Next make a list of the of objects in your system. You might be able to identify the objects in your system from your existing domain/database model.
Find all the objects in the previous step using this template:
These are all the object types from the previous step (in order of appearance) based on that template:
, alignment: 'left', label: 'Document' }} />
, alignment: 'left', label: 'Folder' }} />
, alignment: 'left', label: 'Organization' }} />
Let's highlight all object types in blue:
- A user can create a document in a drive if they are the owner of the drive.
- A user can create a folder in a drive if they are the owner of the drive.
- A user can create a document in a folder if they are the owner of the folder.
- A user can create a folder in a folder if they are the owner of the folder.
---
- A user can share a document with another user or an organization as either editor or viewer if they are an owner or editor of a document or if they are an owner of the folder/drive that is the parent of the document.
---
- A user can share a folder with another user or an organization as a viewer if they are an owner of the folder.
---
- A user can view a document if they are an owner, viewer or editor of the document or if they are a viewer, owner of the folder/drive that is the parent of the document.
---
- A user can edit a document if they are an owner or editor of the document or if they are an owner of the folder/drive that is the parent of the document.
---
- A user can change the owner of a document if they are an owner of the document.
---
- A user can change the owner of a folder if they are an owner of the folder.
---
- A user can be a member of an organization.
How a user is added as a member to an organization is beyond the scope of the feature we picked to write down.
---
- A user can view a folder if they are the owner of the folder, or a viewer or owner of either the parent folder of the folder, or the parent drive of the folder.
However, the list of object types is not finished. To complete the list of object types you must also add all the second nouns that appear in conditions as part of expressions of this format: **"\{first noun\} of a/the \{second noun\}"**.
Let's highlight those expressions in green:
- A user can create a document in a drive if they are the owner of the drive.
- A user can create a folder in a drive if they are the owner of the drive.
- A user can create a document in a folder if they are the owner of the folder. The folder is the parent of the document.
- A user can create a folder in a folder if they are the owner of the folder. The existing folder is the parent of the new folder .
---
- A user can share a document with another user or an organization as either editor or viewer if they are an owner or editor of a document or if they are an owner of the folder/drive that is the parent of the document.
---
- A user can share a folder with another user or an organization as a viewer if they are an owner of the folder.
---
- A user can view a document if they are an owner, viewer or editor of the document or if they are a viewer or owner of the folder/drive that is the parent of the document.
---
- A user can edit a document if they are an owner or editor of the document or if they are an owner of the folder/drive that is the parent of the document.
---
- A user can change the owner of a document if they are an owner of the document.
---
- A user can change the owner of a folder if they are an owner of the folder.
---
- A user can be a member of an organization.
How a user is added as a member to an organization is beyond the scope of the feature we picked to write down.
---
- A user can view a folder if they are the owner of the folder, or a viewer or owner of either the parent folder of the folder, or the parent drive of the folder.
The only second noun we didn't have in our object type list is "Drive", so we'll add it to the list.
We will also need to add "User" to the list as it establishes the type of user who can establish relations.
, alignment: 'left', label: 'Document' }} />
, alignment: 'left', label: 'Folder' }} />
, alignment: 'left', label: 'Organization' }} />
, alignment: 'left', label: 'Drive' }} />
Now that we have a list of object types we can start defining them using the :
:::info Caution
You're now in the process of building a version you can use. The model above is not yet a valid authorization model accepted by .
:::
:::info Important
In a few cases other users can be part of determining whether an action can be performed on an object or not. Social media is an example of this "a user can comment on a picture if they are a friend of the user that published it".
In those cases [**User** should also be an object type](./building-blocks/object-to-object-relationships.mdx). Following the last recommendation, we would discover the User type because it is a second noun in an expression: "friend of the user".
:::
### 03. List Relations For Those Types

Each of the previously defined types has a set of relations. are an important component in your model. After all, is a system.
To identify relations for a type in the write-up we can perform an exercise similar to the one we did in [list the type of objects in your system](#02-list-the-object-types).
Relations for a type \{type\} will be all of these:
- any noun that is the \{noun\} of a "\{noun\} of a/an/the \{type\}" expression. **These are typically the Foreign Keys in a database.** We'll highlight these in green.
- any verb or action that is the \{action\} of a "can \{action\} (in) a/an \{type\}" expression. **These are typically the permissions for a type.** We'll highlight these in yellow.
- A user can create a document in a drive if they are the owner of the drive.
- A user can create a folder in a drive if they are the owner of the drive.
- A user can create a document in a folder if they are the owner of the folder. The folder is the parent of the document.
- A user can create a folder in a folder if they are the owner of the folder. The existing folder is the parent of the new folder.
---
- A user can share a document with another user or an organization as either editor or viewer if they are an owner or editor of a document or if they are an owner of the folder/drive that is the parent of the document.
---
- A user can share a folder with another user or an organization as a viewer if they are an owner of the folder.
---
- A user can view a document if they are an owner, viewer or editor of the document or if they are a viewer or owner of the folder/drive that is the parent of the document.
---
- A user can edit a document if they are an owner or editor of the document or if they are an owner of the folder/drive that is the parent of the document.
---
- A user can change the owner of a document if they are an owner of the document.
---
- A user can change the owner of a folder if they are an owner of the folder.
---
- A user can be a member of an organization.
How a user is added as a member to an organization is beyond the scope of the feature we picked to write down.
---
- A user can view a folder if they are the owner of the folder, or a viewer or owner of either the parent folder of the folder, or the parent drive of the folder.
The resulting list is:
, alignment: 'middle', label: 'Document' }}
>
- parent
- can_share
- owner
- editor
- can_write
- can_view
- viewer
- can_change_owner
, alignment: 'middle', label: 'Folder' }}
>
- can_create_document
- owner
- can_create_folder
- can_view
- viewer
- parent
, alignment: 'middle', label: 'Organization' }}
>
- member
, alignment: 'middle', label: 'Drive' }}
>
- can_create_document
- owner
- can_create_folder
:::info
In , relations can only have alphanumeric characters, underscores and hyphens. We recommend using underscore (\_) to separate words and removing prepositions. E.g.: "can create a document" can become "can_create_document" or "create_document" if you are into brevity.
:::
Using the we can enumerate the relations for each type:
```dsl.openfga
model
schema 1.1
type user
type document
relations
define parent:
define owner:
define editor:
define viewer:
define can_share:
define can_view:
define can_write:
define can_change_owner:
type folder
relations
define owner:
define parent:
define viewer:
define can_create_folder:
define can_create_document:
define can_view:
type organization
relations
define member:
type drive
relations
define owner:
define can_create_document:
define can_create_folder:
```
:::info Caution
You're now in the process of building a version you can use. The model above is not yet a valid authorization model accepted by .
:::
### 04. Define Relations

We will use the to create a for each of the relations we identified. At this stage we will encode the answers to the question we asked at the beginning of the document:.
, alignment: 'left' }}
title="Why could a user U, perform an action A on an object O?"
/>
We are going to go over each type and each of its relations and create a definition for it.
We recommend starting from objects that represent groups/containers of users. For features in most systems these are easy to define and help reason about the other types. Examples of type names for these are "team", "group", "organization", etc.
##### Relation: Member
The member relation is used to tell about the members of an organization.
:::info Important
Relation names in are arbitrary strings. There are no reserved relation names. You can use "member" or "part_of" or anything else to refer to a user that is part of a team/organization.
:::
Remember _"How a user is added as a member to an organization is beyond the scope of this feature."_ For the purposes of this model the relation definition should be:
Why? This relation definition states:
- That organizations have members
- That the members of an organization with id \{id\} are all users described by tuples of the form:
`{ user: {user-id}, relation: "member", object: "organization:{id}" }`
:::info Important
Relation definitions of the form "define \{relation\}: [user, organization#member]" are fairly common. They are used to express that relationships "to the object with that relation" (e.g. "users" of type user or "member of organization") can be assigned by your system and that only the users that have that relation are those with a [direct relationship](./building-blocks/direct-relationships.mdx).
:::
You can read more about group membership and types in [Modeling User Groups](./user-groups.mdx).
For the direct relationships, we need to figure out the object types that makes sense for the relationship tuples' user. In our organization example, it makes sense for member relations to have user of type
- user
- organization#member (i.e., other organization's member)
However, it will not make sense for organization member's user to be of type document, folder or drive.
We will specify this logic as part of .
:::note Side note
This also automatically supports nested organizational membership if you want such a feature in your system. You could use relationship tuples like the following one to express that "members of organization A are members of organization B":
```
{ user: "organization:A#member", relation: "member", object: "organization:B"}
```
If you want to learn more, you can read further about this in [Modeling User Groups](./user-groups.mdx) and [Managing Relationships Between Objects](../interacting/managing-relationships-between-objects.mdx).
:::
##### Complete Type Definition
The complete for the **organization** type is:
After defining your "group" like types, continue with the most important type for the feature: the one that allows the main use case. In this case "document", since the main use case for users is to create, write, read and collaborate on documents.
Defining relations for the main type lets you focus on your core use case, and will likely make other type definitions easier.
##### Relation: Owner
The owner relation is used to tell which users are owners of the document.
:::info Important
In the current version, there is no way to state that there is only one owner in the authorization model. The application must limit this to just one owner if that is a requirement.
:::
When a document is created, a relationship tuple will be stored in representing this relationship between owner and document. This is an example of a [user to object relationship](./direct-access.mdx).
The relation definition then should be:
Why? This states that:
- each document can have one or more owners
- owners of a document are assignable by creating a tuple of the format
`{ user: "{user_id}", relation: "owner", object: "document:{id}" }` for individual users
##### Relation: Editor
The editor relation is used to tell which users are editors of the document.
When a user shares a document with another user or set of users as editor, a relationship tuple will be stored in representing this relationship between editor and document. This is an example of a [users to object relationship](./direct-access.mdx).
The relation definition then should be:
Why? This relation definition states that:
- each document can have editors
- the editor(s) of a document are assignable by creating a tuple with shape
`{ user: "{user_id}", relation: "editor", object: "document:{id}" }` for individual users
This also supports making all members in an organization editors of the document, through a [group to object relationship](./user-groups.mdx). A relationship tuple like the following one states that the members of organization A are editors of document 0001.
You can learn more about this in [Modeling User Groups](./user-groups.mdx).
##### Relation: Viewer
The viewer relation is similar to the document's [editor relation](#relation-editor). It will be defined like this:
##### Relation: Parent
The parent relation is used to tell which folder or drive is the parent of the document.
:::caution Important
Relation names in are arbitrary strings. There are no reserved relation names. You can use "parent", "container" or "ancestor" to refer to a "parent folder".
:::
This relation is different from the others we have seen so far, as it is a relation between two objects (a **folder** and or **drive** that is the parent of the **document**). This is known as an [object to object relationship](./building-blocks/object-to-object-relationships.mdx), of which [parent-child is a particular case](./parent-child.mdx).
When a document is created a relationship tuple will be stored in to represent this relationship between parent and document. The relation definition then should be:
Why? This relation definition states that:
- documents may have a parent
- the parent(s) of a document with id \{id\} is either a folder or a drive, described by one of these relationship tuples:
- `{ user: "folder:{id}", relation: "parent", object: "document:{id}" }`
- `{ user: "drive:{id}", relation: "parent", object: "document:{id}" }`
We can use [direct type restriction](../configuration-language.mdx#direct-relationship-type-restrictions) to ensure a document's parent can only be an object of type either drive or folder.
:::note Side note
You might have noticed that the "user" in the tuple is an object. This is a special syntax accepts in the "user" parameter to write [object to object relationships](./building-blocks/object-to-object-relationships.mdx). You can read more about writing data to manage object to object relationships in [Managing Relationships Between Objects](../interacting/managing-relationships-between-objects.mdx).
:::
##### Relation: can_share
We need to express the following in the :
_A user can share a document with another user or an organization as either editor or viewer if they are an owner or editor of a document or if they are an owner of the folder that is the parent of the document._
We can achieve that with the following definition using :
There are a few key things here:
- **We don't use a [direct relationship type restriction](../configuration-language.mdx#direct-relationship-type-restrictions) as part of the definition.** can_share is a common example of representing a permission that is defined in terms of other relations but is not directly assignable by the system.
- The relation definition contains a [union operator](../configuration-language.mdx#the-union-operator) separating a list of relations that the user must have with the object in order to "be able to share the document". It is any of:
- Being an owner of the document
- Being an editor of the document
- Being an owner of the parent of the document. Whether the parent is a drive or a folder is not important, as they both have an owner relation.
You can read more about the aforementioned items in [Modeling Roles and Permissions](./roles-and-permissions.mdx).
##### Relation: can_view
We need to express the following in the :
_A user can view a document if they are an owner, viewer or editor of a document or if they are a viewer, owner of the folder/drive that is the parent of the document._
Similar to the [can_share relation](#relation-can_share), we can achieve that with the following definition using :
##### Relation: can_write
We need to express the following in the :
_A user can write a document if they are an owner or editor of a document or if they are an owner or editor of the folder/drive that is the parent of the document._
Similar to the [can_share relation](#relation-can_share), we can achieve that with the following definition using :
##### Relation: can_change_owner
We need to express the following in the :
_A user can change the owner of a document if they are an owner of the document._
Similar to the [can_share relation](#relation-can_share), we can achieve that with the following definition using :
##### Complete Type Definition
The complete for the document type is:
Combining the type definitions for document and organization, we have
:::note
The authorization model API and SDK only accepts JSON in its input. To convert from DSL to JSON, you may use the [FGA CLI](https://github.com/openfga/cli) to run `fga model transform`.
:::
### 05. Test The Model

Once you have defined your group like types and the most important type for your feature you want to ensure everything is working as expected. This means testing the model.
How? Remember from the introduction that **'s** main job is to answer the question:
, alignment: 'left' }} title="Can user U, perform an action A on an object O?" />
The service does that by checking if a user has a particular relationship to an object, based on your authorization model and relationship tuples.
"Can user U perform action A on object O?"
"Can user U have relation R with object O?"
What we want is to ensure that given our current authorization model and some sample relationship tuples, we get the expected results for those questions.
So we'll write some relationship tuples and assertions. An assertion takes one of these forms:
1. user U **has** relation R with object O
2. user U **does not have** relation R with object O
Much like automated tests and assertions work for programming languages, you can use assertions to prevent regressions while you change your tuples and authorization model. Essentially, assertions help you ensure things work like you expect them to work as you iterate.
#### Write Relationship Tuples
The relationship tuples should represent real examples from your system with fake data.
At this point you haven't defined the drive or folder types, so you can only test things based on users or organization members' relationships to documents. Let's imagine an example setup and write the relationship tuples for it:
| System Action | Relationship Tuple |
| ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| Anne is a member of the contoso organization | `{ user:"user:anne", relation: "member", object: "organization:contoso"}` |
| Beth is a member of fabrikam organization | `{ user:"user:beth", relation: "member", object: "organization:fabrikam"}` |
| Anne creates document:1, becomes its owner. | `{ user:"user:anne", relation: "owner", object: "document:1"}` |
| Anne shares document:1 with all members of the fabrikam organization as editor. | `{ user:"organization:fabrikam#member", relation: "editor", object: "document:1"}` |
| Beth creates document:2 and becomes its owner. | `{ user:"user:beth", relation: "owner", object: "document:2"}` |
| Beth shares document:2 with all members of the contoso organization as viewer | `{ user:"organization:contoso#member", relation: "viewer", object: "document:2"}` |
Follow these steps to create relationship tuples.
#### Create Assertions
According to our [written down model](#write-it-in-plain-language) and the [relationship tuples](#write-relationship-tuples) from the previous step, these assertions should be specified:
Because anne is the owner of document:1:
- user **anne** has relation **can_share** with document:1
- user **anne** has relation **can_write** with document:1
- user **anne** has relation **can_view** with document:1
- user **anne** has relation **can_change_owner** with document:1
Because beth is a member of organization:fabrikam and members of organization:fabrikam are writer of document:1:
- user **beth** has relation **can_share** with document:1
- user **beth** has relation **can_write** with document:1
- user **beth** has relation **can_view** with document:1
- user **beth** does not have relation **can_change_owner** with document:1
Because beth is the owner of document:2:
- user **beth** has relation **can_share** with document:2
- user **beth** has relation **can_write** with document:2
- user **beth** has relation **can_view** with document:2
- user **beth** has relation **can_change_owner** with document:2
Because anne is a member of organization:contoso and members of organization:contoso are viewer of document:2:
- user **anne** does not have relation **can_share** with document:2
- user **anne** does not have relation **can_write** with document:2
- user **anne** has relation **can_view** with document:2
- user **anne** does not have relation **can_change_owner** with document:2
Follow these steps to create assertions.
#### Run Assertions
Run the assertions. They should all pass. If they don't you can use the query view to understand what is causing them to fail, and then update your authorization model and relation tuples accordingly.
Once all the assertions are working, you should continue the iterative process of working on your model.
### 06. Iterate

We'll leave the exercise of defining the drive and folder relations, then adding relationship tuples and assertions to you. Once you are finished, check out the complete example to see how you did.
When defining the authorization model for your own system, you would continue iterating on the with the [next feature](#01-pick-the-most-important-feature) and so on.
## Related Sections