Use Extended Attributes (XATTRs) for Access Grants


    How to set access grants using extended attributes (xattrs).
    Here we introduce the concept of XATTRS for access grants and their role in assuring secure access control within Sync Gateway.

    Related Topics: Concepts | How-to | Sync Function | Use XATTRs for Access Grants


    Access grant information such as Channels and Roles can be derived or specified as a property within the document body. In this case, the document content itself is used to govern access and routing.

    Alternatively, a more secure option is to store this information in user XATTRs for specifying channels and roles.

    Why use XATTRS

    XATTRs can be used to hold data used for document routing and access control [1]. When retrieved by the Sync Function, this data can be used to drive access grants. This approach has a few benefits:

    • It provide an added level of security, users can no longer identify the channels and users a document is available to by reading its contents, because the information is in metadata that is inaccessible to them

    • Separation of concerns. By separating access grant metadata from document contents, changes to access grants will not create a new document revision that is subsequently pushed to a client

    Sync Gateway exposes a single user-definable XATTR for this purpose. Learn how to configure it in Configuration and how to use it in Setting and Use XATTRs in a Sync Function.


    Name the XATTR (see: user_xattr_key) to be used for channel routing by defining it using the Admin REST API’s Database Configuration — see: Example 1.

    The actual value of this XATTR can be anything that enables the Sync Function to make an appropriate access grant. Its data type can be string, array, object — any valid JSON that meets the required use case.

    Example 1. Define the User Extended Attribute Key

    This example uses the Admin REST API to specify the required XATTR name as channelXattr on the database hotels.

    • CURL

    • HTTP

    curl -X PUT 'http://localhost:4985/hotels/_config' \
    --header 'Accept: application/json' \
    --header 'Content-Type: application/json' \
    --data-raw '{
        "user_xattr_key": "channelXattr" (1)
    PUT /hotels/_config HTTP/1.1
    Host: http://localhost:4985
    Accept: application/json
    Content-Type: application/json
    Content-Length: 999
      “user_xattr_key”: “channelXattr” (1)
    1 Here channelXattr is set as the name of the XATTR designated to hold channel routing information.


    You can set and maintain the value of the XATTR using a Couchbase Server SDK API. You cannot set it using the Sync Gateway REST API.

    For an example of setting the value of the XATTR using the C# SDK, see Example 2, this can be easily translated to any of the available SDK languages. See Example 3 for an example of the metadata model.

    Example 2. Set XATTR using Couchbase Server SDK
    using System;
    using System.Threading.Tasks;
    using Couchbase;
    using Couchbase.KeyValue; (1)
    namespace examples
        class Program
            static async Task Main(string[] args)
                // Set scope - cluster, bucket and collection
                var cluster =
                        await Cluster.ConnectAsync(
                var bucket = await cluster.BucketAsync("travel-sample");
                var collection = bucket.DefaultCollection();
                // Set required  user_xattr_key name and value
                var our_user_xattr_key_name = "channelXattr"; (2)
                String[] channelXattrValue =
                    {"channel1","channel3", "useradmin" }; (3)
                var ourDocumentType = "hotel";
                var documentKey = "";
                // Find our documents and get their ids
                var queryResult =
                   await cluster.QueryAsync<dynamic>(
                       "select meta().id from `travel-sample`.`_default`.`_default` h where h.type = $1",
                            new Couchbase.Query.QueryOptions().Parameter(ourDocumentType)); (4)
                await foreach (var row in queryResult)
                    documentKey =;
                    Console.WriteLine("Working with document id: {0} ",
                    // Check if the document has an existing
                    // user_xattr_key and update or insert new value
                    var result =
                        await collection.LookupInAsync(
                                specs => specs.Exists(
                                    path: our_user_xattr_key_name,
                                    isXattr: true)
                                ); (5)
                    if (result.Exists(0))
                        // Update xattr for retrieved Id
                        await collection.MutateInAsync(
                                specs => specs.Upsert(
                                    path: our_user_xattr_key_name, (6)
                                    value: channelXattrValue, (7)
                                    isXattr: true)); (8)
                        Console.Write("Updated Existing user_xattr_key: {0} to this value: {1}\n",
                            string.Join(", ", channelXattrValue));
                        // Insert xattr for retrieved id
                        await collection.MutateInAsync(
                                specs => specs.Insert(
                                    path: our_user_xattr_key_name, (9)
                                    value: channelXattrValue, (10)
                                    isXattr: true)); (11)
                        Console.Write("Inserted New user_xattr_key: {0} with value {1}\n",
                            string.Join(", ", channelXattrValue));
                Console.WriteLine("Completed Changes\n");
    1 This is required to make the MutateInSpec class available, providing access to sub-documents, of which metadata is a special class
    2 This string’s value is what we want this document’s XATTR to be called
    3 This array contains the channels we want to include as the XATTR value
    4 Here we get all documents that we want to set the XATTR on (type = 'hotel' in this instance)
    5 Check if the XATTR has been defined yet
    6 Update the XATTR — specify the item to update
    7 Update the XATTR — set the required value
    8 Update the XATTR — specify the item is an XATTR
    9 Insert the XATTR — specify the item to add (channelXattr)
    10 Insert the XATTR — set the required value using channelXattrValue
    11 Insert the XATTR — specify the item is an XATTR

    Running the code produces the following output:

    Working with document id: 1000
    Updated Existing user_xattr_key:
      channelXattr to this value: channel1, channel3, useradmin
    Working with document id: 1001
    Inserted New user_xattr_key:
      channelXattr with this value: channel1, channel3, useradmin
    Completed Changes
    Example 3. Metadata on Couchbase Server document
      "meta": { (1)
        "id": "1000",
        "rev": "7-1680c88cbce700000000000002000006",
        "expiration": 0,
        "flags": 33554438,
        "type": "json"
      "xattrs": { (2)
        "channelXattr": [ (3)
    1 This is the Fixed (or System) metadata
    2 This is the User metadata, where you can define extended attributes
    3 Here channelXattr is the name of the designated xattr holding the channel routing information to be passed to the Sync Function. You will set the value of the xattr using the SDK API when the document is created and-or updated.

    For more on Couchbase Server metadata and extended attributes — see Couchbase Server topics: Metadata | Extended Attributes

    Use XATTRs in a Sync Function

    The designated XATTR is exposed to the Sync Function as an additional argument meta.xattrs.<xattr name>

    Example 4. Sync Function Arguments
    function (doc, oldDoc, meta) { (1)
      if (meta.xattrs.channelXattr === undefined) (2)
          console.log("no user_xattr_key defined")
        } else {
          channel(meta.xattrs.channelXattr) (3)
      // Further processing as required ../
    1 The meta parameter exposes the user defined user_xattr_key if defined. The item takes the name configured for the database
    2 Access the meta parameter object to check an xattr exists on this document
    3 Use the content of the xattr to define the channels setting for this document

    See: Sync Function topic for more information.