Permission

With Permission, you 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. Type-level permissions apply to all resources of a specified type, whereas Record-level permissions are specific to individual records of that type. Record-level permissions are also assigned by default when a record is created.

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.

Here's a table describing resource access for each type of permission.

Permission TypeResource Access Description
Type-level

Create

Add new row to the table using create<type-name> mutation.

Delete

Delete a row from the table using delete<type-name> mutation.

Update

Update specific row in the table using update<type-name> mutation.

Read

Read data from a table by querying the <type-name>.

Admin

A user or role must have Admin permission at the Type-level to execute the change<type-name> mutation to update the permissions of the records.

Record-level

Update

Update a specific record in the table.

Delete

Delete a specific record from the table.

Read

Read records of a specific type.

Admin

A user or role must have Admin permission at the Type-level to apply any Record-level permissions.

You must set Type-level permissions to apply any Record-level permissions to the type. Refer Apply record permission to learn more.

Type-level permission

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

You can set up Type-level permission in the CUE schema file using the following 2 steps.

  1. Set permission in the schema file

  2. Apply the changes using tailorctl

Assume you have a 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

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

In the permission, you can set Create, Delete, Update, Read, and Admin permissions.

Each permission field has an array of objects with Id and Permit values.

  • 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 default permission rule restricts everyone.
<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)">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)">./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, you 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>

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, you will receive the authorization token.

You 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, you cannot delete the Payroll resource as you haven't set up delete permission in the setting. Notice that the permissions are correctly applied to the Payroll resource.

<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, you can set Create, Delete, Update, Read, and Admin permissions.

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

Permissions are applied when the defined events occur.

<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 the Payroll example, changePayroll can change permissions for 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>