{"id":4136,"date":"2017-10-23T11:39:31","date_gmt":"2017-10-23T18:39:31","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=4136"},"modified":"2025-06-13T23:43:19","modified_gmt":"2025-06-14T06:43:19","slug":"using-role-based-access-control-in-n1ql","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/","title":{"rendered":"Using Role-Based Access Control in N1QL"},"content":{"rendered":"<p>In Couchbase 4.5, data was secured bucket by bucket. Each bucket had a password, and in order to access a bucket through a N1QL query, the user had to include the bucket password with the query. Passwordless buckets were possible, but not recommended for production use.<\/p>\n<p>This scheme offered basic protection, but it was very coarse-grained: a user could either do everything with a bucket, or nothing at all. Also, queries accessing many buckets required passing in a password for every bucket, which was inconvenient, particularly if passwords changed.<\/p>\n<p>To allow our users to avoid these problems, we introduced role-based access control (RBAC) in Couchbase Server 5.0. Access to data is now controlled through fine-grained roles on buckets, and every user can be assigned roles that fit what they should actually be doing in the database.<\/p>\n<p>In this article I will walk you through the main functionality offered by RBAC in Couchbase Server 5.0. Hands-on exercises will let you try out the new features for yourself.<\/p>\n<h2>Setup<\/h2>\n<p>For the hands-on exercises, you will need to install Couchbase Server 5.0, Enterprise Edition. During installation, configure it to have an administrator named &#8220;Administrator&#8221; with password &#8220;password&#8221;. This is not recommended practice in a production environment, of course.<\/p>\n<p>Log in to the administration console (at https:\/\/localhost:8091) and go to the Buckets screen. There create two buckets, &#8220;testbucket1&#8221; and &#8220;testbucket2&#8221;, each with a memory quota of 100 MB to avoid running out of memory.<\/p>\n<p>Then go to the Query screen and create primary indexes on the two buckets you have just created. The primary indexes let you run queries on the buckets.<\/p>\n<pre class=\"\">CREATE PRIMARY INDEX ON testbucket1\r\nCREATE PRIMARY INDEX ON testbucket2<\/pre>\n<p>You can go the Indexes screen to verify that the indexes were actually created. Both will be named &#8220;#primary&#8221;.<\/p>\n<h2>Main Roles<\/h2>\n<p><span style=\"font-weight: 400\">There are four main roles that control who can execute what N1QL queries. The roles query_select, query_insert, query_update, and query_delete each let you execute N1QL queries of the corresponding type. There are also three more specialized roles (query_manage_index, query_system_catalog, and query_external_access) that will be covered in the next section, Important Additional Roles.<\/span><\/p>\n<p><span style=\"font-weight: 400\">But there&#8217;s more to it. These roles are parameterized by the bucket they apply to. A user can&#8217;t just have role query_select; we need to know what bucket the role is on, such as query_select[testbucket1], which lets the user run a SELECT query against testbucket1. It is also possible to have this role on all buckets, indicated by query_select[*].<\/span><\/p>\n<p><span style=\"font-weight: 400\">To try this yourself, go into the Couchbase console and in the Security screen create a new user user1 with password &#8220;password&#8221; and role query_select[testbucket1].<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-4137\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2017\/10\/new-user-0-260x300.png\" alt=\"\" width=\"260\" height=\"300\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/new-user-0-260x300.png 260w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/new-user-0-300x346.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/new-user-0-17x20.png 17w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/new-user-0.png 538w\" sizes=\"auto, (max-width: 260px) 100vw, 260px\" \/><\/p>\n<p>The role is found under &#8220;Query Roles&#8221; in the user creation menu.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-4138\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2017\/10\/new-user-1-262x300.png\" alt=\"\" width=\"262\" height=\"300\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/new-user-1-262x300.png 262w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/new-user-1-300x344.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/new-user-1-17x20.png 17w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/new-user-1.png 524w\" sizes=\"auto, (max-width: 262px) 100vw, 262px\" \/><\/p>\n<p><span style=\"font-weight: 400\">Then do the same for &#8220;user2&#8221;, but give that user query_select[testbucket2].<\/span><\/p>\n<p><span style=\"font-weight: 400\">Now let&#8217;s try running a query against these buckets using the roles. I&#8217;ll use the CBQ shell tool that comes with Couchbase.<\/span><\/p>\n<pre>cbq -e https:\/\/localhost:8093\/ -s \"select * from testbucket1\"<\/pre>\n<p><span style=\"font-weight: 400\">That get us this response:<\/span><\/p>\n<pre class=\"\">{\r\n\"requestID\": \"d838da35-24a3-415e-b9e1-69ac02a9820b\",\r\n\"signature\": {\"*\":\"*\"},\r\n\"results\": [\r\n],\r\n\"errors\": [{\"code\":13014,\"msg\":\"User does not have credentials to run SELECT queries on the testbucket1 bucket. Add role query_select on testbucket1 to allow the query to run.\"}],\r\n\"status\": \"stopped\",\r\n\"metrics\": {\"elapsedTime\": \"4.214692ms\",\"executionTime\": \"4.190101ms\",\"resultCount\": 0,\"resultSize\": 0,\"errorCount\": 1}\r\n}\r\n<\/pre>\n<p><span style=\"font-weight: 400\">Notice that the error tells us very clearly what role we are lacking. Let&#8217;s try again with user1, who has the correct role:<\/span><\/p>\n<pre>cbq -e https:\/\/localhost:8093\/ -s \"select * from testbucket1\" -u user1 -p password<\/pre>\n<p><span style=\"font-weight: 400\">That worked:<\/span><\/p>\n<pre class=\"\">{\r\n\"requestID\": \"caeba7de-d9eb-4e2f-8f67-d6e795fb1dbd\",\r\n\"signature\": {\"*\":\"*\"},\r\n\"results\": [\r\n],\r\n\"status\": \"success\",\r\n\"metrics\": {\"elapsedTime\": \"11.501861ms\",\"executionTime\": \"11.471201ms\",\"resultCount\": 0,\"resultSize\": 0}\r\n}<\/pre>\n<p>Try the query yourself with user2, who has the right role but on the wrong bucket. The request will fail.<\/p>\n<p>Now let&#8217;s try a more complex query that touches two buckets. Start by running this query:<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ \r\n    -s \"INSERT INTO testbucket2 (KEY source.c_id, VALUE source.customer) \r\n        SELECT * FROM testbucket1 source WHERE source.new = true\"<\/pre>\n<p>The system tells us it needs role query_insert[testbucket2]:<\/p>\n<pre class=\"\">\"errors\": [{\"code\":13014,\"msg\":\"User does not have credentials to run INSERT queries \r\n     on the testbucket2 bucket. Add role query_insert on testbucket2 to allow the query to run.\"}],<\/pre>\n<p>Create a new user &#8220;user3&#8221; with the required role, and try again:<\/p>\n<pre class=\"\">\"errors\": [{\"code\":13014,\"msg\":\"User does not have credentials to run SELECT queries \r\n     on the testbucket1 bucket. Add role query_select on testbucket1 to allow the query to run.\"}],<\/pre>\n<p>We are still getting an error, but it is a different error than before. The query we are trying to run has two parts; it selects from testbucket1 and inserts into testbucket2. We have provided enough credentials for the insertion but not for the selection. Go into the console, add query_select[testbucket2] to user3 and try again. This time the query works.<\/p>\n<pre class=\"\">{\r\n\"requestID\": \"3c313c29-8b67-4e63-92b0-763586345f59\",\r\n\"signature\": null,\r\n\"results\": [\r\n],\r\n\"status\": \"success\",\r\n\"metrics\": {\"elapsedTime\": \"11.451689ms\",\"executionTime\": \"11.415157ms\",\"resultCount\": 0,\"resultSize\": 0}\r\n}<\/pre>\n<p>Let&#8217;s try one more thing. Add a RETURNING clause to the query and try to execute it:<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ -s \"INSERT INTO testbucket2 (KEY source.c_id, VALUE source.customer)\r\n       SELECT * FROM testbucket1 source WHERE source.new = true RETURNING meta().id id\" \r\n    -u user3 -p password<\/pre>\n<p>This fails:<\/p>\n<pre class=\"\">\"errors\": [{\"code\":13014,\"msg\":\"User does not have credentials to run SELECT queries \r\n     on the testbucket2 bucket. Add role query_select on testbucket2 to allow the query to run.\"}],<\/pre>\n<p>What&#8217;s going on here is that the RETURNING clause is being treated as a SELECT on the bucket we inserted into (testbucket2), occurring just after the insertion. The user does not have the query_select[testbucket2] role and is therefore being refused.<\/p>\n<p>Add role query_select[testbucket2] to user3 and rerun the query. It will now work.<\/p>\n<h2>Important Additional Roles<\/h2>\n<p>There are three more roles you should know when working with N1QL.<\/p>\n<p><strong>query_manage_index<\/strong><br \/>\nFirst, let&#8217;s try to create an index:<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ -s \"CREATE INDEX test_idx ON testbucket1(price)\"<\/pre>\n<p>That gets us an error:<\/p>\n<pre class=\"\">\"errors\": [{\"code\":13014,\"msg\":\"User does not have credentials to run index operations. \r\n     Add role query_manage_index on testbucket1 to allow the query to run.\"}],\r\n\"status\": \"stopped\",<\/pre>\n<p>The role Query Manage Index on a bucket is necessary for creating, deleting, or building indexes on that bucket.<\/p>\n<p>Create a new user &#8220;user4&#8221; with role query_manage_index[testbucket1]. Try the <a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/createindex.html\">index creation<\/a> again. The query will now work.<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ -s \"CREATE INDEX test_idx ON testbucket1(price)\" \r\n    -u user4 -p password<\/pre>\n<p><strong>query_system_catalog<\/strong><br \/>\nIn earlier versions of Couchbase, the system tables were fully accessible to anyone. They are now more restricted in various ways that will be described later in this document, but there is a useful role, query_system_catalog, that allows for access to the system tables. This is particularly useful for staff who need to be able to debug problems with queries or the system, but shouldn&#8217;t be given full administrator privileges.<\/p>\n<p>If we query system:keyspaces as administrator, we see both of the bucket we have created in the system:<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ -s \"SELECT * FROM system:keyspaces\" -u Administrator -p password<\/pre>\n<pre class=\"\">{\r\n\"requestID\": \"46ee066e-25f6-4bef-a70a-553f4c224c39\",\r\n\"signature\": {\"*\":\"*\"},\r\n\"results\": [\r\n{\"keyspaces\":{\"datastore_id\":\"https:\/\/127.0.0.1:8091\",\"id\":\"testbucket2\",\"name\":\"testbucket2\",\"namespace_id\":\"default\"}},\r\n{\"keyspaces\":{\"datastore_id\":\"https:\/\/127.0.0.1:8091\",\"id\":\"testbucket1\",\"name\":\"testbucket1\",\"namespace_id\":\"default\"}}\r\n],\r\n\"status\": \"success\",\r\n\"metrics\": {\"elapsedTime\": \"16.562026ms\",\"executionTime\": \"16.52656ms\",\"resultCount\": 2,\"resultSize\": 238}\r\n}<\/pre>\n<p><span style=\"font-weight: 400\">But if we run the same query without credentials, the results are filtered out:<\/span><\/p>\n<pre class=\"\">{\r\n\"requestID\": \"932e6b73-3058-4877-8da1-1715b16e53f5\",\r\n\"signature\": {\"*\":\"*\"},\r\n\"results\": [\r\n],\r\n\"warnings\": [{\"code\":11011,\"msg\":\"One or more documents were excluded from the system:keyspaces bucket because of insufficient user permissions.\"}],\r\n\"status\": \"success\",\r\n\"metrics\": {\"elapsedTime\": \"20.563024ms\",\"executionTime\": \"20.532213ms\",\"resultCount\": 0,\"resultSize\": 0,\"warningCount\": 1}\r\n}<\/pre>\n<p><span style=\"font-weight: 400\">Create a new user &#8220;user5&#8221; with role query_system_catalog, and rerun the query. You will see the same results as when we ran the query as Administrator.<\/span><\/p>\n<p><strong>Query_external_access<\/strong><\/p>\n<p><span style=\"font-weight: 400\">The new CURL() function makes it possible to query REST services from within N1QL. To use the function, we need to do some configuration, and run the query using the new role query_external_access. <\/span><\/p>\n<p><span style=\"font-weight: 400\">Let&#8217;s try the query first:<\/span><\/p>\n<pre>cbq -e https:\/\/localhost:8093\/query\/service \r\n    -s 'SELECT CURL(\"https:\/\/maps.googleapis.com\/maps\/api\/geocode\/json\", \r\n        {\"data\":\"address=Half+Moon+Bay\", \"get\":true}) GEO'<\/pre>\n<p><span style=\"font-weight: 400\">The query is refused because appropriate permissions are not supplied:<\/span><\/p>\n<pre>\"errors\": [{\"code\":13014,\"msg\":\"User does not have credentials to run queries using \r\n     the CURL() function. Add role query_external_access to allow the query to run.\"}]<\/pre>\n<p><span style=\"font-weight: 400\">Create a user &#8220;user6&#8221; with role query_external_access and rerun the query using that user. This time the query refuses to run because we have not enabled CURL(); for security reasons it is disabled by default.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Create a file &#8220;curl_whitelist.json&#8221; with the following contents:<\/span><\/p>\n<pre>{\"all_access\":true}<\/pre>\n<p><span style=\"font-weight: 400\">Place it under the couchbase directory. On a Mac, the exact location is &#8220;\/Applications\/Couchbase Server.app\/Contents\/Resources\/couchbase-core\/var\/lib\/couchbase\/n1qlcerts\/curl_whitelist.json&#8221;. On other systems, the location is <\/span><a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/3.x\/admin\/Misc\/install-location.html\"><span style=\"font-weight: 400\">slightly different<\/span><\/a><span style=\"font-weight: 400\">. Try the query again, which should run correctly, downloading data like this:<\/span><\/p>\n<pre class=\"\">\"address_components\" : [\r\n {\r\n \"long_name\" : \"Half Moon Bay\",\r\n \"short_name\" : \"Half Moon Bay\",\r\n \"types\" : [ \"locality\", \"political\" ]\r\n },\r\n {\r\n \"long_name\" : \"San Mateo County\",\r\n \"short_name\" : \"San Mateo County\",\r\n \"types\" : [ \"administrative_area_level_2\", \"political\" ]\r\n },\r\n {\r\n \"long_name\" : \"California\",\r\n \"short_name\" : \"CA\",\r\n \"types\" : [ \"administrative_area_level_1\", \"political\" ]\r\n },\r\n {\r\n \"long_name\" : \"United States\",\r\n \"short_name\" : \"US\",\r\n \"types\" : [ \"country\", \"political\" ]\r\n }<\/pre>\n<p>The full list of N1QL roles is as follows:<\/p>\n<table>\n<tbody>\n<tr>\n<td><b>Role<\/b><\/td>\n<td><b>Permits<\/b><\/td>\n<td><b>GRANT Syntax<\/b><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Query Select<\/span><\/td>\n<td><span style=\"font-weight: 400\">SELECT Statements<\/span><\/td>\n<td><span style=\"font-weight: 400\">GRANT select ON testbucket TO myuser<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Query Insert<\/span><\/td>\n<td><span style=\"font-weight: 400\">INSERT Statements<\/span><\/td>\n<td><span style=\"font-weight: 400\">GRANT insert ON testbucket TO myuser<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Query Update<\/span><\/td>\n<td><span style=\"font-weight: 400\">UPDATE Statements<\/span><\/td>\n<td><span style=\"font-weight: 400\">GRANT update ON testbucket TO myuser<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Query Delete<\/span><\/td>\n<td><span style=\"font-weight: 400\">DELETE Statements<\/span><\/td>\n<td><span style=\"font-weight: 400\">GRANT delete ON testbucket to myuser<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Query System Catalog<\/span><\/td>\n<td><span style=\"font-weight: 400\">Access to system keyspaces<\/span><\/td>\n<td><span style=\"font-weight: 400\">GRANT query_system_catalog TO myuser<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Query Manage Index<\/span><\/td>\n<td><span style=\"font-weight: 400\">Index Operations<\/span><\/td>\n<td><span style=\"font-weight: 400\">GRANT query_manage_index ON testbucket TO myuser<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400\">Query External Access<\/span><\/td>\n<td><span style=\"font-weight: 400\">CURL() Function<\/span><\/td>\n<td><span style=\"font-weight: 400\">GRANT query_external_access TO myuser<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>EXPLAIN and PREPARE<\/h2>\n<p>Of course, we can do things with queries other than just running them. We can use EXPLAIN to understand how the query engine computes a query. And we can use PREPARE to set up a query for repeated execution.<\/p>\n<p>In Couchbase 5.0, the permissions for EXPLAIN and PREPARE are simple. They are the same as the permissions required for the underlying statement. That&#8217;s all there is to it.<\/p>\n<p>To test this, let&#8217;s try to EXPLAIN a simple SELECT statement, the same one we used in the earlier &#8220;Primary Roles&#8221; section:<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ -s \"explain select * from testbucket1\"<\/pre>\n<p>In response we get an error message asking for a specific role:<\/p>\n<pre>\"errors\": [{\"code\":13014,\"msg\":\"User does not have credentials to run SELECT queries \r\n    on the testbucket1 bucket. Add role query_select on testbucket1 to allow the query to run.\"}],<\/pre>\n<p><span style=\"font-weight: 400\">Let&#8217;s provide a user with that role:<\/span><\/p>\n<pre>cbq -e https:\/\/localhost:8093\/ -s \"explain select * from testbucket1\" -u user1 -p password<\/pre>\n<p><span style=\"font-weight: 400\">Success, just as we saw for the statement itself back in &#8220;Primary Roles&#8221;.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Now let&#8217;s try to PREPARE the second statement from &#8220;Primary Roles&#8221;:<\/span><\/p>\n<pre>cbq -e https:\/\/localhost:8093\/ \r\n    -s \"PREPARE INSERT INTO testbucket2 (KEY source.c_id, VALUE source.customer) \r\n        SELECT * FROM testbucket1 source WHERE source.new = true\"<\/pre>\n<p><span style=\"font-weight: 400\">We get the same error message we originally got for the statement itself:<\/span><\/p>\n<pre>\"errors\": [{\"code\":13014,\"msg\":\"User does not have credentials to run INSERT queries on the \r\n     testbucket2 bucket. Add role query_insert on testbucket2 to allow the query to run.\"}],<\/pre>\n<p><span style=\"font-weight: 400\">And if we add a user with credentials for the SELECT and INSERT, the PREPARE succeeds:<\/span><\/p>\n<pre>cbq -e https:\/\/localhost:8093\/ \r\n    -s \"PREPARE INSERT INTO testbucket2 (KEY source.c_id, VALUE source.customer) \r\n        SELECT * FROM testbucket1 source WHERE source.new = true\" \r\n    -u user3 \r\n    -p password<\/pre>\n<h2>GRANT and REVOKE<\/h2>\n<p><span style=\"font-weight: 400\">In 5.0, N1QL includes statements for giving users roles (GRANT) and for taking them away (REVOKE). These statements require Administrator permission to run.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Before trying out these statements, let&#8217;s review what users are configured and what roles they have. Here is what you should see in the Security screen of the Couchbase console.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-4139\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2017\/10\/user-permissions-300x161.png\" alt=\"\" width=\"300\" height=\"161\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/user-permissions-300x161.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/user-permissions-20x11.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/user-permissions.png 628w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>We can grant a new role cluster_admin to user1 like this:<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ -s \"grant cluster_admin to user1\" -u Administrator -p password<\/pre>\n<p>This will succeed, and shortly thereafter the Couchbase console will update to reflect the new role assignment.<\/p>\n<p>We can also assign parameterized roles, like this:<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ \r\n    -s \"grant query_insert on testbucket2 to user2\" \r\n    -u Administrator \r\n    -p password<\/pre>\n<p>We can undo the initial grant by a REVOKE:<\/p>\n<pre>cbq -e https:\/\/localhost:8093\/ -s \"revoke cluster_admin from user1\" -u Administrator -p password<\/pre>\n<p><span style=\"font-weight: 400\">All of these parameters can take lists of arguments:<\/span><\/p>\n<pre>cbq -e https:\/\/localhost:8093\/ \r\n    -s \"grant query_insert, query_delete on testbucket1, testbucket2 to user5, user6\" \r\n    -u Administrator \r\n    -p password<\/pre>\n<p><span style=\"font-weight: 400\">And finally, the query_ prefix is optional for query_insert, query_update, query_delete, and query_select, making some of the syntax more familiar:<\/span><\/p>\n<pre>cbq -e \u00a0https:\/\/localhost:8093\/ -s \"grant insert,delete on testbucket1 to user4\" \r\n    -u Administrator -p password<\/pre>\n<h2>Comparison with Oracle<\/h2>\n<p>Role-based access control in Couchbase 5.0 has been designed to be familiar to professionals who have used access control in other current database systems. By now, you should have recognized familiar concepts such as insert\/select\/update\/delete permissions being applicable to buckets, which are sort of like tables. Also, the notion of administrator users with broad permissions should be familiar.\u00a0Role-based access control in Couchbase 5.0 has been designed to be familiar to professionals who have used access control in other current database systems. By now, you should have recognized familiar concepts such as insert\/select\/update\/delete permissions being applicable to buckets, which are sort of like tables. Also, the notion of administrator users with broad permissions should be familiar.<\/p>\n<p>For example, this GRANT query will work on both Couchbase and Oracle:<\/p>\n<pre class=\"\">GRANT select, insert ON default TO jlarson, pedwards<\/pre>\n<p>One conceptual difference between Couchbase and other systems such as Oracle is that we have a binary model of privilege: users and roles. They typically have a trinary model, with users, roles, and privileges. Accordingly, giving users permissions in Oracle is about granting privileges on objects to users. In Couchbase, it&#8217;s about granting parameterized roles to users.<\/p>\n<p>Roles are static in 5.0. There is no equivalent of statements to CREATE\/DROP\/ALTER ROLE.<\/p>\n<p>Couchbase permissions are either on the system as a whole or on buckets. We have no notion of permissions on tables, columns, or collections.<\/p>\n<p>In Couchbase GRANT and REVOKE are only possible by Admin users. There is no such thing as an ADMIN OPTION or a GRANT OPTION. Changing permissions requires you to be an Administrator.<\/p>\n<p>Finally, we have no equivalent of SET ROLE. SET ROLE is a session-level command, which makes no sense in Couchbase because we have no sessions, only individual RESTful requests.<\/p>\n<h2>New System Keyspaces<\/h2>\n<p>Couchbase 5.0 introduces three new system keyspaces related to users. The first of these is system:user_info. This keyspace lists the users configured in the system, including their roles. Let&#8217;s try a query:<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ -s \"select * from system:user_info\" -u Administrator -p password<\/pre>\n<p>That gets us seven entries like this, one for every user we have set up, plus the configured Administrator:<\/p>\n<pre class=\"\">{\"user_info\":{\"domain\":\"local\",\"id\":\"user4\",\"name\":\"User4\",\"roles\":[{\"bucket_name\":\"testbucket1\",\"role\":\"query_manage_index\"},{\"bucket_name\":\"testbucket1\",\"role\":\"insert\"},{\"bucket_name\":\"testbucket1\",\"role\":\"delete\"}]}},\r\n{\"user_info\":{\"domain\":\"local\",\"id\":\"user2\",\"name\":\"User 2\",\"roles\":[{\"bucket_name\":\"testbucket2\",\"role\":\"select\"},{\"bucket_name\":\"testbucket2\",\"role\":\"insert\"}]}},\r\n{\"user_info\":{\"domain\":\"local\",\"id\":\"user5\",\"name\":\"User5\",\"roles\":[{\"bucket_name\":\"testbucket2\",\"role\":\"insert\"},{\"bucket_name\":\"testbucket1\",\"role\":\"insert\"},{\"bucket_name\":\"testbucket2\",\"role\":\"delete\"},{\"bucket_name\":\"testbucket1\",\"role\":\"delete\"},{\"role\":\"query_system_catalog\"}]}},<\/pre>\n<p>The system:applicable_roles keyspace is similar, but breaks up each user role into a separate entry, producing a more relational view of the data:<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ \r\n    -s \"select * from system:applicable_roles where grantee = 'user3'\" \r\n    -u Administrator \r\n    -p password<\/pre>\n<pre class=\"\">\"results\": [\r\n{\"applicable_roles\":{\"bucket_name\":\"testbucket2\",\"grantee\":\"user3\",\"role\":\"select\"}},\r\n{\"applicable_roles\":{\"bucket_name\":\"testbucket1\",\"grantee\":\"user3\",\"role\":\"select\"}},\r\n{\"applicable_roles\":{\"bucket_name\":\"testbucket2\",\"grantee\":\"user3\",\"role\":\"insert\"}}\r\n],<\/pre>\n<p>Finally, the system:my_user_info keyspace shows the portion of system:my_user_info corresponding to the user whose credentials are passed in with the query.<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ -s \"select * from system:my_user_info\" -u user3 -p password<\/pre>\n<pre class=\"\">\"results\": [\r\n{\"my_user_info\":{\"domain\":\"local\",\"id\":\"user3\",\"name\":\"User 3\",\r\n   \"roles\":[{\"bucket_name\":\"testbucket2\",\"role\":\"select\"},{\"bucket_name\":\"testbucket1\",\"role\":\"select\"},{\"bucket_name\":\"testbucket2\",\"role\":\"insert\"}]}}\r\n],<\/pre>\n<h2>Access to System Keyspaces<\/h2>\n<p>In keeping with a general philosophy of secure operation, system keyspaces (buckets) are secured in version 5.0. The degree of restriction varies based on the data present in each keyspace.<\/p>\n<p>Three keyspaces have nothing that is likely to be valuable to an attacker:<\/p>\n<ul>\n<li>system:datastores<\/li>\n<li>system:namespaces<\/li>\n<li>system:dual<\/li>\n<\/ul>\n<p>Accordingly, these keyspaces are not secured. No credentials are needed to access them.<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/query\/service -s \"select * from system:datastores\"<\/pre>\n<pre class=\"\">\"results\": [\r\n{\"datastores\":{\"id\":\"https:\/\/127.0.0.1:8091\",\"url\":\"https:\/\/127.0.0.1:8091\"}}\r\n],<\/pre>\n<p>At the other end of security are system:user_info and system:applicable_roles, which contain the list of users and their roles. These are accessible only by Admin and Read Only Admin users. The system:my_user_info table is similar, but only shows the relevant information for the user whose credentials are presented with the query. We have already explored these tables, above.<\/p>\n<p>The next four system keyspaces contain a variety of runtime and configuration information.<\/p>\n<ul>\n<li>System:prepareds<\/li>\n<li>System:completed_requests<\/li>\n<li>System:active_requests<\/li>\n<li>System:nodes<\/li>\n<\/ul>\n<p>Since the information in them is not as sensitive as user information, they are more widely viewable. They can be accessed by most admins, even minor ones: Admin, Read Only Admin, Cluster Admin, Query System Catalog, Replication Admin, Bucket Admin(any bucket), or Views Admin(any bucket).<\/p>\n<p>Let&#8217;s try looking at system:prepareds as user5, the user we created with Query System Catalog permission, above.<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ -s \"select * from system:prepareds\" -u user5 -p password<\/pre>\n<p>This shows us one prepared statement that we created earlier.<\/p>\n<p>The system:keyspaces keyspace shows the list of buckets configured in the system. This information is somewhat sensitive, since it gives an attacker information about what a system is used for. Accordingly, users with high-level roles (Admin, Read Only Admin, Cluster Admin) see everything in this keyspace. Users with the Query System Catalog role also see everything, since this role is intended for debugging query problems. For other users, the view is filtered; the user sees only those keyspaces for which they have query_select permission.<\/p>\n<p><span style=\"font-weight: 400\">For example, a query against system:keyspaces with no credentials will succeed but will show no entries:<\/span><\/p>\n<pre>cbq -e https:\/\/localhost:8093\/ -s \"select * from system:keyspaces\"<\/pre>\n<pre>\"results\": [\r\n\r\n],<\/pre>\n<p><span style=\"font-weight: 400\">Add credentials for user5, who has the Query System Catalog role, and all entries are shown:<\/span><\/p>\n<pre>cbq -e https:\/\/localhost:8093\/ -s \"select * from system:keyspaces\" -u user5 -p password<\/pre>\n<pre class=\"\">\"results\": [\r\n{\"keyspaces\":{\"datastore_id\":\"https:\/\/127.0.0.1:8091\",\"id\":\"testbucket1\",\"name\":\"testbucket1\",\"namespace_id\":\"default\"}},\r\n{\"keyspaces\":{\"datastore_id\":\"https:\/\/127.0.0.1:8091\",\"id\":\"testbucket2\",\"name\":\"testbucket2\",\"namespace_id\":\"default\"}}\r\n],<\/pre>\n<p><span style=\"font-weight: 400\">Use credentials for user1, who has only query_select[testbucket1], and you&#8217;ll see only the entry for testbucket1.<\/span><\/p>\n<pre>cbq -e https:\/\/localhost:8093\/ -s \"select * from system:keyspaces\" -u user1 -p password<\/pre>\n<pre class=\"\">\"results\": [\r\n{\"keyspaces\":{\"datastore_id\":\"https:\/\/127.0.0.1:8091\",\"id\":\"testbucket1\",\"name\":\"testbucket1\",\"namespace_id\":\"default\"}}\r\n],<\/pre>\n<p><span style=\"font-weight: 400\">The system:indexes keyspace is handled much like system:keyspaces: high-level roles allow complete access, while the query_select role allows filtered access. The real difference is that the query_manage_index role allows filtered access, like query_select.<\/span><\/p>\n<h2>Protection for Admin APIs<\/h2>\n<p>The N1QL query engine has RESTful APIs corresponding to three of the system keyspaces: system:prepareds, system:completed_requests, and system:active_requests. These used to be open in Couchbase 4.6, but are now secured. They require the same credentials as the the keyspaces do.<\/p>\n<pre class=\"\">curl https:\/\/localhost:8093\/admin\/prepareds<\/pre>\n<pre class=\"\">{\"caller\":\"auth:268\",\r\n \"code\":13014,\"key\":\"datastore.couchbase.insufficient_credentiasl\",\r\n \"message\":\"User does not have credentials to run queries accessing the system tables. \r\n     Add role query_system_catalog to allow the query to run.\"}<\/pre>\n<p>If we try again with user5, who has the required role, it works.<\/p>\n<pre class=\"\">curl https:\/\/localhost:8093\/admin\/prepareds -u user5:password<\/pre>\n<h2>Access to Migrated Passwordless Buckets<\/h2>\n<p>When migrating from 4.6 to 5.0, it is useful to preserve existing permissions patterns, to allow legacy applications to keep working as they did before. This is a bit tricky in this case, because in 4.6 access was controlled using passwords on buckets themselves, whereas in 5.0 access control is based on users with various roles.<\/p>\n<p>To preserve legacy access patterns, during the upgrade process we create users with names and passwords matching the original bucket. This lets existing applications keep doing what they were doing, even in the case of access without any password at all.<\/p>\n<p>Seeing this in action is going to take some work. Get comfortable.<\/p>\n<p>Begin by installing Couchbase 4.6. Then create two buckets, &#8220;openbucket&#8221; with no password and &#8220;closedbucket&#8221; with password &#8220;password&#8221;.<\/p>\n<p>Go to the Query tab and add primary indexes for both buckets to allow N1QL queries to run.Go to the Query tab and add primary indexes for both buckets to allow N1QL queries to run.<\/p>\n<pre class=\"\">create primary index on openbucket\r\ncreate primary index on closedbucket<\/pre>\n<p>Verify that openbucket can be queried without a password:<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ -s \"select * from openbucket\"<\/pre>\n<p>But querying closedbucket without a password fails:<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ -s \"select * from closedbucket\"<\/pre>\n<p>But closedbucket can be queried with a password:<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ -s \"select * from closedbucket\" -u closedbucket -p password<\/pre>\n<p>This is the pattern of access we want to preserve as we upgrade to 5.0.\u00a0Now shut down Couchbase, and upgrade to 5.0, while preserving the underlying data we have just created. Then go to the Security screen of the Couchbase console. There you will see two new users created by the upgrade process.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-4140\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2017\/10\/created-users-300x63.png\" alt=\"\" width=\"300\" height=\"63\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/created-users-300x63.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/created-users-20x4.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/created-users.png 735w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>The &#8220;closedbucket&#8221; user has the same name as the &#8220;closedbucket&#8221; bucket and the password that was assigned to the bucket in 4.6. It allows us to preserve legacy access to closedbucket. The &#8220;openbucket&#8221; user does the same, but for openbucket.<\/p>\n<p>Let&#8217;s check that the earlier access pattern still works.<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ -s \"select * from openbucket\"<\/pre>\n<p>Openbucket is still accessible without a password.<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ -s \"select * from closedbucket\"<\/pre>\n<p>Closedbucket access fails without a password.<\/p>\n<pre class=\"\">cbq -e https:\/\/localhost:8093\/ -s \"select * from closedbucket\" -u closedbucket -p password<\/pre>\n<p>But closedbucket access succeeds with a password.<\/p>\n<p>Hurray! Things work as they did before. Go fix yourself a treat.<\/p>\n<h2>Summary<\/h2>\n<ul>\n<li>Access control in in Couchbase 4.6 was using passwords for buckets. In 5.0 it is using roles assigned to users.<\/li>\n<li>The primary roles used to control a user&#8217;s access to N1QL are query_select\/query_insert\/query_update\/query_delete. All of them are parameterized by bucket.<\/li>\n<li>Important more specialized roles include query_manage_index, query_system_catalog, and query_external_access.<\/li>\n<li>Explaining or preparing a query requires the same roles as executing it would.<br \/>\nThere are new statements that let you GRANT and REVOKE roles.<\/li>\n<li>The system of roles should be familiar to users familiar with other major databases. The main difference is that Couchbase has no notion of permissions outside of roles.<\/li>\n<li>There are new system keyspaces for querying users and the roles assigned to them.<br \/>\nSystem keyspaces are controlled for security. The behavior varies from keyspace to keyspace depending on the sensitivity of the data therein.<\/li>\n<li>Existing access patterns, even for passwordless buckets, should still work after migration from 4.6 to 5.0.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In Couchbase 4.5, data was secured bucket by bucket. Each bucket had a password, and in order to access a bucket through a N1QL query, the user had to include the bucket password with the query. Passwordless buckets were possible, [&hellip;]<\/p>\n","protected":false},"author":8157,"featured_media":4141,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1813,1812],"tags":[1903],"ppma_author":[9058],"class_list":["post-4136","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-security","category-n1ql-query","tag-rbac"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.8 (Yoast SEO v25.8) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Role-Based Access Control (RBAC) Use in N1QL | Couchbase<\/title>\n<meta name=\"description\" content=\"Walk through the main functionality of role-based access control (RBAC) in Couchbase. These exercises will let you try out the new features for yourself.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Using Role-Based Access Control in N1QL\" \/>\n<meta property=\"og:description\" content=\"Walk through the main functionality of role-based access control (RBAC) in Couchbase. These exercises will let you try out the new features for yourself.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2017-10-23T18:39:31+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T06:43:19+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/Chain-link_and_barbed_wire.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2048\" \/>\n\t<meta property=\"og:image:height\" content=\"1365\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Johan Larson\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Johan Larson\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/\"},\"author\":{\"name\":\"Johan Larson\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/043ccbbfc54b95927c73f81ec7f6a0a1\"},\"headline\":\"Using Role-Based Access Control in N1QL\",\"datePublished\":\"2017-10-23T18:39:31+00:00\",\"dateModified\":\"2025-06-14T06:43:19+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/\"},\"wordCount\":2838,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/Chain-link_and_barbed_wire.jpg\",\"keywords\":[\"RBAC\"],\"articleSection\":[\"Security\",\"SQL++ \/ N1QL Query\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/\",\"name\":\"Role-Based Access Control (RBAC) Use in N1QL | Couchbase\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/Chain-link_and_barbed_wire.jpg\",\"datePublished\":\"2017-10-23T18:39:31+00:00\",\"dateModified\":\"2025-06-14T06:43:19+00:00\",\"description\":\"Walk through the main functionality of role-based access control (RBAC) in Couchbase. These exercises will let you try out the new features for yourself.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/Chain-link_and_barbed_wire.jpg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/Chain-link_and_barbed_wire.jpg\",\"width\":2048,\"height\":1365},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Using Role-Based Access Control in N1QL\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/043ccbbfc54b95927c73f81ec7f6a0a1\",\"name\":\"Johan Larson\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/93b175bb8728e12439dd573fc27b9d1a\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/2ddf616344da1f84e85c42ba2bfc102e28380128c107cc21eeecc26edc737227?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/2ddf616344da1f84e85c42ba2bfc102e28380128c107cc21eeecc26edc737227?s=96&d=mm&r=g\",\"caption\":\"Johan Larson\"},\"description\":\"Johan Larson is a Senior Software Engineer at Couchbase. Johan's work responsibility is building an SQL-based query language for JSON data in a distributed NoSQL system.\",\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/johan-larson\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Role-Based Access Control (RBAC) Use in N1QL | Couchbase","description":"Walk through the main functionality of role-based access control (RBAC) in Couchbase. These exercises will let you try out the new features for yourself.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/","og_locale":"en_US","og_type":"article","og_title":"Using Role-Based Access Control in N1QL","og_description":"Walk through the main functionality of role-based access control (RBAC) in Couchbase. These exercises will let you try out the new features for yourself.","og_url":"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/","og_site_name":"The Couchbase Blog","article_published_time":"2017-10-23T18:39:31+00:00","article_modified_time":"2025-06-14T06:43:19+00:00","og_image":[{"width":2048,"height":1365,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/Chain-link_and_barbed_wire.jpg","type":"image\/jpeg"}],"author":"Johan Larson","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Johan Larson","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/"},"author":{"name":"Johan Larson","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/043ccbbfc54b95927c73f81ec7f6a0a1"},"headline":"Using Role-Based Access Control in N1QL","datePublished":"2017-10-23T18:39:31+00:00","dateModified":"2025-06-14T06:43:19+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/"},"wordCount":2838,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/Chain-link_and_barbed_wire.jpg","keywords":["RBAC"],"articleSection":["Security","SQL++ \/ N1QL Query"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/","url":"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/","name":"Role-Based Access Control (RBAC) Use in N1QL | Couchbase","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/Chain-link_and_barbed_wire.jpg","datePublished":"2017-10-23T18:39:31+00:00","dateModified":"2025-06-14T06:43:19+00:00","description":"Walk through the main functionality of role-based access control (RBAC) in Couchbase. These exercises will let you try out the new features for yourself.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/Chain-link_and_barbed_wire.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/10\/Chain-link_and_barbed_wire.jpg","width":2048,"height":1365},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/using-role-based-access-control-in-n1ql\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Using Role-Based Access Control in N1QL"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/043ccbbfc54b95927c73f81ec7f6a0a1","name":"Johan Larson","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/93b175bb8728e12439dd573fc27b9d1a","url":"https:\/\/secure.gravatar.com\/avatar\/2ddf616344da1f84e85c42ba2bfc102e28380128c107cc21eeecc26edc737227?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/2ddf616344da1f84e85c42ba2bfc102e28380128c107cc21eeecc26edc737227?s=96&d=mm&r=g","caption":"Johan Larson"},"description":"Johan Larson is a Senior Software Engineer at Couchbase. Johan's work responsibility is building an SQL-based query language for JSON data in a distributed NoSQL system.","url":"https:\/\/www.couchbase.com\/blog\/author\/johan-larson\/"}]}},"authors":[{"term_id":9058,"user_id":8157,"is_guest":0,"slug":"johan-larson","display_name":"Johan Larson","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/2ddf616344da1f84e85c42ba2bfc102e28380128c107cc21eeecc26edc737227?s=96&d=mm&r=g","author_category":"","last_name":"Larson","first_name":"Johan","job_title":"","user_url":"","description":"Johan Larson is a Senior Software Engineer at Couchbase. Johan's work responsibility is building an SQL-based query language for JSON data in a distributed NoSQL system."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/4136","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/8157"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=4136"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/4136\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/4141"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=4136"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=4136"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=4136"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=4136"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}