Derive required scopes from GraphQL queries


#1

As an integrator, figuring the required scopes for my GitHub app or personal access token is a recurring pain. With GraphQL, I think that it would be possible to derive required scopes from my app’s queries, using static analysis.

If I recall correctly, @kdaigle mentioned at this year’s universe that this is what GitHub is or will be doing before resolving the query. But having a way to do the same as an integrator would remove all the guesswork of what checkboxes I have to click when selected required scopes :slight_smile:

I like the approach Dan Schafer from auth0 is suggesting, using directives: https://youtu.be/4_Bcw7BULC8?t=16m33s. Do you have anything in that direction in the works? Or any other suggestions that would help me to derive scopes from GraphQL queries as an integrator?


#2

I’m going to CC @gjtorikian who is the person on GitHub’s side who has been looking at this recently. :smiley: But I do believe we can provide you more clarity over what scopes/permissions are needed where.


#3

Indeed, this is technically possible. Our GraphQL schema is already annotated for inclusion of required scopes.

However, I think the directive approach isn’t the one we’d take. I remember being in the audience for that GraphQL Summit talk and the main takeaway I got from using directives is that that’s intended for a query that’s executing on the server, not the client. Meaning, GitHub.com would annotate queries sent with the @scopes directive. A third-party client, building some sort of integration into GitHub, which has already asked for permissions, would not necessarily make use of a directive to selectively access fields.

There has been a lot of questions internally on the representation of metadata (see https://github.com/facebook/graphql/issues/300 for example). We’re hoping to work with the GQL community to agree on what metadata representation would look like. Once that’s done, we can provide that information in the IDL so that tools like GraphiQL or our documentation site will be able to consume and act on that info.


#4

Thank you Garen!

Can you elaborate on the difference between a query that is executed on the server vs the client? I think I’m missing something obvious here, GraphQL is still new to me :slight_smile: Aren’t all queries executed on the server?


#5

Ah, totally. I’ll try to use a real-life example.

GitHub.com’s UI page for pull requests is backed by GraphQL. We have a static query that is defined as part of our backend that is executed through the GraphQL pipeline every time a page loads. A query for this might look like:

query {
  pullRequest(number: 123) {
   title
   body
  }
}

Suppose we want to show certain information if a user has certain privileged access, like if they’re an admin. We might want to toggle that field using a directive, like this:

query {
  pullRequest(number: 123) {
   title
   body
   superNewField @hasScope(scope: ["repo:admin"])
  }
}

That’s what the slides are implying ought to be done. Requests made by the server (GitHub.com, to itself) can pass along scope information (that comes from the browsing user) to toggle parts of a query on or off.

Now, let’s say you’re a third-party app developer. You want to make a request to the /graphql API endpoint, and you have to pass along some authorization information, like an OAuth scope. Executing a query that has @hasScope defined in the body makes less sense, because as you make the request to the GitHub API, we already know what permissions you have, because you’ve passed along the authorization information to us–either as a token or as an app that’s acting on behalf of you (like, you granting Travis CI commit status information for private repos). This is what I meant by saying:

A third-party client, building some sort of integration into GitHub, which has already asked for permissions, would not necessarily make use of a directive to selectively access fields.

Is that helpful?


#6

This was very helpful, thanks so much Garen for the great explanation!

Executing a query that has @hasScope defined in the body makes less sense, because as you make the request to the GitHub API, we already know what permissions you have

That makes sense! Having the @hasScope directives in the public GraphQL schema would still be cool for tooling, e.g. something like this:

$ github-graphql-validate-scopes --scopes="public_repo,read:org" queries/*.graphql

The CLI tool looks for all *.graphql files in the app’s queries/ folder which presumably contains all the queries that the app runs. If one of them requires a scope that is not included in public_repo and read:org, it would fail with an error. I could add such a script to my CI to avoid an accidental deploy of an app that is missing scopes for one of its queries.

Does that make sense?