This note is in Hasura.RQL.DDL.Permission. It is referenced at:
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.
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:
x-hasura-admin-secret
(if authorization is configured),x-hasura-use-backend-only-permissions
(value must be set to “true”),x-hasura-role
to identify the rolebackend_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:
x-hasura-use-backend-only-permissions
header is sent as FALSE along with the
request then the mutation will be hidden (4th case)x-hasura-use-backend-only-permissions
header is sent as TRUE along with the
request then the mutation will be visible (5th case)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:
x-hasura-use-backend-only-permissions
is set (backend scenario)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)}
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.