Configuring permission rules

Introduction

Access control rules in Hasura are defined at a role, table and action (insert, update, select, delete) level granularity:

Access control rules in Hasura

Requests to Hasura should contain the reserved session variable X-Hasura-Role to indicate the requesting user’s role, and the table and action information is inferred from the request itself. This information is used to determine the right permission rule to be applied (if one has been defined) to the incoming request.

Hasura converts GraphQL queries (or mutations/subscriptions) into a single SQL query that is executed on the configured database instance. Hasura also includes constraints from permission rules in the SQL query itself.

Permissions are essentially a combination of boolean expressions and column selections that impose constraints on the data being returned or modified.

Let’s take a look at the different configuration options available to define a permission rule. Permission rules are defined for each role, table, operation (insert, select, update, delete) by using the console or the metadata APIs for permissions.

Operation permissions

Select permissions

For select operations or for GraphQL queries, you can configure the following:

Insert permissions

For insert operations or for GraphQL mutations of the type insert, you can configure the following:

Update permissions

For update operations or for GraphQL mutations of the type update, you can configure the following:

Delete permissions

For delete operations or for GraphQL mutations of the type delete, you can configure the following:

Permission categories

Row-level permissions

Row-level premissions are boolean expressions that help you restrict access to rows depending on the operation being performed. E.g. in the case of select, your boolean expression is run on every row to determine whether that row can be read. In the case of insert, the boolean expression determines whether or not the mutation is allowed.

Row-level permissions are defined using operators, static values, values in columns (including those in related tables or nested objects) and session variables.

Using column operators to build rules

Type-based operators (depending on the column type) are available for constructing row-level permissions. You can use the same operators that you use to filter query results along with a few others to define permission rules.

See the API reference for a list of all supported column operators.

For example, the following two images illustrate the different operators available for integer and text types:

Column operators for integer types Column operators for text types

Using boolean expressions

The following is an example of a simple boolean expression to restrict access for select to rows where the value in the id column is greater than 10:

You can define permissions using boolean expressions on the Hasura console as follows:

Using boolean expressions to build rules

You can define permissions using boolean expressions in the tables.yaml file inside the metadata directory:

   - table:
       schema: public
       name: author
     select_permissions:
     - role: user
       permission:
         columns: []
         filter:
           id:
             _gt: 10

Apply the metadata by running:

hasura metadata apply

You can define permissions using boolean expressions when using the permissions metadata API:

POST /v1/query HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin

{
   "type": "create_select_permission",
   "args": {
      "table": "author",
      "role": "user",
      "permission": {
         "columns": "*",
         "filter": {
            "id": {"_gt": 10}
         }
      }
   }
}

You can construct more complex boolean expressions using the _and, _or and not operators:

Using more complex boolean expressions to build rules

For example, using the _and operator, you can construct a rule to restrict access for select to rows where the value in the id column is greater than 10 and the value in the name column starts with “a” or “A”:

You can define permissions using the _and operator on the Hasura console as follows:

Example of a rule with the _and operator

You can define permissions using the _and operator in the tables.yaml file inside the metadata directory:

   - table:
       schema: public
       name: author
     select_permissions:
     - role: user
       permission:
         columns: []
         filter:
           _and:
             - id: {_gt: 10}
             - name: {_ilike: a%}

Apply the metadata by running:

hasura metadata apply

You can define permissions using the _and operator when using the permissions metadata API:

POST /v1/query HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin

{
   "type": "create_select_permission",
   "args": {
      "table": "author",
      "role": "user",
      "permission": {
         "columns": "*",
         "filter": {
            "$and": [
               {
                  "id": {
                     "_gt": 10
                  }
               },
               {
                  "name": {
                     "_ilike": "a%"
                  }
               }
            ]
         }
      }
   }
}

Using session variables

Session variables that have been resolved from authentication tokens by either your authentication webhook or by Hasura using the JWT configuration are available for constructing row-level permissions.

