Skip to main content

Schema Language

Overview#

The Schema Language is a language for specifying the definitions of object types, their relations to one another, and the permissions they expose as part of a Permissions System.

The Schema Language's extension for use on a file system is .zed

Definitions#

The top level of a Schema consists of zero or more Object definitions, which define the types exposed in the permissions system.

It might help to think about Object Definitions as similar to a class definition in an Object Oriented programming language.

The name of each Object Definition is prefixed with the Permissions System it will be applied to. This is done to make all Object names globally unique in Authzed.

/** * sometype is some type that I've decided to define */definition sysprefix/sometype {}
note

Note that sysprefix is the prefix used in the examples. You'll need to replace it with the prefix from your permissions system.

Relations#

A relation defines how two objects (or an object and subject) can relate to one another. For example, a reader on a document, or a member of a group.

Relations are always defined with a name and one (or more) allowed types of objects that can be the subjects of that relation:

/** * user represents a user */definition sysprefix/user {}
/** * document represents a document in the system */definition sysprefix/document {    /**     * reader relates a user that is a reader on the document     */    relation reader: sysprefix/user}

Relations can also "contain" references to other relations/permissions. For example, a group's member relation might include the set of objects marked as member of another group, indicating that the other group's members are, themselves, members of this group:

definition sysprefix/user {}
definition sysprefix/group {    /**     * member includes both users and *all the members* of other groups.     */    relation member: sysprefix/user | sysprefix/group#member}
info

sysprefix/user is shorthand for sysprefix/user#...

... indicates that the entire object (in this case user) is allowed for the relation, rather than a specific relation defined within user (such as #member for sysprefix/group)

Naming Relations#

Relations define how one object relates to another object/subject, and thus relations should be named as adjectives, read as {relation name} (of the object).

Examples:

NameRead as
readerreader of the document
writerwriter of the document
membermember of the group
parentparent of the folder

Permissions#

A permission defines a computed set of objects that have a permission of some kind on the parent object. For example, can a user edit a document.

Permissions are always defined with a name and an expression defining how that permission's allowed set of objects is computed:

definition sysprefix/user {}
definition sysprefix/document {    relation writer: sysprefix/user    relation reader: sysprefix/user
    /**     * edit determines whether a user can edit the document     */    permission edit = writer
    /**     * view determines whether a user can view the document     */    permission view = reader + writer}

Operations#

Permissions support four kinds of operations: union, intersection, exclusion and arrow.

+ (Union)#

Unions together the relations/permissions referenced

Union is the most common operation and is used to join different relations or permissions together to form a set of allowed objects.

For example, to grant a permission to both the readers and writers of a document:

permission combined = reader + writer

& (Intersection)#

Intersects the set of objects found for the relations/permissions referenced

Intersection allows for a permission to only include those objects that were found in both relations/permissions.

For example, to grant a permission to a user that is both a reader and a writer of a document:

permission read_and_write = reader & writer

- (Exclusion)#

Excludes the set of objects found for the right side relation/permission from those found in the left side relation/permission

Exclusion allows for computing the difference between two sets of relations/permissions

For example, to grant a permission to a user that is reader but not the writer of a document:

permission can_only_read = reader - writer

-> (Arrow)#

Arrows allow for "walking" the heirarchy of relations (and permissions) defined for an object, referencing a permission or relation on the resulting object.

For example, imagine a schema where a document is found under a folder:

definition sysprefix/user {}
definition sysprefix/folder {    relation reader: sysprefix/user}
definition sysprefix/document {    /**     * parent_folder defines the folder that holds this document     */    relation parent_folder: sysprefix/folder}

We likely want to allow any reader of the folder to also be a reader of the document. To accomplish this, we can use the arrow operator to walk to the parent_folder's reader relation:

definition sysprefix/user {}
definition sysprefix/folder {    relation reader: sysprefix/user}
definition sysprefix/document {    relation parent_folder: sysprefix/folder
    /**     * read defines whether a user can read the document     */    permission read = parent_folder->reader}

The expression parent_folder->reader indicates to "walk" from the parent_folder of the document, and then to include the objects found within reader of that folder.

Making use of a union, we can also include the local reader relation, allowing the read permission on a document can check whether a user is a reader of a document or a reader of its parent folder.

definition sysprefix/user {}
definition sysprefix/folder {    relation reader: sysprefix/user}
definition sysprefix/document {    relation parent_folder: sysprefix/folder    relation reader: sysprefix/user
    /**     * read defines whether a user can read the document     */    permission read = reader + parent_folder->reader}

Naming Permissions#

Permissions define a set of objects that can perform an action or have some attribute, and thus permissions should be named as verbs or nouns, read as (is/can) {permission name} (the object).

Examples:

NameRead as
readcan read the object
writecan write the object
deletecan delete the object
memberis member of the object
note

You'll note that we also used member above in the relation example. Defining member as a permission might be found when you have multiple "ways" an object can be a member of another object, thus changing it from a direct relation to a computed set.

Comments#

Documentation Comments#

note

It is highly recommended to put doc comments on all definitions, relations and permissions.

/** * something has some doc comment */

Non-doc comments#

// Some comment/* Some comment */

Full Example#

Try it out!#

Try the schema Language out now in the Authzed Playground