Disable GraphQL Query and Subscription Root Fields selectively with RBAC

For each database table in a Hasura app, the GraphQL engine creates three root fields by default. Assuming there is a note table, the three root fields would be:

  1. note
  2. note_by_pk
  3. note_aggregate

However, there are use cases where you might want to expose only certain root fields or none at all. For example, you might want to hide note_aggregate, expose only note_by_pk, or hide all of them. Now it's possible to do that.

Hasura launched this feature in the v2.8.0 version. You can check the v2.8.0 changelog here.

In the next step, you will build and use a Hasura application to test the different use cases.

Try it out via Hasura

The Hasura application you will build is a basic note-taking app. Users can add multiple notes, whereas each note belongs to only one user.

The quickest way to use Hasura is via the Hasura Cloud. Create a new Hasura project and launch the console.

Deploy to Hasura button

Note: If you prefer local development using Docker, check out the documentation on getting started with Docker.

After that, connect the Hasura application to a database and create two tables - user and note.

The user table has the following columns:

  • id of type UUID (PK)
  • name of type Text
Create the user table in Hasura

The note table has the following columns:

  • id of type UUID (PK)
  • title of type Text
  • content of type Text
  • author_id of type Text
Create the note table in Hasura

The next step involves creating the relationships between the two tables. Navigate to the "Permissions" tab in the user table and create an array relationship between the user and note tables.

The id column from the user table maps to the author_id column from the note table.

Create an array relationship between user and note tables

Similarly, create an object relationship between the note and user table. The author_id column from the note table maps to the id column from the user table.

Create an object relationship between note and user tables

You finished configuring the application! Add some data (users and notes) to the application so you can test the different use cases.

How to use the feature

It's important to mention that you can disable query/subscription root fields only through the metadata file. You need to export and import metadata whenever you want to customize the root fields.

Export and import metadata in Hasura Cloud

You will export the metadata file, make the corresponding changes and then upload the metadata file to Hasura.

Note: An alternative way of managing the metadata is to use the Hasura command-line interface (CLI). The documentation covers the hasura metadata in detail.

The console support will come soon too!

Use case: Disable GraphQL operations

The feature allows you to disable a specific GraphQL operation (queries or subscriptions) or all of them. You can grant a role to make queries, but not subscriptions, and vice-versa. Or you can disallow both.

Using the example Hasura application, you can disable all the root fields of the user table for the guest role as follows:

{
   "role": "guest",
   "permission": {
     "columns": [
       "id",
       "title",
       "content",
       "author_id"
     ],
     "filter": {},
     "allow_aggregations": true,
     "query_root_fields": [],
     "subscription_root_fields": []
   }
}

The empty arrays from the last two fields indicate that no root fields should be displayed for the user table.

The image illustrates what you should see after applying the permissions.

Disabled GraphQL operations for the "user" table

⚠️ It's important to note that the guest role can still indirectly access the user table through the notes relationship.

query {
  note {
    id
    title
    content
    author_id
    author {
      id
      name
    }
  }
}

If you run the above query, you will see the author details for each note. Keep this in mind when disabling direct access to a table.

You can see the complete metadata code for this use case in this Gist.

Use case: Primary key access only

Another use case would be to access the table only through its primary key. The client can only fetch data from the table if the client knows the primary key of a particular row.

Add the following permissions to the note table in the metadata file:

{
  "role": "guest",
  "permission": {
    "columns": [
      "author_id",
      "content",
      "title",
      "id"
    ],
    "filter": {},
    "query_root_fields": ["select_by_pk"],
    "subscription_root_fields": ["select_by_pk"]
  }
}

After you import the updated metadata file, the guest role should only have access to the note_by_pk root field, as shown in the image below.

Access data in a table through the primary key

You can see the complete metadata code for this use case in this Gist.

Use case: Access table through a relationship

The last scenario from this post involves providing indirect access to a table. That means accessing a table through a relationship.

In this application example, you could make the user table accessible only through the notes relationship.

Go to the metadata file and apply the following permissions for the user table:

{
  "role": "guest",
  "permission": {
    "columns": [
      "id", 
      "name"],
    "filter": {},
    "query_root_fields": [],
    "subscription_root_fields": []
  }
}

If you go to the Hasura console and perform the query shown in the image, you should be able to access the rows from the user table.

Access a table indirectly through a relationship

You can see the complete metadata code for this use case in this Gist.

Summary

The feature allows you to disable root fields and customize your GraphQL API. You can disable queries, subscriptions, or both of them. It also allows you to make tables accessible only through a relationship.

There is also a video that talks about hiding root fields.

Hiding root-level fields
Blog
05 Sep, 2022
Email
Subscribe to stay up-to-date on all things Hasura. One newsletter, once a month.
Loading...
v3-pattern
Accelerate development and data access with radically reduced complexity.