app.get("/documents/:id", async (res, req) => {
if (!req.user.roles.includes("employee") && !req.user.roles.includes("manager")) {
throw new ForbiddenError();
}
const document = await db.documents.findOne({ id: req.params.id });
res.send({ document });
});
Add RBAC!
If the user has a role, grant access
But… what if there are many roles? What if new roles get added?
Add PBAC (RBAC + permissions)!
If the user has a permission, grant access
But… how do you grant (or revoke) permissions to view a single document?
app.get("/documents/:id", async (res, req) => {
if (!req.user.permissions.includes("documents:view")) {
throw new ForbiddenError();
}
Downsides:
●Role explosion: delegating access to individual resources requires creating a
new role per resource. (and if you try to add the roles to the JWT? You can’t
have many!)
●Expressiveness: you can’t express more complex policies
○How do you handle hierarchies, e.g. if a user can view a parent folder, they
should be able to view all the documents inside child folders?
○How do you grant access to a single folder or a single document?
ABAC allows granting more granular permissions.
But… is this check fast?! What if you forget to check the folders the document is in?
// GET /documents/:id
const document = await db.documents.findOne({ id: req.params.id });
// Because we might have the document nested in many folders, any of which may have been shared with
the user
const folders = await db.folders.recursivelyFindAllFoldersInChain ({ id: document.folder_id });
// Because the document or folder may have been shared with a group the user is in
const groups = await db.groups.recursivelyFindAllGroupsInChain ({ ids: req.user.group_ids });
await authorize(req.user, "read", { folders, groups });
res.send({ document });
Use ABAC!
Downsides:
●Nesting gets complicated: attributes about the documents and the users need to
be gathered from the database, increasing database load and increasing
response latency
●Repeated implementation for each type of resources and each type of requests
(whether user can access a particular resource and what resources a particular
user can access)
Attribute-Based Access Control (ABAC)
Introducing… ReBAC!
It allows expressing authorization rules based on relations that users and objects in a
system have with each other.
Google Zanzibar
OpenFGA is based
on Zanzibar
There are other solutions out there, too: SpiceDB, Aserto,
Topaz, etc.
In order to make authorization decisions, OpenFGA
needs two types of data:
1.An authorization model
-Does not change often
-Usually updated when introducing new products
or features
2.The authorization data
-Changes very often
-Updated as relationships between objects
change