Write Security
How to manage write-access in Sync Gateway to ensure secure cloud-to-edge synchronization of enterprize data.
The Sync Function API provides several methods that you can use to validate document creation, updates and deletions.
Related access-control topics: Sync function | Read access | Write access
Introduction
You should use the Sync Function to validate any changes and to authorize document writes.
Access Old Document
Before you can validate a document update, you often need to know which user is changing it, and sometimes you need to compare the old and new revisions. The Sync Function makes it easy to access any pre-revision document content — see Example 1:
function(doc, oldDoc) { ... } (1)
1 | Here in the Sync Function header, the oldDoc contains the document content prior to any changes.
It is empty if this is a new document. |
Validate Document Changes
For document schema validation, you can write your own rules in the Sync Function. Use it to validate any document changes made before writing them.
When a document is deemed invalid, you can simply call the built-in JavaScript throw() function to raise an exception and reject the revision — see Example 2.
Rejected documents are not saved to the Sync Gateway database, so no access changes take effect. Instead an error code (usually 403 Forbidden) is returned to Couchbase Lite’s replicator.
Any other exception (including implicit ones thrown by the JavaScript runtime, like array bounds exceptions) will also prevent the document update.
These will cause the gateway to return an HTTP 500 — Internal Error
status.
throw ({forbidden: "error message"}) (1)
1 | A 403 — Forbidden status and the given error string is returned to the client. |
Check for Write Access
Use the Sync Function’s helper functions such as requireUser() or requireRole() to specify the user(s) allowed to write a document — see Example 3
In this example, our simple Sync Function validates whether the user modifying a document is a valid owner by checking if they are recorded as an owner of the old document:
function (doc, oldDoc) {
if (oldDoc) {
requireUser(oldDoc.owner); // may throw({forbidden: "wrong user"})
}
}
If the user or role making the change is not in that list, an exception is thrown and the update is rejected with an error.
Similarly, requireAccess() requires that the user making the change has access to any of the listed channels — see Example 4 for more helper function usage.
The Sync Function executes with admin privileges for changes made using the Admin REST API.
So, requireUser , requireAccess and requireRole are no-ops; they will always be successful.
|
This example shows how to use some of the helper functions:
requireUser("snej") (1)
requireUser(["snej", "jchris", "tleyden"]) (2)
requireRole("admin") (3)
requireRole(["admin", "old-timer"]) (4)
requireAccess("events") (5)
requireAccess(["events", "messages"]) (6)
1 | throw an error if username is not "snej" |
2 | throw if username is not in the list |
3 | throw an error unless the user has the "admin" role |
4 | throw an error unless the user has one of those roles |
5 | throw an error unless the user has access to read the "events" channel |
6 | throw an error unless the can read one of these channels |
When sending a change to Sync Gateway through the Admin REST API, the Sync Function is executed with admin privileges: calls to requireUser
, requireAccess
and requireRole
are no-ops (that is, they will always be successful).
To create and manage user accounts, refer to Users. |