For example, to allow an author to access only their articles, you can use the X-Hasura-User-ID session variable to construct a rule to restrict access for select to rows in the articles table where the value in the id column is equal to the value in the session variable (assuming this variable is being used to indicate the author’s ID):

You can define session variables in permissions on the Hasura console:

Using session variables to build rules

You can define session variables in permissions in the tables.yaml file inside the metadata directory:

   - table:
       schema: public
       name: article
     select_permissions:
     - role: author
       permission:
         columns:
         - title
         - content
         filter:
           id:
             _eq: X-Hasura-User-Id

Apply the metadata by running:

hasura metadata apply

You can define session variables in permissions tables when using the permissions metadata API:

POST /v1/query HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin

{
   "type": "create_select_permission",
   "args": {
      "table": "article",
      "role": "author",
      "permission": {
         "columns": "*",
         "filter": {
            "id": "X-Hasura-User-Id"
         }
      }
   }
}

Array session variables in permission rules

Support for using session variables for array operators like _in, _nin, _has_any_keys, _has_all_keys is available in versions v1.0.0-beta.3 and above.

When you use array operators such as _in in the permissions builder in the Hasura console, it will automatically open an array for your values. If your session variable value is already an array, you can click the [X-Hasura-Allowed-Ids] suggestion to remove the brackets and set your session variable in its place.

Using relationships or nested objects

You can leverage table relationships to define permission rules with fields from a nested object.

For example, let’s say you have an object relationship called agent from the authors table to another table called agent (an author can have an agent) and we want to allow users with the role agent to access the details of the authors who they manage in authors table. We can define the following permission rule that uses the aforementioned object relationship:

You can use a nested object to build rules on the Hasura console:

Using a nested object to build rules

You add permissions using relationships or nested objects in the tables.yaml file inside the metadata directory:

   - table:
       schema: public
       name: author
     select_permissions:
     - role: agent
       permission:
         columns: []
         filter:
           agent:
             agent_id:
               _eq: X-Hasura-User-Id

Apply the metadata by running:

hasura metadata apply

You add permissions using relationships or nested objects when using the permissions metadata API:

POST /v1/query HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin

   {
      "type": "create_select_permission",
      "args": {
         "table": "author",
         "role": "agent",
         "permission": {
            "columns": "*",
            "filter": {
               "agent": {
                  "agent_id": {
                     "_eq": "X-Hasura-User-Id"
                  }
               }
            }
         }
      }
   }

This permission rule reads as “if the author’s agent’s id is the same as the requesting user’s id , allow access to the author’s details.”

Array and object relationships work similarly

  • The above example would have worked even if the relationship were an array relationship. In our example, the corresponding rule for an array relationship would have read “if any of this author’s agents’ id is the same as the requesting user’s id , allow access to the author’s details”.
  • You can also check out this more elaborate example.

Using unrelated tables / views

You can use the _exists operator to set a permission rule based on tables/views that are not related to our table.

For example, say we want to allow a user to insert an article only if the value of the allow_article_create column in the users table is set to true. Let’s assume the user’s id is passed in the X-Hasura-User-ID session variable.

You can set permissions using unrelated tables on the Hasura console as follows:

Use an unrelated table to build rules

You can set permissions using unrelated tables in the tables.yaml file inside the metadata directory:

   - table:
       schema: public
       name: article
     insert_permissions:
     - role: user
       permission:
         check:
           _exists:
             _where:
               _and:
                 - id: {_eq: X-Hasura-User-Id}
                 - allow_article_create: {_eq: true}
             _table:
               schema: public
               name: users
         columns:
         - content
         - id
         - title

Apply the metadata by running:

hasura metadata apply

You can set permissions for unrelated tables when using the permissions metadata API:

POST /v1/query HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin

