Metadata API Reference: Remote Schema Permissions
Introduction
Remote Schema permissions can be defined to:
- Expose only certain parts of the Remote Schema to a role
- Preset arguments with static values or session variables for any field.
By default, the admin
role has unrestricted access to the remote
schema.
The Metadata API is supported for versions v2.0.0
and above and
replaces the older schema/Metadata API.
add_remote_schema_permissions
This API takes the schema (GraphQL IDL format) which should
be a subset of the Remote Schema and the role for which this restricted
schema is exposed. The schema also accepts a custom @preset
directive
for setting argument presets.
Suppose the following is the schema document of the remote.
type User {
user_id: Int
name: String
phone: String
userMessages(where: MessageWhereInpObj, includes: IncludeInpObj): [Message]
}
interface Communication {
id: Int!
msg: String!
}
type Message implements Communication {
id: Int!
name: String!
msg: String!
errorMsg: String
}
input MessageWhereInpObj {
id: IntCompareObj
name: StringCompareObj
}
input IntCompareObj {
eq : Int
gt : Int
lt : Int
}
input StringCompareObj {
eq : String
}
input IncludeInpObj {
id: [Int]
name: [String]
}
type Query {
hello: String
messages(where: MessageWhereInpObj, includes: IncludeInpObj): [Message]
user(user_id: Int!): User
users(user_ids: [Int]!): [User]
message(id: Int!) : Message
}
type mutation_root {
insert_user: (name: String!, phone: String!): User
}
schema {
query: Query
mutation: mutation_root
}
Let's say we want to impose some restrictions on the user
role:
- Expose only the
user_id
,name
and theuser_messages
field in theUser
object. - Add a preset value to the
user_id
argument of theuser
field defined in theQuery
object. We want the value of the preset to come from a session variable calledx-hasura-user-id
. - Allow filtering of the messages only by
name
in thewhere
argument of theuser_messages
field. - Allow only the fields
hello
,messages
and theuser
top level node in theQuery
object. - Expose only the
query_root
and not allow mutations for the role.
The schema document, implementing the above restrictions will look like:
type User {
user_id: Int
name: String
userMessages(where: MessageWhereInpObj, includes: IncludeInpObj): [Message]
}
interface Communication {
id: Int!
msg: String!
}
type Message implements Communication {
id: Int!
name: String!
msg: String!
errorMsg: String
}
input MessageWhereInpObj {
name: StringCompareObj
}
input IntCompareObj {
eq: Int
gt: Int
lt: Int
}
input StringCompareObj {
eq: String
}
input IncludeInpObj {
id: [Int]
name: [String]
}
type Query {
hello: String
messages(where: MessageWhereInpObj, includes: IncludeInpObj): [Message]
user(user_id: Int! @preset(value: "x-hasura-user-id")): User
}
schema {
query: Query
}
To add the Remote Schema permission for the role user
, the following
API should be called with the schema document.
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type" : "add_remote_schema_permissions",
"args" : {
"remote_schema" : "user_messages",
"role" : "user",
"definition" : {
"schema" : "type User { user_id: Int name: String userMessages(where: MessageWhereInpObj, includes: IncludeInpObj): [Message] } interface Communication { id: Int! msg: String! } type Message implements Communication { id: Int! name: String! msg: String! errorMsg: String } input MessageWhereInpObj { name: StringCompareObj } input IntCompareObj { eq : Int gt : Int lt : Int } input StringCompareObj { eq : String } input IncludeInpObj { id: [Int] name: [String] } type Query { hello: String messages(where: MessageWhereInpObj, includes: IncludeInpObj): [Message] user(user_id: Int! @preset(value: \"x-hasura-user-id\")): User } schema { query: Query }"
},
"comment":"remote schema permissions for role: user"
}
}
Argument Presets
Argument presets can be used to automatically inject input values for fields during execution. This way the field is executed with limited input values. Argument presets are of two types:
- Static Value
- Session Variable
A preset value can be added to an input value via the @preset
directive.
type User {
name String
id Int
}
type Query {
user(user_id: Int! @preset(value: 1))
}
When an input field has a preset defined, it will be removed from the
exposed schema. So, following the above example, the user won't be able
to specify the user_id
argument while querying the user
field and
whenever the role executes the user
field, the preset value will get
added before querying the Remote Schema.
A preset value can also reference a session variable. When the preset value has a session variable, then its value is resolved and then added before querying the Remote Schema.
By default, if the input value preset contains a
session variable value, then its value
will be resolved when the query is executed. To treat the session
variable value as a literal value (avoiding resolving of the session
variable value) can be done by specifying static
as true
while
defining the preset.
For example:
type Query {
hello(text: String! @preset(value: "x-hasura-hello", static: true))
}
In this case, "x-hasura-hello"
will be the argument to the hello
field whenever it's queried.
Remote Relationship Permissions
Permissions for remote relationships are derived from the role's remote schema permissions. When permissions for a given remote relationship cannot be derived from the Remote Schema permissions of a given role, that remote relationship will not be accessible to that role.
Cases when the remote relationship cannot be derived are:
- There are no Remote Schema permissions configured for the role for the remote join's Remote Schema.
- The remote join field is not accessible to the role.
- Any of the type (both output and input types) used in the remote join field is not accessible to the role.
When a remote field's argument contains a preset and the same argument is used for creating a remote relationship, then the remote presets will be overridden by the remote join configuration. For example:
Let's say we have a table called customer
and we have a Remote Schema
called payments
and we have a remote relationship
customer_transactions_history
defined which joins customer
to
transactions
field of the payments
field.
Suppose, the payments
Remote Schema is defined in the following way:
type Transaction {
customer_id Int!
amount Int!
time String!
merchant String!
}
type Query {
transactions(customer_id: String!, limit: Int): [Transaction]
}
And, the customer
table is defined in the following manner.
CREATE TABLE customer (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
The remote relationship is defined to join the id
field from the
customer
table to the customer_id
argument of the transactions
field.
We only allow the user
role to access the amount
and time
fields of
the Transaction
object, and introduce a preset for the limit
argument of the transaction
field, resulting in the following schema
being presented.
type Transaction {
amount Int!
time String!
}
type Query {
transactions(customer_id: String!, limit: Int @preset(value: 10)): [Transaction]
}
Two changes have been made for the user
role:
- The
merchant
andcustomer_id
fields are not accessible in theTransaction
object. - The
limit
argument has a preset of 10.
Now, consider the following query:
query {
customer {
name
customer_transactions_history {
amount
time
}
}
}
The user
role won't be able to provide the value for the limit
argument in the customer_transactions_history
field because the
limit
has a preset set and the value will be added by the GraphQL
engine before it queries the Remote Schema.
Args syntax
Key | Required | Schema | Description |
---|---|---|---|
remote_schema | true | RemoteSchemaName | Name of the Remote Schema |
role | true | RoleName | Role |
definition | true | RemoteSchemaPermission | The Remote Schema permission definition |
comment | false | text | Comment |
drop_remote_schema_permissions
The drop_remote_schema_permissions
API is used to drop an existing
delete permission for a role on a Remote Schema.
An example:
POST /v1/metadata HTTP/1.1
Content-Type: application/json
X-Hasura-Role: admin
{
"type" : "drop_remote_schema_permissions",
"args" : {
"remote_schema" : "user_messages",
"role" : "user"
}
}
Args syntax
Key | Required | Schema | Description |
---|---|---|---|
table | true | RemoteSchemaName | Name of the Remote Schema |
role | true | RoleName | Role |