Define application authorization logic independently from application code using a domain-specific language (DSL).
A schema is the fundamental building block of any authorization model in FGA. Like a database schema, each schema in FGA defines what kinds of resources exist in an application. More importantly, a schema also defines what permissions users can have on those resources and how permissions can be inherited under certain conditions.
Every schema is defined using the FGA schema language, a domain-specific language (DSL) designed to express authorization logic in a developer-friendly format.
Managing authorization logic as a schema makes it easy to evolve your authorization logic independently from your application logic over time. You can manage a schema alongside application code with a version control system like Git and apply it using the CLI:
workos fga schema apply ./schema.txt
Once applied, a new schema takes effect immediately. In other words, any change in authorization logic will immediately be reflected in subsequent permission checks and queries.
Each schema must start with a version
declaration. This version declaration dictates the version of the schema language the transpiler will use to convert the schema into its JSON representation. As we add support for new features and functionality to the schema language, we will release new versions of it. Versioning the language in this way allows us to ensure backwards compatibility as we roll out these enhancements. See a full changelog of schema versions here.
version 0.2
Resource types are the building blocks of your authorization model. They represent different types of entities in your application. For example users, organizations, stores, items, etc. See more information about resource types here.
To define a resource type, use the type
keyword followed by the name of the resource type.
type user
Relations are a specific type of connection between two resources. Relations define how a subject can access a resource. For instance, the user
resource type might define a manager
relation. The manager
relation authorizes certain users to access employee information for a user.
To define a relation for a resource type, use the relation
keyword followed by the name of the relation. Optionally, you can add the type(s) of resources the service can assign to the relation.
Use brackets []
after the relation name for resource type checking. The resource type can be empty, a single type, or an array of types. Type checking occurs at runtime when your application calls the service create warrants. The server validates that warrants have proper subject types. The service also checks types when applying a new schema to confirm that inheritance rules are valid.
Use empty resource types to define computed relationships with no direct subjects. Such as a relation inherited from other relations.
Version 0.1
of the schema language does not support type safety on relations.
type user relation manager [user]
In this example, the manager
relation indicates that only a user
can be a manager
of another user
.
type user relation editor [user] relation manager [user] relation computed [] inherit computed if any_of relation editor relation manager
In this example, the computed
relation is inherited if either the editor
or manager
relation exists. You cannot assign a subject to the computed
relation directly.
Use inheritance rules to define how certain relations are granted implicitly based on the existence of other relations. They are useful for expressing hierarchical relationships without having to explicitly define every possible relation as a warrant.
There are two types of inheritance rules:
To define an inheritance rule, use the inherit
keyword followed by the name of the inherited relation. On the next line add a condition that the subject should meet in order for the inheritance to occur.
type store relation viewer [user] relation editor [user] inherit viewer if relation editor
In this example, the viewer
relation is inherited if the editor
relation exists for a subject.
Use relation inheritance to inherit from another relation within the same resource type. This is useful when you want to create hierarchical relationships. One common use case is to inherit the viewer
relation if the editor
relation exists.
To define a relation inheritance rule, specify the relation to inherit, and the relation to inherit based on.
type store relation viewer [user] relation editor [user] relation owner [user] inherit viewer if relation editor inherit editor if relation owner
In this example, the viewer
relation is inherited if the editor
relation exists. The editor
relation is inherited if the owner
relation exists.
Use resource inheritance to inherit from a relation in another resource type. This is useful when you want to create hierarchical relationships between different resource types.
To define a resource inheritance rule, specify the relation, the resource type to inherit from, and the relation to inherit based on.
type item relation owner [user] relation parent [store] inherit owner if relation owner on parent [store]
In this example, the owner
relation on an item
is inherited if all of the following conditions are met
owner
relation on the parent
.owner
parent
is a store
.Use logical operators to combine multiple inheritance conditions. The supported operators are all_of
, any_of
, and none_of
. They behave the same as JSON resource type inheritance rules.
type item relation owner [user] relation editor [user] relation manager [user] inherit editor if any_of relation owner relation manager on owner [user]
In this example, the editor
relation is inherited if either of the following conditions are met:
owner
relation exists on the item type (relation inheritance).manager
relation exists on the owner
if the owner
is a user
(resource inheritance).You can also nest logical operators to define complex relationships between resource types. Here’s an example:
inherit editor if any_of relation owner relation editor on parent [store] all_of relation viewer on parent [store] relation manager on owner [user]
In this example, the schema defines an editor
relationship that is granted if any of the following conditions are met:
owner
.editor
on the parent
store
.viewer
on the parent
store
and a manager
on the owner
user
.Here is an example schema that incorporates resource types, relations, inheritance rules, and logical operators:
version 0.2 type user relation manager [user] type store relation viewer [user] relation owner [user] relation editor [user] inherit viewer if relation editor inherit editor if relation owner type item relation viewer [user] relation parent [store] relation owner [user] relation editor [user] inherit viewer if relation editor inherit owner if relation owner on parent [store] inherit editor if any_of relation owner relation editor on parent [store] relation manager on owner [user]
version 0.2 type report relation parent [organization] relation owner [user] relation editor [user]