Permission

With Permission, we can control the access to resources. By default, no one has access to the resources. We can grant read, write, or delete permissions to specific users, roles, or groups.

The Tailor DB supports both Type-level and Record-level permissions. The Type-level permissions are applied to all resources of a given Type, while The Record-level permissions work against a specific record of a given Type.

The Record-level permissions must be more restrictive than the permissions defined in the Type-level. If both levels of permissions are set, the record will be subject to both permission rules, which will be applied in an AND condition.

Type-level permission

With the Type-level permission, we can control access to a specific Type (corresponding to Table).

We can set up Type-level permission in the CUE schema file. 2 steps to apply the permission.

  1. Set permission in the schema file

  2. Apply the changes using tailorctl

Assume we have an Payroll type resource that contains sensitive data such as pay amount.

Let's grant User A (id:11111111-1111-1111-1111-111111111111) permissions for create, read, and admin operations on the Payroll type of resources.

1. Set permission in the schema file

We can set TypePermission field in the type definition schema file.

In the permission, we can set create, delete, update, read, and admin permissions.

Each permission field has an array of Id and Permit.

  • Id: Target audience to which the permission applies. This can be the ID of a user, role, or group, or one of the following special pre-defined variables.
    • tailordb.#EveryoneUserID: Applies to all anonymous users
  • Permit: tailordb.#Permit.Allow or tailordb.#Permit.Deny or tailordb.#Permit.Skip. No need to set tailordb.#Permit.Deny for every out-of-scope audience as the permission default rule is restricting anyone.
