Recommended way of running queries or mutations from the backend?

I have a backend API along with my single page app that will run queries and mutations to my database. Ideally, the @auth directives I’ve setup on my types should only apply to queries that come from my frontend. The backend should have unrestriced access to run any kinds of queries or mutations on the database.

I’ve tried doing it with the Dg-Auth header along with a client API key on Slash GraphQL and sending requests using this from my backend but that doesnt seem to work. Are there any docs or guidance along doing this?

2 Likes

To provide some more perspective, I come from a Firestore background where I did something similar. The Firestore auth rules apply to only queries coming from the firebase client running on users’ browsers. I would also have a REST API endpoint where I would be running firebase admin which would bypass the auth rules that are imposed on the client. Looking to do something similar here

Here’s what I’m doing:

type User @auth(
  add: {rule: "{$DENIED: {eq: \"DENIED\"}}"}
  update: { rule: """
        query ($FUID: String!) { 
            queryUser(filter: { firebaseUID: { eq: $FUID } } ) { 
                firebaseUID 
            } 
        }
    """
  }
  delete: {rule: "{$DENIED: {eq: \"DENIED\"}}"} 
)  {
	firebaseUID: String! @id
	displayName: String 
	photoURL: String 
	userContactDetail: ContactDetail! 
}

I’ve setup the add like above so that frontend users cant create new users, only my backend can

Please help

P.S. Apologies for the snipboard links, but discourse wont let me attach multiple screenshots

When you say backend, are you talking about lamdas? I got backlash for pointing out that there should be no need for @auth directive when calling the query / mutation on a lambda. That query itself should be secured by you before it is run.

This would be a breaking change (even though it makes more sense), so I have not yet seen any support for this by my request.

However, you can run DQL on the backend (you have to learn it) without @auth directive necessity. In a week or so, it will also support JSON Mutations

But to answer your question, a backend should never need @auth rules. However you are calling that backend should (or be secure). At least in all standard software products…

J

@jdgamble555 By backend I mean a separate NodeJS environment running an Express server, not running on DGraph Lambda

It is secured in that it is a trusted environment that will only run queries that I’ve programmed in there on a specific route and is authenticated in that every request made to it goes through an auth middleware that makes sure only authorized users are trying and allowed to do what the particular endpoint logic is programmed to do.

Does that answer your question?

I think DQL still answers your original question, as I don’t know a way to disable @auth requirements in dgraph graphql in general…

@jdgamble555 Essentially, what I’m asking is, is there a way to run queries and mutations on my database bypassing the @auth rules specified on the types?

Isn’t the client/admin API keys supposed to do that on Slash GraphQL? Is so, what’s the right way? Any documentation I can refer?

1 Like

@gja Any thoughts on this?

I don’t believe so directly. If you want to do all that, you might as well host your own dgraph in a docker on your own server somewhere.

SOMEONE PLEASE CORRECT ME IF I’M WRONG

From my understanding the client token is to restrict anonymous access, and the admin token is for schema changes…

https://dgraph.io/docs/slash-graphql/admin/authentication/

However, you can run a custom resolver to query your backend changes, and then post it:

https://dgraph.io/docs/graphql/custom/mutation/

But for more direct control of changes, you would create your own custom mutation through lamdas, which do give you direct access to DQL without @auth rules…

https://dgraph.io/docs/graphql/lambda/mutation/

If you run your own dgraph server, you should have access to /mutation, /query, /alter… but even then it is DQL, not graphql

https://dgraph.io/docs/get-started/

This is my understanding, again, there may be another way I missed in the docs.

Note: Really, the easiest way would be to create an ADMIN role in your @auth directives. That way you can call it however you want. That really depends on your authorization api…

J

I believe you can run mutations without auth if you use an admin token.

@chewxy I get the same results with an admin token.

I think it’s getting filtered out by the auth rules. Thoughts?

  1. Add additional Role field to your JWT
  2. Chain multiple rules in your auth directive, e.g.:
 @auth(
    query: {
      or: [
        # Admins can see all users
        { rule: "{$ROLE: { eq: \"ADMIN\" }}" }
        # users can see only their own data
        {
          rule: "query($USERNAME: String!) { queryOwnable{owner(filter: { username: {eq: $USERNAME }}) { username }}}"
        }
      ]
    }
1 Like

@maaft In case I go the Role route, how would I generate the JWT for the server?
I am using firebase auth and following the guide provided here
https://dgraph.io/docs/graphql/todo-app-tutorial/todo-firebase-jwt/

So, here Firebase auth generates short lived 1 hour access token JWTs that Dgraph verifies using the auth mechanism specified. However, for the backend server, I dont see a straightforward way for the server to generate its own ADMIN role JWT tokens.

Thoughts?

I don’t know much about firebase, but:

  • you can generate an admin token and paste it on jwt.io to see its contents
  • if you see that the admin role is encoded somewhere, use this in your auth directive

you can also have a look at: Create Custom Tokens  |  Firebase

I’ll wait to see if the team has any other suggestions where I dont have to do the heavy lifting myself in terms of generating custom tokens and maintaining them. And also sprinkling that extra line of checking if role equals admin on all the auth directives seems boilerplatey.

I would love if what @chewxy suggested would work where I could just generate an admin token on Slash and that bypasses the auth roles completely

For the boilerplate part: I suggest using interfaces and implement the auth rules there:

E.g.

interface Ownable @auth (....) {
   owner: User!
}

type Foo implements Ownable {
 ... 
}
3 Likes

1.) There are other use cases (in lambdas) for bypassing @auth directive on the server end when calling graphql. I again, submit this as a feature request. Of course it needs to be optional to not break the code when @auth is needed.

2.) There still should be a way to call DQL directly, bypassing @auth, so you might want to mess with that.

3.) There may also be a way with an ADMIN token to do this, SOMEONE FROM DGRAPH PLEASE COMMENT HERE so that we can see how it is done.

4.) As far as Firebase, you can easily use the ADMIN SDK to create a custom token. Of course, you need a user. You would just pick the uid of a user with the ADMIN role:

admin
  .auth()
  .createCustomToken(uid)

Of course, that assumes the user already has the custom claim. If you add the custom claim on user.onCreate, then it should already be there. See my repo:

Hope this helps,

J

1 Like

It would appear I was mistaken. Sorry.

@chewxy - Is there a way to access DQL on the dgraph backend (not slash dgraph) besides within lambdas?

Ya. You can connect to your Slash instance with your favourite Dgraph clients (mine’s dgo). With it you can do all the DQL!

I’m facing the same issue right now and the workaround I’m implementing is the following:

  • Create an admin user in Firebase auth (just a normal user)
  • Retrieve that user’s ID
  • When initializing the Apollo client, first use the createCustomToken method from admin passing that user ID and adding the ADMIN claim or whatever claim you want to use
  • Pass that token to Apollo client