{
   "type": "create_insert_permission",
   "args": {
      "table": "article",
      "role": "user",
      "permission": {
         "columns": "*",
         "check": {
            "$exists": {
               "_table": "users",
               "_where": {
                  "$and": [
                     {
                        "id": "X-Hasura-User-Id"
                     },
                     {
                        "allow_article_create": true
                     }
                  ]
               }
            }
         }
      }
   }
}

This permission rule reads as “if there exists a row in the table users whose id is the same as the requesting user’s id and has the allow_article_create column set to true, allow access to insert articles.”

Column-level permissions

Column-level permissions determine access to columns in the rows that are accessible based on row-level permissions.

Column-level permissions are simple selections on the Hasura console:

Column level permissions

You can set column-level permissions in the tables.yaml file inside the metadata directory:

   - table:
       schema: public
       name: article
     select_permissions:
     - role: author
       permission:
         columns:
         - author_id
         - id
         - content
         - title
         filter:
           author_id:
             _eq: X-Hasura-User-Id

Apply the metadata by running:

hasura metadata apply

You can set column-level permissions when using the permissions metadata API:

POST /v1/query HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin

{
   "type": "create_select_permission",
   "args": {
      "table": "article",
      "role": "author",
      "permission": {
         "columns": [
            "id",
            "title",
            "content",
            "author_id"
         ],
         "filter": {
            "author_id": "X-Hasura-User-Id"
         }
      }
   }
}

In this example, the role author has only partial access to columns of the accessible rows for the select operation.

Row fetch limit

In the case of select operations, the number of rows to be returned in the response can be limited using this configuration:

You can set a row fetch limit on the Hasura console as follows:

Row fetch limit

You can set a row fetch limit for a table in the tables.yaml file inside the metadata directory:

   - table:
       schema: public
       name: author
     select_permissions:
     - role: user
       permission:
         columns:
         - id
         - name
         filter:
           user_id:
             _gt: 10
         limit: 20

Apply the metadata by running:

hasura metadata apply

You can a row fetch limit for a table when using the permissions metadata API:

POST /v1/query HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin

{
   "type": "create_select_permission",
   "args": {
      "table": "author",
      "role": "user",
      "permission": {
         "columns": "*",
         "filter": {
            "id": {
               "_gt": 10
            }
         },
         "limit": 20
      }
   }
}

In the above example, this configuration restricts the number of accessible rows (based on the rule: {"id":{"_eq":"X-Hasura-User-Id"}}) to 20.

Aggregation queries permissions

In the case of select operations, access to aggregation queries can be enabled for a given role using this configuration.

You can enable aggregation queries permissions on the Hasura console as follows:

Aggregation queries permissions

You can allow aggregation query permissions in the tables.yaml file inside the metadata directory:

   - table:
       schema: public
       name: author
     select_permissions:
     - role: user
       permission:
         columns:
         - id
         - name
         filter:
           user_id:
             _gt: 10
         allow_aggregations: true

Apply the metadata by running:

hasura metadata apply

You can allow aggregation query permissions when using the permissions metadata API

POST /v1/query HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin

{
   "type": "create_select_permission",
   "args": {
      "table": "author",
      "role": "user",
      "permission": {
         "columns": [
            "id",
            "name"
         ],
         "filter": {
            "id": "X-Hasura-User-Id"
         },
         "allow_aggregations": true
      }
   }
}

In the above example, the role user is allowed to make aggregation queries.

Column presets

While this is strictly not a permission configuration, defining role-based column presets on any column automatically removes access to it. This preset can be defined for insert and update operations. This configuration is also very useful to avoid sending sensitive user-information in the request and leverage session variables or static data instead.

Backend only

If a permission is marked as backend_only, the mutation is accessible to the given role only if x-hasura-use-backend-only-permissions session variable exists and is set to true and request is made with x-hasura-admin-secret set if any auth is configured.

This might be useful if you would like to hide a mutation from the public facing API but allow access to it via a “trusted backend”.

Note

Setting backend-only is currently available for insert mutations only.

Additional Resources

Enterprise Grade Authorization - Watch Webinar.