Webstrates A research prototype enabling collaborative editing of websites through DOM manipulations.

Webstrates supports per-webstrate permission configuration, allowing users of a webstrate to only permit certain users read and/or write access to a webstrate.

To enable the permissions functionality, the Webstrate server must be configured with at least one OAuth provider. See Server Configuration for information on how to configure your server with permissions.

Permissions in a webstrate is configured using the data-auth attribute that can be set on the <html> tag in JSON format.

The data-auth property

If no data-auth attribute has been set (or it’s malformed), any user will have access to the webstrate according to the default permissions defined in the server configuration. This will usually mean access to view, modify or delete the webstrate, unless loggedInToCreateWebstrates has been configured in the server configuration. In this case, only users logged in with the configured OAuth providers will be able to modify or create webstrate documents.

The data-auth should contain a serialized JavaScript array, consisting of objects with the properties username, provider and permissions, or alternatively, objects containing only webstrateId to inherit permissions from another webstrate.

<html data-auth='[{"username": "cklokmose", "provider": "github", "permissions": "rw"},
  {"username": "anonymous", "provider": "", "permissions": "r"}]'>
...
</html>

The above example provides the user with GitHub username cklokmose permissions to read and write (rw), while users who are not logged in (anonymous) only have read (r) access. Logged-in users will automatically inherit the permissions of the anonymous user (if defined), and thus also have read permissions to the webstrate. Any users not present in the permissions list will not have any access to the webstrate (either explicitly or implicitly through the anynomous user).

Any user with write permissions will implictly also have read permissions. Adding r to cklokmose in the above is thus technically redundant, but it adds some clarity to the user.

Wait, what's my username and provider?

Each user logged in with an OAuth provider will have a unique userId. The userId is the username and provider joined together with a :.

When logged in (authorized with a OAuth provider), the userId, username, and provider will be available on the webstrate.user object as webstrate.user.userId, webstrate.user.username, and webstrate.user.provider, respectively.

The webstrate.user will also have a permissions property, containing the user's permissions in the current webstrate, e.g. rw.

Admin permissions

The admin permission a allows only certain users to be able to edit the permissions of a webstrate and delete and restore the webstrate.

[ {"username": "cklokmose", "provider": "github", "permissions": "rw"},
  { "username": "kbadk", "provider": "github", "permissions": "arw" },
  ... ]

In the above example, the user kbadk has been promoted to admin of the document and therefore neither cklokmose or any other user may modify the data-auth property or delete or restore the webstrate.

Deleting and restoring the webstrate is restricted, because otherwise a malicious user may simply delete the webstrate and recreate it as their own, or restore the webstrate to before the permissions were added and take over the webstrate.

A webstrate can have multiple admins. Admin privilege is not inherited.

Permission inheritance

Permission inheritance allows one webstrate to inherit all its permissions from another webstrate, thus making it easier to manage users across multiple webstrates.

Adding { webstrateId: <some-webstrateId> } to the permissions list (data-auth), inherits the permissions of <some-webstrateId> into the current webstrate.

[ {"username": "raedle", "provider": "github", "permissions": "rw"},
  { "webstrateId": "test-webstrate" },
  ... ]

In the above example, we inherit the permissions from the webstrate test-webstrate. If test-webstrate contains the permissions we defined in the previous example, the users cklokmose and kbadk would now also have rw to the document.

Note that the admin privilege is not inherited into the new document: The user kbadk will therefore only have rw permission in the webstrate; the same as raedle and cklokmose.

Recursive inheritance is supported up to a depth of 3. E.g. webstrate X can inherit from Y, Y can inherit from Z, but even though Z inherits from W, the users of W won’t have access to X. Both the users of Y and Z, however, will have access.

Inheriting from multiple webstrates is also allowed.

If multiple permissions are found for the same user in different webstrates inherited from, the first one found takes precedence. E.g. if user A has r permissions to webstrate Y and rw permissions to webstrate Z, and X inherits from Y and then from Z (i.e. [{ webstrateId: 'Y' }, { webstrateId: 'Z' }, ...]), user A will only have r permissions to X. This mechanism can also be used to exclude members who would otherwise have access by simply preceding the permissions list with an empty permission, e.g. [{ username: 'A', provider: 'github', permissions: '' }, { webstrateId: 'Y' }, { webstrateId: 'Z' }, ...]. This will disallow user A permission to X, regardless of A’s permissions in Y and Z.

If webstrate X inherits from webstrate Y, and permissions in X changes, they will immediately be reflected (as usual). However, if the permissions change in Y, the changes will not be reflected until the permissions of X have been modified, or until the permission cache expires. Permissions will expire after 2 minutes or as defined by permissionTimeout in the server configuration.