hasura / hasura/graphql-engine

Proposal: allow specifying role for query via custom directive

Open
#9,111 1 comment 0 reactions 0 assignees View on GitHub
k/enhancement
Dominant language
TypeScript
Stars
32.1k
Forks
3k
PR merge metrics
PR metrics pending

Description

### Is your proposal related to a problem?

GraphQL operations executed against a hasura endpoint are typically tightly coupled with a role.
Because hasura generates different schemas on a per-role basis, it's common that a query valid for one role will be outright rejected by another.

When using JWT auth, a token may include claims indicating the user has authorization for a list of roles, as well as a default role.
If a `X-Hasura-Role` header is passed along with the request, and the role thus specified is one of the allowed roles, that role will be used instead of the default role for the token.

This is unwieldy, as it requires client logic to ensure every query is sent alongside the correct accompanying role.
Furthermore, it can complicate documenting the association between an operation and a role in client-side code: one has to be aware of both the operation and the accompanying headers.

A secondary problem is building role-based allow-lists in an automated manner. It is possible to extract GraphQL operations from a codebase to somewhat automate the process of building allow-lists.

However, it is currently impossible to determine what roles are associated with an operation, which is necessary when trying to build-role-based allowlists.

### Describe the solution you'd like

Allowing users annotate operations with a desired role(s) for the operation.
Such an operation may look like this:
```gql
query GetUser @role(name: "user") {
user {
id
name
}
}
```
HGE would then execute the above query with the `user` role, provided the authentication allows for the use of that role.
Users would also be able to specify multiple roles like so:
```gql
query GetUser @role(name: ["user","anotherrole"]) {
user {
id
name
}
}
```
(unsure the above would work but I do know a lot of hasura types that expect arrays also accept a single value instead).

For the above operation, we are effectively annotating that this operation may be executed with any of the listed roles.
Hasura would then execute the operation with the first role that is annotated, _and_ is part of a user's list of allowed roles.

This would allow users to write a query with a few roles in mind, and annotate the intended roles in the query.
Then, any user with one of the intended roles would be able to execute the operation, with minimal front-end logic required.

#### Drawbacks

- The concept of multiple roles for a single operation only applies for JWT auth modes, not webhook auth mode.
- There may be performance implications as queries would need to be parsed first to get the role for an operation,
validate if the user is authorized to use that role, then validated against the schema for that role (currently it is possible for auth to failed and an operation to be rejected due to invalid auth _before_ the graphql query (or even the http body) is parsed).

### Describe alternatives you've considered

Queries can be annotated with comments for the purpose of associating them with a role when building role-based allow-lists. This is however not standard and brittle.

Users can also implement the logic associating roles with operations in front end code, which is in fact the current way to handle this use case.

Finally, users may also use inherited roles a single inherited role instead of dynamically allocating roles on a per-query basis.
This does have some drawbacks, as inherited roles cannot be modified dynamically without altering metadata. So in a scenario where a user may gain additional privileges and start a new session with those new privileges, inherited roles would not allow the user to gain additional permissions.

Contributor guide

Open the contributing guide

Research direction

Start by tracing how GraphQL operations are parsed and how Hasura selects and validates roles for JWT-authenticated requests. Compare that flow with custom directive handling and consider how single or multiple roles would be authorized and applied. Done means the proposal's role annotation works without weakening authorization and is covered by relevant tests, though no files or tests are named in the issue.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, typescript
Domain
api, authorization
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.