Roles and Permissions
Roles and permissions can be modeled within OpenFGA using an authorization model and relationship tuples.
- Roles are assigned to users or a group of users. Any user can have more than one role, like
editor
orowner
. - Permissions allow users to access certain objects based on their specific roles, like
device_renamer
orchannel_archiver
.
For example, the role viewer
of a trip
can have permissions to view bookings, while the role owners
can have permissions to add or view trip bookings.
Role and permissions models in OpenFGA can both directly assign roles to users and assign permissions through relations users receive downstream from other relations. For example, you can:
- Grant someone an
admin
role that canedit
andread
adocument
- Grant someone a
security_guard
role that canlive_video_viewer
on adevice
- Grant someone a
viewer
role that canview_products
on ashop
Implementing a Roles and Permissions model allows existing roles to have finer-grained permissions, allowing your application to check whether a user has access to a certain object without having to explicitly check that specific users role. In addition, you can add new roles/permissions or consolidate roles without affecting your application behavior. For example, if your app's checks are for the fine permissions, like check('bob', 'booking_adder', 'trip:Europe')
instead of check('bob', 'owner', 'trip:Europe')
, and you later decide owners
can no longer add bookings to a trip
, you can remove the relation within the trip
type with no code changes in your application and all permissions will automatically honor the change.
Before you start
Familiarize yourself with the basics of OpenFGA Concepts.
Assume that you have the following authorization model and a type called trip
that users can be related to as viewer
and/or an owner
.
trip
that users can be related to as viewer
and/or an owner
.- DSL
- JSON
model
schema 1.1
type user
type trip
relations
define owner: [user]
define viewer: [user]
{
"schema_version": "1.1",
"type_definitions": [
{
"type": "user"
},
{
"type": "trip",
"relations": {
"owner": {
"this": {}
},
"viewer": {
"this": {}
}
},
"metadata": {
"relations": {
"owner": {
"directly_related_user_types": [
{
"type": "user"
}
]
},
"viewer": {
"directly_related_user_types": [
{
"type": "user"
}
]
}
}
}
}
]
}
In addition, you need to know the following:
Direct Access
Creating an authorization model and a relationship tuple can grant a user access to an object. To learn more, read about Direct Access
OpenFGA Concepts
- A Type: a class of objects that have similar characteristics
- A User: an entity in the system that can be related to an object
- A Relation: a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system
- An Object: represents an entity in the system. Users' relationships to it can be define through relationship tuples and the authorization model
- A Relationship Tuple: a group stored in OpenFGA that consists of a user, a relation, and an object
- A Relationship: OpenFGA will be called to check if there is a relationship between a user and an object, indicating that the access is allowed
- Union Operator: can be used to indicate that the user has multiple ways of being related to an object
- Direct Relationship Type Restrictions: can be used to indicate direct relationships between users and objects
- A Check API Request: used to check for relationships between users and objects
Step by step
The Roles and Permissions example below is a trip booking system that has owners
and/or viewers
, both of which can have more granular permissions like adding bookings to a trip or viewing a trip's bookings.
To represent this in an OpenFGA environment, you need to:
- Understand how roles are related to direct relations for the trip booking system
- Add implied relations to the existing authorization model to define permissions for bookings
- Check user roles and their permissions based on relationship tuples for direct and implied relations
01. Understand how roles work within the trip booking system
Roles are relations that are directly assigned to users. Below, the stated roles that a given user can be assigned are owner
and viewer
.
- DSL
- JSON
model
schema 1.1
type user
type trip
relations
define owner: [user]
define viewer: [user]
{
"schema_version": "1.1",
"type_definitions": [
{
"type": "user"
},
{
"type": "trip",
"relations": {
"owner": {
"this": {}
},
"viewer": {
"this": {}
}
},
"metadata": {
"relations": {
"owner": {
"directly_related_user_types": [
{
"type": "user"
}
]
},
"viewer": {
"directly_related_user_types": [
{
"type": "user"
}
]
}
}
}
}
]
}
02. Add permissions for bookings
Permissions are relations that users get through other relations. To avoid adding a direct relationship type restriction to the relation in the authorization model while representing permissions, they instead define the relation via other relations in the model, which indicates that it is a permission granted to and implied from a different relation.
To add permissions related to bookings, add new relations to the trip
object type denoting the various actions a user can take on trips
, like view, edit, delete, or rename.
To allow viewers
of a trip
to have permissions to view bookings and owners
to have permissions to add/view bookings, you modify the type:
- DSL
- JSON
model
schema 1.1
type user
type trip
relations
define owner: [user]
define viewer: [user]
define booking_adder: owner
define booking_viewer: viewer or owner
{
"schema_version": "1.1",
"type_definitions": [
{
"type": "user"
},
{
"type": "trip",
"relations": {
"owner": {
"this": {}
},
"viewer": {
"this": {}
},
"booking_adder": {
"computedUserset": {
"relation": "owner"
}
},
"booking_viewer": {
"union": {
"child": [
{
"computedUserset": {
"relation": "viewer"
}
},
{
"computedUserset": {
"relation": "owner"
}
}
]
}
}
},
"metadata": {
"relations": {
"owner": {
"directly_related_user_types": [
{
"type": "user"
}
]
},
"viewer": {
"directly_related_user_types": [
{
"type": "user"
}
]
}
}
}
}
]
}
Note: both
booking_viewer
andbooking_adder
don't have direct relationship type restrictions, which ensures that the relation can only be assigned through the role and not directly.