Authorization for the GraphQL API using neo4j


(Shreyansh Zazz) #1

How can I authorize that the requesting client is valid or allowed?


(M. David Allen) #2

There are a host of javascript modules which do this. One of the most common is passport. In the sample grandstack app, this code isn't there yet (although I think @William_Lyon may be planning to add it at some point).

To authorize clients, there are a lot of decisions to be made. Would you use your own username/password? If so, you need a signup/reset password flow. Would you use Oauth to other providers like google? Then you need extra screens to handle redirects and get tokens on the front end, etc.

But to answer your question, best way is to use passport (https://www.npmjs.com/package/passport). This provides an express.js middleware component that checks every request for authorization and only forwards it if authorization is present. It gets complicated in deciding what kind of authorization you want, see other plugins such as passport-jwt for examples of that.


(Shreyansh Zazz) #3

Actually I was talking about the GraphQL API authorization.
How can we verify that the API is accessible only via our services.


(M. David Allen) #4

That's what I'm talking about as well. Please provide some additional details if these assumptions aren't right, but I think you're probably exposing the GraphQL API via express.js. By default with our starter kit, there's no authorization there so really anyone could hit the URL of your API. What I said about passport above is the answer on how you protect that API so that only people who you want to call it can.

If this isn't the right solution approach, I need more detail about what you mean by the API, and what you mean by "only accessible by our services".


(Styk Tv) #5

Quick relqted question: could you please confirm if there is any reference materials on how to use JWT details from incoming token as part of the graphql/neo4j query? For example any or few of aud/username/email/group details etc. Essentially if there is a way to create a method that would have ability to pre-filter based on the details from the token? Without writing custom code (but by referencing to jwt variables)?

I'm playing around with kubernetes oauth-proxy, nginx-oidc plugin, swagger openapi3 oidc elements to do admission control to unauthenticated api methods based on kubernetes-ingress-controller token inspection.

Because of sessionless jwt I don't mind if this would happen on graphql endpoint itself. This way I could utilize this on application level to pre-filter based on information inside jwt: for example, filter on nodes that have email property same as in auth bearer token.

I use keycloak as identity provider and consume in react-native. Token handling done on native level.


(Shreyansh Zazz) #6

Got it. Actually passport.js is also used to authenticate users on the website. That's why I got confused.
Thanks


(M. David Allen) #7

@styk-tv I don't know of any jwt-specific documentation for graphql / neo4j. But I also don't think it's really needed. There are a lot of good blog posts (like this: https://medium.freecodecamp.org/securing-node-js-restful-apis-with-json-web-tokens-9f811a92bb52) that cover how to secure express.js APIs with JWT.

And the graphql API is just an express.js API, so really securing graphQL with JWT is no different than securing any REST API with JWT.


(Styk Tv) #8

Hi David. Thank you for your answer, however it's a lazy one. No-one can just whip-out a field-based verification hence interest in two products providing this out of the box (neo4j and grapql). Consider the following example:

I want to retrieve UserA payment history. I construct query on client and authorize and get access to full database. I can get anyone's records. What i want instead is to push request for history with my signed token instead. What comes from query, Who comes from token. Identiy Provider verified I AM the user, information is confirmed and Signed in the token. I want the API on method execute to take Principal from the JWT token (confirmed) and then run What query. This way I am guaranteed results only for the Bearer of the token. Isn't there anyone that you know as Neo4j Staff that had this requirement in the past? Seems like such a common question. Cheers.


(William Lyon) #9

Field level authorization is certainly something that's been requested and something we've been planning to add to neo4j-graphql-js, however it's not implemented yet.

Our plan is to use schema directives that allow you specify scope for fields, and the generated Cypher query takes the user context into account when generating the Cypher query. Basically our plan is to implement something similar to the second approach (schema directives) in this example:



(Styk Tv) #10

Thank you William. Slides with Video are really self-explanatory. It's exactly what I was looking for. Ability to protect queries based on token details like sub or groups. And also, use details from the token as part of the query. Many many thanks.

..and now that I know what to look for: Python Sanic Graphene Neo4j https://medium.com/@amhopkins/my-new-development-stack-using-python-graphql-and-neo4j-the-brewmasters-guide-to-the-internet-87e3879009c4 including like to JWT decorators layer and my Keycloak minting.


(Styk Tv) #11

Quick question. I am slowly recoding all my queries to support 1) Models and 2) Schemas. And yet once in a while I go back to the original neo4j-graphql repo and see example of something like this:

query Nineties($released: Long, $letter: String)
{ Movie(released: $released,
        filter: {title_starts_with: $letter,
                 actors_some: { name_contains: $letter}}) {
    title
    released
    actors(first: 3) {
      name
      born
      movies(first: 1, orderBy: title_desc) {
        title
        released
      }
    }
  }
}

# query variables
{ "released":1995, "letter":"A"}

And makes me wonder why I cannot use your implementation of neo4j-graphql in my project. It will take me a year to manually implement all the types and all the schemas to get them to level of above example using Graphene and py2neo. All of them work form /graphql/ on plugin but obviously have to be recoded back on my api. Is there a way to get around this and still stay compatible with Relay on client side? For example can I pass query from relay into api (verify access) and then relay query to neo4j-graphql plugin? I mean I can now do everything I wanted with graphene and py2neo but maybe i'm missing something as I'm bypassing the neo4j-graphql plugin completely. Please explain.