Object Types
Object types are the basic building blocks of an authorization scheme in Warrant. They are very flexible, allowing you to express an application's data model as relationships that exist between its resources and its users. This includes the ability to express more complex hierarchical and inherited relationships.
Let's build up object types for a simple eCommerce application. The app has two main object types: stores and items.
{
"type": "store"
},
{
"type": "item"
}
With these object types we can create fine-grained authorization rules for each store, item, and user to enforce access in the app by answering questions like:
Does [user1] have access to edit [itemx]?
Does [user2] have access to edit [store3]?
Relations
To help answer questions like the ones above, we need to add relations to our object types. Relations define the relationships that are possible between users and object types.
In our app, stores can have owners
, editors
, and viewers
. owners
and editors
have more privileged access (ex. being able to modify details about a store) than viewers
(who have read-only access).
Items have the same three relations as stores plus a fourth relation called parent
. A store can be the parent
of an item, meaning that item belongs to that store. We'll use this relation to implement inherited privileges later. Let's add these relations to our object types:
{
"type": "store",
"relations": {
"owner": {},
"editor": {},
"viewer": {}
}
},
{
"type": "item",
"relations": {
"parent": {},
"owner": {},
"editor": {},
"viewer": {}
}
}
Now we can create authorization rules using these object types to specifically define which users are owners
, editors
, viewers
, etc. of each store and item.
Rules
Explicitly defining relations like we did above (owners
, editors
, etc.) might work for many cases. However, in practice, it's common for relations to overlap. In our app, an owner
is also both an editor
and a viewer
. An editor
is also a viewer
. We need to tell Warrant that some of these relations can be inherited and how exactly they can be inherited. We do this via userset
and object userset
rules.
Userset Rule
A userset rule allows you to inherit relations by specifying the inherited relation. Let's define a rule specifying that owners are editors
and editors are viewers
in our object types:
{
"type": "store",
"relations": {
"owner": {},
"editor": {
"type": "anyOf",
"rules": [
{
"type": "userset",
"relation": "owner"
}
]
},
"viewer": {
"type": "anyOf",
"rules": [
{
"type": "userset",
"relation": "editor"
}
]
}
}
},
{
"type": "item",
"relations": {
"parent": {},
"owner": {},
"editor": {
"type": "anyOf",
"rules": [
{
"type": "userset",
"relation": "owner"
}
]
},
"viewer": {
"type": "anyOf",
"rules": [
{
"type": "userset",
"relation": "editor"
}
]
}
}
}
note
Each relation
spec has a type
parameter that defines how to treat the rules defined in the rules
array. Currently, only the anyOf
type is supported. This means that the relation is valid if any of the rules in the array match (this is equivalent to the boolean OR operator). In our example above, the user is an editor if they are an owner.
Object Userset Rule
With object userset rules, we can define inherited relations between objects. We now want to define that an editor
of a store is also an editor
on items that belong to that store (parent
). We specify this dual-inheritance by defining an object userset rule on the editor
relation of the item
object type:
{
"type": "store",
"relations": {
"owner": {},
"editor": {
"type": "anyOf",
"rules": [
{
"type": "userset",
"relation": "owner"
}
]
},
"viewer": {
"type": "anyOf",
"rules": [
{
"type": "userset",
"relation": "editor"
}
]
}
}
},
{
"type": "item",
"relations": {
"parent": {},
"owner": {},
"editor": {
"type": "anyOf",
"rules": [
{
"type": "userset",
"relation": "owner"
},
{
"type": "objectUserset",
"relation": "parent",
"userset": {
"type": "userset",
"relation": "editor"
}
}
]
},
"viewer": {
"type": "anyOf",
"rules": [
{
"type": "userset",
"relation": "editor"
}
]
}
}
}
In other words, the user is an editor of an item if that user is an editor of the parent store of that item. Now we don't always have to create an access rule for every item in our application.
Creating and Managing Object Types
Currently, object types can be created directly in the Warrant dashboard or via API. Check out the API Reference for more details.