Use SKDB groups to control who can see and modify data¶
SKDB groups define permission rules for users.
You can use a group id as the value of the skdb_access
column in a
mirrored table to control which users can see or modify the data.
There are three possible permissions a group can grant a user:
-
read
- can this user read the row? This is how you choose who can see the data. A user cannot modify data they cannot see. -
insert
- can this user insert a row with theskdb_access
column set to this group id? Use this to control who can create data. -
delete
- can this user delete this row?
Updates are possible if a user has both the delete
and insert
permission.
Use skdb_access
to control who can see and modify rows¶
A table can only be mirrored if it has an skdb_access
column defined
as text NOT NULL
. For example:
CREATE TABLE cannot_be_mirrored (id text PRIMARY KEY);
CREATE TABLE can_be_mirrored (id text PRIMARY KEY, skdb_access text NOT NULL);
The value stored in the skdb_access
column controls who can read or
modify the row.
Privacy in SKDB is not something you opt-in to, but must define in
order to share data with other users. This is why you cannot mirror a
table that does not have an skdb_access
column.
The value that you write in the skdb_access
column should be a:
-
user ID (often also referred to as an 'access key')
- only the user defined by this value is able to read or modify this row.
-
or a group ID
- The group with this ID defines who can read or modify this row.
- To write a row with this value, you must have the 'insert' permission. To read or delete this row, you must have the 'read' or 'delete' permission respectively.
- Please see create and manage a group for a discussion on how groups define access policies.
Create and manage a group¶
SKDB provides the createGroup()
method to make group creation easy.
With a connected client, let's create a group:
Groups can have a default permission for users. The default is that all users have no permissions. We will use the default permission to allow all users to read for this group.
We use the permission 'r' to indicate read
. 'i' corresponds to
insert
and 'd' for delete
. You can also use 'w' for insert
and
delete
permissions.
This is how you would specify that some users can read, insert, and delete.
We can use group.groupID
to get the groupID. This can be passed as a
param to a SQL statement or query in order to update the value for the
skdb_access
column.
Groups are defined in the system tables skdb_groups
and
skdb_group_permissions
.
We can query to see that the group definitions have been created.
console.log("The group ID is", group.groupID);
console.table(
await skdb.exec(
"SELECT * FROM skdb_groups WHERE groupID = @id",
{id: group.groupID},
),
);
console.table(
await skdb.exec(
"SELECT * FROM skdb_group_permissions WHERE groupID = @id",
{id: group.groupID},
),
);
The group ID is 3g476zUQiUqDsj94uB4N3tI-eAE
┌─────────┬───────────────────────────────┬─────────────┬─────────────────────────────────────┬──────────────┐
│ (index) │ groupID │ skdb_author │ adminID │ skdb_access │
├─────────┼───────────────────────────────┼─────────────┼─────────────────────────────────────┼──────────────┤
│ 0 │ '3g476zUQiUqDsj94uB4N3tI-eAE' │ 'root' │ 'admin-3g476zUQiUqDsj94uB4N3tI-eAE' │ 'read-write' │
└─────────┴───────────────────────────────┴─────────────┴─────────────────────────────────────┴──────────────┘
┌─────────┬───────────────────────────────┬───────────────────────────────┬─────────────┬─────────────────────────────────────┐
│ (index) │ groupID │ userID │ permissions │ skdb_access │
├─────────┼───────────────────────────────┼───────────────────────────────┼─────────────┼─────────────────────────────────────┤
│ 0 │ '3g476zUQiUqDsj94uB4N3tI-eAE' │ null │ 4 │ 'admin-3g476zUQiUqDsj94uB4N3tI-eAE' │
│ 1 │ '3g476zUQiUqDsj94uB4N3tI-eAE' │ 'fGuqIC7ix96La3p0vkBiZeCoUw9' │ 7 │ 'read-write' │
│ 2 │ '3g476zUQiUqDsj94uB4N3tI-eAE' │ 'root' │ 7 │ 'admin-3g476zUQiUqDsj94uB4N3tI-eAE' │
└─────────┴───────────────────────────────┴───────────────────────────────┴─────────────┴─────────────────────────────────────┘
Change the permissions for users in an existing group¶
Continuing our group example, let's get hold of a
group object from a group ID string and update the permissions for a user
using setMemberPermission()
.
setMemberPermission()
inserts a new definition for the user or
overwrites any existing definition.
const newGroupHandle = await skdb.lookupGroup(group.groupID);
await newGroupHandle.setMemberPermission(user, "ri");
console.log(
await skdb.exec(
`
SELECT
permissions
FROM
skdb_group_permissions
WHERE
groupID = @group
AND userID = @user`,
{group: newGroupHandle.groupID, user}
),
);
The permissions
value is 6
, corresponding to the 1st and 2nd bits
being set (4 + 2 = 6). But usually you would use the group API
described here or the skdb_permission()
function in SQL to avoid
errors.
Mnemonic | Bit | Meaning if set to 1 |
---|---|---|
d | 0 | User can delete the row. |
i | 1 | User can insert the row. |
r | 2 | User can read the row. |
Remove a user from a group¶
With a group created and a user added to it, let's now remove that user:
Add and remove group administrators¶
Only group admins can alter the permissions of a group. Group admins may
- add users with an initial set of permissions
- update the permissions for users
- remove a user from a group
Only group owners can add and remove group admins.
The user that created the group is the initial owner and also an admin of the group.
With a group created, let's add another user as an administrator:
const newAdmin = "fGypgZw0C_OPajASatBh9Sb4tEB";
await group.addAdmin(newAdmin);
console.log(
await skdb.exec(
"SELECT * FROM skdb_group_permissions WHERE userID = @newAdmin AND groupID = @adminGrp",
{newAdmin, adminGrp: group.adminGroupID},
),
);
SKDBTable(1) [
{
groupID: 'admin-3g475jnOh6pII38Drp4h5s7nwg',
userID: 'fGypgZw0C_OPajASatBh9Sb4tEB',
permissions: 7,
skdb_access: 'admin-3g475jnOh6pII38Drp4h5s7nwg'
}
]
Add and remove group owners¶
Only group owners can add and remove group admins. Group owners can also add and remove group owners.
The user that created the group is the initial owner.
With a group created, let's add another user as an owner and then remove them:
const newOwner = "fGuqIC7ix96La3p0vkBiZeCoUw9";
await group.addOwner(newOwner);
await group.removeOwner(newOwner);
Transfer group ownership¶
It is possible to transfer group ownership to another user so that they can add and remove admins from the group.
With a connected client, let's create a group and then transfer ownership to another user: