Queries with ADMIN Key should ignore @auth rules

Hi!

I was recently experimenting with all sorts of @auth rules and came across a use-case, I am obviously not alone with - see here.

Scenario

In some occasions it might be useful to run queries (eg. from an external backend) by using an API key. We have no access to an ID token. Therefore it would be nice if eg. the Admin Key included via DG-Auth: <admin-key> in the request header, could completely bypass all @auth rules for a node. At the moment this is not possible. We would have to have multiple different queries via lambda.

What we have

Assume this setup

type Test {
  id: ID!
  name: String
}

Anonymous Access for both write and read is turned off for Test. If we now run a query

query QueryWithApiKey {
  queryTest {
    id
    name
  }
}

and pass "DG-Auth": "<client-or-admin-api-key>" into the header, the query works.

However, if we change the access rules for Test (write and read is allowed by anonymous) and add an @auth rule to it

type Test @auth(
  query: { rule: "{ $isAuthenticated: { eq: \"true\" } }" }
) {
  id: ID!
  name: String
}

the above query fails because no ID Token which includes the parameter isAuthenticated is submitted in the header. This is a bit of a weird behaviour and not really expected since passing an API key usually gives you all the rights.

Further Testing

Nonetheless, I have been testing further and this is where interfaces came into my mind. I thought defining

interface TestQuery @auth(
  query: { rule: "{ $isAuthenticated: { eq: \"true\" } }" }
) {
  id: ID!
  name: String
}

type Test implements TestQuery {
  id: ID!
  name: String
}

and reworking write and read access from Test, would do the job. Unfortunately, Dgraph adds the interface @auth rule with a union OR rule to type Test - which is basically the same result as before.

The (very bad) workaround

A workaround would probably be that we define separate types with different rules and leave the actual Test without anonymous access.

type TestQuery @auth(
  query: { rule: "{ $isAuthenticated: { eq: \"true\" } }" }
) {
  test: Test
}

type Test {
  id: ID!
  name: String
}

where TestQuery could be publicly queryable (via ID Token including isAuthenticated) and Test is not accessible and could be queried via API key.

The Request

In order to not fiddle around with the schema too much it would be very nice if:

  • the Client Api Key stays like it is (can only do client side queries and does not ignore @auth)
  • the Admin Api key can do admin stuff, client stuff PLUS ignores @auth for client stuff

I have figured out a solution in my case (I use Dgraph in combination with Auth0).

I have created an M2M login flow in Auth0 and attach an API Key to the token claim which I can then use in my @auth rules.

I have written a longer article about this here

Hope this helps!