graphql-engine

This note is in Hasura.RQL.DDL.Permission. It is referenced at:

Backend only permissions

As of writing this note, Hasura permission system is meant to be used by the frontend. After introducing “Actions”, the webhook handlers now can make GraphQL mutations to the server with some backend logic. These mutations shouldn’t be exposed to frontend for any user since they’ll bypass the business logic.

Backend only permissions is available for all(insert/update/delete) mutation operations.

For example:-

We’ve a table named “user” and it has a “email” column. We need to validate the email address. So we define an action “create_user” and it expects the same inputs as “insert_user” mutation (generated by Hasura). Note that both “create_user” and “insert_user” can insert values into the “user” table but only “create_user” has the logic to validate the email address.

In the current Hasura permission system, a role has permission for both ‘actions’ and ‘insert operations’ on the table. That means, both the “create_user” and “insert_user” operations will be visible to the frontend client. This is bad, since users can use “insert_user” operation to circumvent the validation logic of “create_user”.

We can overcome this problem by using “Backend only permissions”. In this if the insert/update/delete permission is marked as “backend_only: true”, then the insert operation will not be visible to the frontend client unless specifically specified

Backend only permissions adds an additional privilege to Hasura generated operations.

Those are accessable only if the request is made with all of the following:

backend_only x-hasura-admin-secret x-hasura-use-backend-only-permissions Result ———— ——————— ————————————- —— FALSE ANY ANY Mutation is always visible (Default Case: When no authorization is setup) TRUE FALSE ANY Mutation is always hidden FALSE TRUE ANY Mutation is always visible TRUE TRUE (OR NOT-SET) FALSE Mutation is hidden TRUE TRUE (OR NOT-SET) TRUE Mutation is shown

case 1: default case - no authorization is set and no backend_only permission are set then irresepective of the value of x-hasura-use-backend-only-permissions the mutation will always be visible

case 2: the authorization is set and the backend_only permissions are set but the x-hasura-admin-secret is not sent along with request then irresepective of the value in x-hasura-use-backend-only-permissions the mutation will always be hidden

case 3: the authorization is set, but no backend_only permission are set, the x-hasura-admin-secret is sent along with request then irresepective of the value in x-hasura-use-backend-only-permissions the mutation will always be visible

case 4 and 5: the authz is set and the backend_only permissions are also set and the x-hasura-admin secret is also sent along with the request then:

How it Works:-

Hasura has two scenarios:

When no backend-only permissions are set then Hasura runs only in frontend scenario, i.e all the mutation operations are visible.

When backend-only permissions are set, there comes a notion of:

Hasura maintains two different graphql schema (‘frontend schema’ and ‘backend schema’) for all mutation fields of a table:

The generation of these schemas happen in the buildSource functions of buildRoleContext and buildRelayRoleContext functions. The internal representation of these schema’s look like: {RoleName: (Frontend Schema/Default Schema, Backend Schema)}

For example:

We’ve a table “user” tracked by hasura and a role “public”

* If the update permission for the table “user” is marked as backend_only then the GQL context for that table will look like:

{"public": (["insert_user","delete_user"], ["update_user"])}

In the above ‘[“insert_user”,”delete_user”]’ are the only mutation operation visible by default on the frontend client. And the ‘update_user’ opertaion is only visible when the x-hasura-use-backend-only-permissions request header is present.

* If there is no backend_only permissions defined on the role then the GQL context looks like:

{"public": (["insert_user","delete_user", "update_user"], [])}

In the above there is no specific schema for the backend scenario i.e all the mutation operations are visible by default.