<span><span style="color: var(--shiki-color-text)">Payroll: tailordb.#Type </span><span style="color: var(--shiki-token-keyword)">&amp;</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">  Description: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">Payroll information</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">  Fields:      {</span></span>
<span><span style="color: var(--shiki-color-text)">    grossPay: {</span></span>
<span><span style="color: var(--shiki-color-text)">      Type:        tailordb.#TypeInt</span></span>
<span><span style="color: var(--shiki-color-text)">      Description: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">Grosspay in payroll</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-comment)">// Define permission for create, delete and admin to user id: 11111111-1111-1111-1111-111111111111</span></span>
<span><span style="color: var(--shiki-color-text)">  TypePermission: tailordb.#TypePermissions </span><span style="color: var(--shiki-token-keyword)">&amp;</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">    Create: [</span></span>
<span><span style="color: var(--shiki-color-text)">        {Id: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">11111111-1111-1111-1111-111111111111</span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)">   Permit: tailordb.#Permit.Allow}</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">    ]</span></span>
<span><span style="color: var(--shiki-color-text)">    Delete: [</span></span>
<span><span style="color: var(--shiki-color-text)">        {Id: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">11111111-1111-1111-1111-111111111111</span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)">   Permit: tailordb.#Permit.Allow}</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">    ]</span></span>
<span><span style="color: var(--shiki-color-text)">    Admin: [</span></span>
<span><span style="color: var(--shiki-color-text)">        {Id: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">11111111-1111-1111-1111-111111111111</span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)">   Permit: tailordb.#Permit.Allow}</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">    ]</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

2. Apply the changes using tailorctl

<span><span style="color: var(--shiki-token-function)">tailorctl</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">manifest</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">tidy</span></span>
<span><span style="color: var(--shiki-token-function)">cue</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">eval</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">-f</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">manifest/workspace.cue</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">-o</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">generated/workspace.cue</span></span>
<span><span style="color: var(--shiki-token-function)">tailorctl</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">workspace</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">apply</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">-m</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">generated/workspace.cue</span></span>
<span></span>

We can now verify the Type-level permission behavior through the GraphQL queries.

To execute operations as the user, we need to create a user by mutation.

<span><span style="color: var(--shiki-token-keyword)">mutation</span><span style="color: var(--shiki-color-text)">{</span></span>
<span><span style="color: var(--shiki-color-text)">  createUser(</span></span>
<span><span style="color: var(--shiki-color-text)">      input: {</span></span>
<span><span style="color: var(--shiki-color-text)">        </span><span style="color: var(--shiki-token-string)">name</span><span style="color: var(--shiki-color-text)">: </span><span style="color: var(--shiki-token-string-expression)">&quot;{USER_NAME}&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">        </span><span style="color: var(--shiki-token-string)">email</span><span style="color: var(--shiki-color-text)">: </span><span style="color: var(--shiki-token-string-expression)">&quot;{USER_EMAIL}&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">        </span><span style="color: var(--shiki-token-string)">roles</span><span style="color: var(--shiki-color-text)">: </span><span style="color: var(--shiki-token-string-expression)">&quot;11111111-1111-1111-1111-111111111111&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">      }</span></span>
<span><span style="color: var(--shiki-color-text)">  ){</span></span>
<span><span style="color: var(--shiki-color-text)">    id</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

NOTE: Make sure this user is created in the preferred identity provider. Refer Auth service to setup the identity provider.

After creating the user, run the following command to login to the application:

<span><span style="color: var(--shiki-token-function)">tailorctl</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">workspace</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">app</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">login</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">-n</span><span style="color: var(--shiki-color-text)"> ${your-app-name} </span></span>
<span></span>

After successfully logging in, we will receive the authorization token.

We can now include this token in the HTTP Authorization header to access protected resources.

To include the token in GraphQL Playground, navigate to the Headers tab and add the token to the Authorization header.

<span><span style="color: var(--shiki-color-text)">{</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-keyword)">&quot;Authorization&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;Bearer &lt;token&gt;&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

User A should be able to create Payroll resources with the following query

<span><span style="color: var(--shiki-token-keyword)">mutation</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">  createPayroll(input: { </span><span style="color: var(--shiki-token-string)">grossPay</span><span style="color: var(--shiki-color-text)">: </span><span style="color: var(--shiki-token-constant)">100</span><span style="color: var(--shiki-color-text)"> }) {</span></span>
<span><span style="color: var(--shiki-color-text)">    id</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

The create permission is granted to User A in the setting above, allowing the mutation query to be executed successfully.

<span><span style="color: var(--shiki-color-text)">{</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-keyword)">&quot;data&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">    </span><span style="color: var(--shiki-token-keyword)">&quot;createPayroll&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">      </span><span style="color: var(--shiki-token-keyword)">&quot;id&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;&lt;resource_uuid&gt;&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

However, we cannot delete the Payroll resource as we haven't set up delete permission in the setting. We'll see the permissions are correctly applied to the Payroll resources.

<span><span style="color: var(--shiki-token-keyword)">mutation</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">deletePayroll</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">  deletePayroll(id: </span><span style="color: var(--shiki-token-string-expression)">&quot;&lt;resource_uuid&gt;&quot;</span><span style="color: var(--shiki-color-text)">)</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

It should return an error response like below:

<span><span style="color: var(--shiki-color-text)">{</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-keyword)">&quot;errors&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> [</span></span>
<span><span style="color: var(--shiki-color-text)">    {</span></span>
<span><span style="color: var(--shiki-color-text)">      </span><span style="color: var(--shiki-token-keyword)">&quot;message&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;access denied&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">      </span><span style="color: var(--shiki-token-keyword)">&quot;locations&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> [</span></span>
<span><span style="color: var(--shiki-color-text)">        {</span></span>
<span><span style="color: var(--shiki-color-text)">          </span><span style="color: var(--shiki-token-keyword)">&quot;line&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">1</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">          </span><span style="color: var(--shiki-token-keyword)">&quot;column&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">2</span></span>
<span><span style="color: var(--shiki-color-text)">        }</span></span>
<span><span style="color: var(--shiki-color-text)">      ]</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">      </span><span style="color: var(--shiki-token-keyword)">&quot;path&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> [</span><span style="color: var(--shiki-token-string-expression)">&quot;deletePayroll&quot;</span><span style="color: var(--shiki-color-text)">]</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span></span>
<span><span style="color: var(--shiki-color-text)">  ]</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-keyword)">&quot;data&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">    </span><span style="color: var(--shiki-token-keyword)">&quot;deletePayroll&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">null</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

Record level permission

While Type-level permission is applied against all resources of the type, Record-level permission works against the single resource.

There are 2 ways to set record level permissions:

  • Setting the recordPermission property when defining a model.
  • Sending a change<type_name> GraphQL query to update permissions on a live application.

Apply recordPermission property

We can set recordPermission field in the type definition schema file.

In the permission, we can set the following permissions.

  • read
  • update
  • delete

Each permission field has an array of id and permit like the Type-level permission.

Permissions are applied when the defined events occur.

Note : You cannot define recordPermission on its own. It is always defined with the Type-level permission and works within the scope allowed by the Type-level permission.

<span><span style="color: var(--shiki-color-text)">Payroll: tailordb.#Type </span><span style="color: var(--shiki-token-keyword)">&amp;</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">  Description: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">Payroll information</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">  Fields:      {</span></span>
<span><span style="color: var(--shiki-color-text)">    grossPay: {</span></span>
<span><span style="color: var(--shiki-color-text)">      Type:        tailordb.#TypeInt</span></span>
<span><span style="color: var(--shiki-color-text)">      Description: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">Grosspay in payroll</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-comment)">// Define permission for create, delete and admin to `Role` id: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee</span></span>
<span><span style="color: var(--shiki-color-text)">  TypePermission: tailordb.#TypePermissions </span><span style="color: var(--shiki-token-keyword)">&amp;</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">    Create: [</span></span>
<span><span style="color: var(--shiki-color-text)">        {Id: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee</span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)">   Permit: tailordb.#Permit.Allow}</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">    ]</span></span>
<span><span style="color: var(--shiki-color-text)">    Delete: [</span></span>
<span><span style="color: var(--shiki-color-text)">        {Id: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee</span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)">   Permit: tailordb.#Permit.Allow}</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">    ]</span></span>
<span><span style="color: var(--shiki-color-text)">    Admin: [</span></span>
<span><span style="color: var(--shiki-color-text)">        {Id: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee</span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)">   Permit: tailordb.#Permit.Allow}</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">    ]</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-comment)">// Define permission for update and read to `User` id: 11111111-1111-1111-1111-111111111111</span></span>
<span><span style="color: var(--shiki-color-text)">  RecordPermission: {</span></span>
<span><span style="color: var(--shiki-color-text)">    Update: [</span></span>
<span><span style="color: var(--shiki-color-text)">      {Id: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">11111111-1111-1111-1111-111111111111</span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> Permit: tailordb.#Permit.Allow}</span></span>
<span><span style="color: var(--shiki-color-text)">    ]</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">    Read: [</span></span>
<span><span style="color: var(--shiki-color-text)">      {Id: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">11111111-1111-1111-1111-111111111111</span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> Permit: tailordb.#Permit.Allow}</span></span>
<span><span style="color: var(--shiki-color-text)">    ]</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

If there are two users, here is the behavior for each:

UserA (id: 11111111-1111-1111-1111-111111111111)

UserB (id: 22222222-2222-2222-2222-222222222222)

Both users have the same role (id: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee).

In the case of the above example, here is the behavior of each:

  • Read: Only UserA can read payroll records but UserB cannot read.
  • Update: Both users cannot update payroll records because the role id: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee is not allowed to update on the Type-level permission.
  • Delete: Both users can delete.

Apply record level permission through GraphQL query

In Payroll example, changePayroll can change permissions to the single resource of Payroll by specifying the resource ID and permissions.

To use any change<type_name> mutation, the user need to have an admin permission at the type level. We can verify the Record-level permission behavior through the GraphQL queries in the following steps:

  1. Create a new Payroll resource
  2. Read the resource
  3. Change the read permission at the Record level.
  4. Retry to read the resource

1. Create a new Payroll resource

First, we'll need to create a new Payroll resource by executing the following query.

<span><span style="color: var(--shiki-token-keyword)">mutation</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">createPayroll</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">  createPayroll(input: { </span><span style="color: var(--shiki-token-string)">grossPay</span><span style="color: var(--shiki-color-text)">: </span><span style="color: var(--shiki-token-constant)">100</span><span style="color: var(--shiki-color-text)"> }) {</span></span>
<span><span style="color: var(--shiki-color-text)">    id</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

Use the created resource uuid in the next step.

<span><span style="color: var(--shiki-color-text)">{</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-keyword)">&quot;data&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">    </span><span style="color: var(--shiki-token-keyword)">&quot;createPayroll&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">      </span><span style="color: var(--shiki-token-keyword)">&quot;id&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;&lt;resource_uuid&gt;&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

2. Read the resource

Using the resource UUID created in the previous step, User A can read the resource of Payroll as the Type-level read permission is set for the Payroll Type. See Type-level permission setting.

<span><span style="color: var(--shiki-color-text)">{</span></span>
<span><span style="color: var(--shiki-color-text)">  payroll(id: </span><span style="color: var(--shiki-token-string-expression)">&quot;&lt;resource_uuid&gt;&quot;</span><span style="color: var(--shiki-color-text)">) {</span></span>
<span><span style="color: var(--shiki-color-text)">    grossPay</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

It should return a successful response like below:

<span><span style="color: var(--shiki-color-text)">{</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-keyword)">&quot;data&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">    </span><span style="color: var(--shiki-token-keyword)">&quot;payroll&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">      </span><span style="color: var(--shiki-token-keyword)">&quot;grossPay&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">100</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

3. Change permission for read

Let's change the Record-level permission by changePayroll mutation. The following query set permission to deny read access to the resource created in the 1st step.

<span><span style="color: var(--shiki-token-keyword)">mutation</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">changePermission</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">  changePayroll(</span></span>
<span><span style="color: var(--shiki-color-text)">    id: </span><span style="color: var(--shiki-token-string-expression)">&quot;&lt;resource_uuid&gt;&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">    read: [{ </span><span style="color: var(--shiki-token-string)">id</span><span style="color: var(--shiki-color-text)">: </span><span style="color: var(--shiki-token-string-expression)">&quot;&lt;user_uuid&gt;&quot;</span><span style="color: var(--shiki-color-text)">, </span><span style="color: var(--shiki-token-string)">permit</span><span style="color: var(--shiki-color-text)">: deny }]</span></span>
<span><span style="color: var(--shiki-color-text)">  )</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

4. Retry to read the resource

Let's verify the permission behavior by running the following query:

<span><span style="color: var(--shiki-color-text)">{</span></span>
<span><span style="color: var(--shiki-color-text)">  payroll(id: </span><span style="color: var(--shiki-token-string-expression)">&quot;&lt;resource_uuid&gt;&quot;</span><span style="color: var(--shiki-color-text)">) {</span></span>
<span><span style="color: var(--shiki-color-text)">    grossPay</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

As we set the read permission to deny for the specified user, the user can no longer read the resource.

<span><span style="color: var(--shiki-color-text)">{</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-keyword)">&quot;errors&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> [</span></span>
<span><span style="color: var(--shiki-color-text)">    {</span></span>
<span><span style="color: var(--shiki-color-text)">      </span><span style="color: var(--shiki-token-keyword)">&quot;message&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;failed to access to record with id = {&lt;your_domain_name&gt; Payroll} &lt;resource_uuid&gt;&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">      </span><span style="color: var(--shiki-token-keyword)">&quot;locations&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> [</span></span>
<span><span style="color: var(--shiki-color-text)">        {</span></span>
<span><span style="color: var(--shiki-color-text)">          </span><span style="color: var(--shiki-token-keyword)">&quot;line&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">1</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">          </span><span style="color: var(--shiki-token-keyword)">&quot;column&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">16</span></span>
<span><span style="color: var(--shiki-color-text)">        }</span></span>
<span><span style="color: var(--shiki-color-text)">      ]</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">      </span><span style="color: var(--shiki-token-keyword)">&quot;path&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> [</span><span style="color: var(--shiki-token-string-expression)">&quot;payroll&quot;</span><span style="color: var(--shiki-color-text)">]</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span></span>
<span><span style="color: var(--shiki-color-text)">  ]</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-keyword)">&quot;data&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">    </span><span style="color: var(--shiki-token-keyword)">&quot;payroll&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">null</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

Getting permission

<type_name>Permission is an auto-generated API, which returns the permissions set in the resource based on the provided resource ID.

Here is a sample query and response:

<span><span style="color: var(--shiki-color-text)">{</span></span>
<span><span style="color: var(--shiki-color-text)">  taskPermission(id: </span><span style="color: var(--shiki-token-string-expression)">&quot;c3e9313b-ef80-45da-a5b2-f6d77810dd92&quot;</span><span style="color: var(--shiki-color-text)">) {</span></span>
<span><span style="color: var(--shiki-color-text)">    read {</span></span>
<span><span style="color: var(--shiki-color-text)">      permit</span></span>
<span><span style="color: var(--shiki-color-text)">      id</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span></span>
<span><span style="color: var(--shiki-color-text)">    update {</span></span>
<span><span style="color: var(--shiki-color-text)">      permit</span></span>
<span><span style="color: var(--shiki-color-text)">      id</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span></span>
<span><span style="color: var(--shiki-color-text)">    delete {</span></span>
<span><span style="color: var(--shiki-color-text)">      permit</span></span>
<span><span style="color: var(--shiki-color-text)">      id</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>
<span><span style="color: var(--shiki-color-text)">{</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-keyword)">&quot;data&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">    </span><span style="color: var(--shiki-token-keyword)">&quot;taskPermission&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">      </span><span style="color: var(--shiki-token-keyword)">&quot;read&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> [</span></span>
<span><span style="color: var(--shiki-color-text)">        {</span></span>
<span><span style="color: var(--shiki-color-text)">          </span><span style="color: var(--shiki-token-keyword)">&quot;permit&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;deny&quot;</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">          </span><span style="color: var(--shiki-token-keyword)">&quot;id&quot;</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;11111111-1111-1111-1111-111111111111&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">        }</span></span>
<span><span style="color: var(--shiki-color-text)">      ]</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>